7 Oracle XML Security

XML security refers to standard security requirements of XML documents such as confidentiality, integrity, message authentication, and non-repudiation. You can setup your environment and use Oracle XML Securityto fulfil these standard security requirements of XML documents.

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.

We cover features and provide code samples for implementing Oracle XML Security:

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 References.

7.1 Oracle XML Security Features and Benefits

Oracle Security Developer Tools provide a complete implementation of the XML Signature and XML Encryption specifications, and supports Signature Algorithms, Digest Algorithms, Data Encryption Algorithms, Key Encryption and Key Wrapping Algorithms, and Transforms.

These algorithms are:

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

7.2 Setting Up Your Oracle XML Security Environment

Setup your Oracle XML Security environment by installing Oracle Security Developer Tools and JDK, and setting up CLASSPATH environment variable for jar files.

The Oracle Security Developer Tools are installed with Oracle WebLogic 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.

7.3 Signing Data with Oracle XML Security

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 Signing Data with the Oracle XML Security API through Decrypting Data with the Oracle XML Security API.

7.3.1 Identifying What to Sign

As a first step, you must identify the data that you need to sign and where your signature will be placed. You can do this by adding the xml:id attribute to the information element. The Signature uses this attribute to refer to the element.

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  xml:id="foo1">
    ...
  </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.

7.3.1.1 Determining 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.

Here is an example of Enveloped Signing:

<myDoc>
  <importantInfo  xml:id="foo1">
    ...
    <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.

7.3.1.2 Deciding 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.

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  xml:id="foo1">
    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.

7.3.1.3 Signing 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.

7.3.1.4 Excluding 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.

7.3.2 Deciding on a Signing Key

Once you have decided on what to sign, and how to reference it, you can decide on a signing key, by using a X509Certificate, a symmetric key, or a raw asymmetric signing key, like a DSA, RSA, or DH key.

These options are:

  • 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.

7.3.2.1 Setting 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.

7.3.2.2 Providing a Receiver Hint

You also need to provide a hint so that the receiver 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.

7.4 Verifying XML Data

You can verify XML data by searching for the signature element and fetching the verification key.

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

7.5 Understanding how Data is Encrypted

You can encrypt an XML document, a fragment of an XML document or some binary data by applying an encryption key.

This section explains the concepts behind data encryption.

The basic steps are as follows:

See Also:

For details of data encryption with the Oracle XML Security APIs, see Encrypting Data with the Oracle XML Security API.

7.5.1 Identifying what to Encrypt

The most common encryption scenario is to encrypt and replace. When you are encrypting a part of the document, replace 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.

7.5.1.1 Using 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.

7.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.

You can store the data externally or inside the encrypted data element.

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.

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

7.5.2 Decide on the Encryption Key

You can choose a random symmetric key and encrypt your data. Then you can encrypt this symmetric key with your asymmetric key.

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

  1. choose a random symmetric key,

  2. encrypt your data with this key,

  3. encrypt this random symmetric key with your asymmetric key, and

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

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

  1. generate a random symmetric key,
  2. encrypt this random symmetric key with your symmetric key and
  3. 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.

7.6 Understanding Data Decryption with Oracle XML Security

Data decryption follows the same process as for data encryption, but in reverse. You need to decrypt the random symmetric key, and then use this key to decrypt the data.

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:

  1. locate the corresponding EncryptedKey,

  2. decrypt it first, and

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

See Also:

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

7.7 Understanding and Using Element Wrappers in the OSDT XML APIs

All the XML-based Oracle Security Developer Tools APIs like Oracle XML Security and Oracle Web Services Securityuse a wrapper concept, in which 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. Topics include:

7.7.1 Constructing the Wrapper Object

You can invoke the constructor to construct a wrapper object from a DOM element. If the DOM element does not exist, either you can first create a DOM element, and then use the constructor, or you can use a newInstance method.

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.

7.7.2 Obtaining the DOM Element from the Wrapper Object

You can use the method XMLElement.getElement() to get the underlying 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.

7.7.3 Parsing Complex Elements

For complex elements containing a hierarchy of subelements, there are 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.

7.7.4 Constructing Complex Elements

You can create individual wrapper objects and assemble them by using the set methods to construct a complex element.

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());

7.8 Signing Data with the Oracle XML Security API

With Oracle XML Security APIs, you can create signatures for the XML data elements.

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

Topics include:

7.8.1 Creating a Detached Signature, Basic Procedure

You can create a detached signature with an identified XML element, an ID attribute added to the element, and a signing key and certificate.

To create a detached signature like this:

<myDoc>
  <importantInfo  xml:id="foo1">
    ...
  </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.

7.8.2 Using Variations on the Basic Signing Procedure

While creating a signature you can include multiple references, enveloped signatures, XPath expressions, certificate hints, and HMAC key signing.

The following topics explain it further:

7.8.2.1 Including 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.

7.8.2.2 Using an 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);
7.8.2.3 Using an 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);
7.8.2.4 Using a 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.

7.8.2.5 Signing with an 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.

7.9 Verifying Signatures with the Oracle XML Security API

Using Oracle XML Security APIs, you can locate what is signed, fetch the keyinfo of the signature, and then verify the signature.

Signature verification topics include:

7.9.1 Checking What is Signed, Basic Procedure

You can verify a signature by first locating the <dsig:Signature> element in your document, using it to construct the XSSignature wrapper object, and then fetching the KeyInfo of the signature.

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.

7.9.2 Setting Up Callbacks

If the KeyInfo contains the signing certificate, set a certificate validator callback. If the KeyInfo contains a hint, write a KeyRetriever to fetch a certificate from a certificate store.

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));

7.9.3 Writing 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.

7.9.4 Checking What is Signed

You can check if a signature really signs what you were expecting it to sign. The Oracle Security Developer Tools API provides methods 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
}

7.9.5 Verifying the Signature

You can verify a signature by using the sig.verify() method and know whether the signature format is correct. You can also debug the failed signatures.

The last step is to actually verify the signature. The call protocol depends on whether callbacks are set up.

7.9.5.1 Verifying 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.

7.9.5.2 Verifying 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.

7.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.

7.10 Encrypting Data with the Oracle XML Security API

You can encrypt data with a shared symmetric key or a random symmetric key.

The following topics explain it further:

7.10.1 Encrypting with a Shared Symmetric Key

You can create a new XEEncryptedData instance and specify the encryption method. Then, create a Keyinfo with a hint to the symmetric key. You can use the utility method XEncUtils.encryptElement to perform all these steps.

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);

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
);

7.10.2 Encrypting with a Random Symmetric Key

Usually you need to generate a random symmetric key and encrypt the data with that key, and then encrypt this random symmetric key with the receiver's public key. The XEncUtils.encryptElement method performs all these steps.

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);

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);

7.11 Decrypting Data with the Oracle XML Security API

Oracle XML Security API has different methods for decrypting data depending upon whether you have used a shared symmetric key or a random symmetric key.

The topics in this section explain it further.

7.11.1 Decrypting with a Shared Symmetric Key

You can search for the encrypted data element and decrypt the data by using the XEEncrytedData.decryptAndReplace method.

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);

7.11.2 Decrypting with a Random Symmetric Key

With a random symmetric key, you can decrypt the data by using the XEEncUtils.decryptElement method.

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);

7.12 About Supporting Classes and Interfaces

Oracle XML Security API contains supporting classes and interfaces. The oracle.security.xmlsec.util.XMLURI interface defines URI string constants for algorithms, namespaces, and objects. The oracle.security.xmlsec.util.XMLUtils class contains static utility methods for XML and XML-DSIG.

It contains these topics:

7.12.1 About the oracle.security.xmlsec.util.XMLURI Interface

The oracle.security.xmlsec.util.XMLURI 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_".

7.12.2 About the oracle.security.xmlsec.util.XMLUtils class

The oracle.security.xmlsec.util.XMLUtils class contains static utility methods for XML and XML-DSIG.

Methods frequently used in applications include the createDocBuilder(), createDocument(), toBytesXML(), and toStringXML() methods.

7.13 Common XML Security Questions

Learn frequently asked questions about Oracle XML Security.

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.

7.14 Best Practices for Oracle XML Security

You can refer to discussions on best practices for implementors and users of the XML Signature specification.

See the best practices at:

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

7.15 The Oracle XML Security Java API Reference

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