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
.
System Requirements
In order to use Oracle XML Security, you must have JDK 17 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:
- Identify what to sign and where to place the signature.
- 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.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 orIssuerSerial
.
-
-
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:
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:
-
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 theEncryptedKey
in theKeyInfo
of theEncryptedData
. -
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:
-
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
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 callXSSignature.verify()
you call it with no verification key. Internally, the Oracle Security Developer Tools look at theKeyInfo
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()
returnsfalse
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.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.
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.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:
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.
You can access the guide at:
Oracle Fusion Middleware Java API Reference for Oracle Security Developer Tools