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".
Oracle Security Developer Tools provide a complete implementation of XML Signature and XML Encryption specification.
Oracle Security Developer Tools provide a complete implementation of the XML Signature and XML Encryption specifications, and support these algorithms:
DSA with SHA1
RSA with SHA1
HMAC-SHA1
MD5
SHA1
SHA256
SHA512
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
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".
This section describes the Oracle XML Security API.
About the Examples in this Chapter
This chapter contains several sections with instructions and examples of API usage.
The following sections are specific to the Oracle XML Security API:
Section 8.7, "About Element Wrappers in the Oracle Security Developer Tools XML APIs"
Section 8.8, "How to Sign Data with the Oracle XML Security API"
Section 8.9, "How to Verify Signatures with the Oracle XML Security API"
Section 8.10, "How to Encrypt Data with the Oracle XML Security API"
Section 8.11, "How to Decrypt Data with the Oracle XML Security API"
The Oracle Security Developer Tools are installed with Oracle WebLogic Server in ORACLE_HOME/modules/oracle.osdt_11.1.1
.
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.
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 Section 8.8The 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.
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.
<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.
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.
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.
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.
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.
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.
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:
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.
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, seeThis 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"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.
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.
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.
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.
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
.
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, seeAll 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.
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.
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.
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. Theget
methods always create new wrapper objects, and if you modify the underlying DOM, the wrapper objects always see the most recent changes.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());
This section describes techniques for signing data with the Oracle XML Security APIs.
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 levelSignature
object into your document.Variations on the basic signing procedure include multiple references, enveloped signatures, XPath expressions, certificate hints, and HMAC key signing.
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.
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);
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);
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
.
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.
This section explains how to verify signatures using the Oracle XML Security APIs.
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.
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 yourKeyInfo
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));
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.
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 }
The last step is to actually verify the signature.
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.
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.
This section describes various options for data encryption with Oracle XML Security.
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 );
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);
Decryption techniques depend on whether you have a shared symmetric key or use a random 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);
This section describes additional classes and interfaces in the Oracle XML Security API.
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_".
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.
For a discussion of best practices for implementors and users of the XML Signature specification, see:
The Oracle XML Security API (Javadoc) is available at:
Oracle Fusion Middleware XML Security Java API Reference for Oracle Security Developer Tools