FileDocCategorySizeDatePackage
XMLSignature.javaAPI DocJava SE 6 API29232Tue Jun 10 00:23:04 BST 2008com.sun.org.apache.xml.internal.security.signature

XMLSignature

public final class XMLSignature extends SignatureElementProxy
Handles <ds:Signature> elements. This is the main class that deals with creating and verifying signatures.

There are 2 types of constructors for this class. The ones that take a document, baseURI and 1 or more Java Objects. This is mostly used for signing purposes. The other constructor is the one that takes a DOM Element and a BaseURI. This is used mostly with for verifying, when you have a SignatureElement. There are a few different types of methods:

  • The addDocument* methods are used to add References with optional transforms during signing.
  • addKeyInfo* methods are to add Certificates and Keys to the KeyInfo tags during signing.
  • appendObject allows a user to add any XML Structure as an ObjectContainer during signing.
  • sign and checkSignatureValue methods are used to sign and validate the signature.
author
$Author: raul $

Fields Summary
static Logger
log
{@link java.util.logging} logging facility
public static final String
ALGO_ID_MAC_HMAC_SHA1
MAC - Required HMAC-SHA1
public static final String
ALGO_ID_SIGNATURE_DSA
Signature - Required DSAwithSHA1 (DSS)
public static final String
ALGO_ID_SIGNATURE_RSA
Signature - Recommended RSAwithSHA1
public static final String
ALGO_ID_SIGNATURE_RSA_SHA1
Signature - Recommended RSAwithSHA1
public static final String
ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5
Signature - NOT Recommended RSAwithMD5
public static final String
ALGO_ID_SIGNATURE_RSA_RIPEMD160
Signature - Optional RSAwithRIPEMD160
public static final String
ALGO_ID_SIGNATURE_RSA_SHA256
Signature - Optional RSAwithSHA256
public static final String
ALGO_ID_SIGNATURE_RSA_SHA384
Signature - Optional RSAwithSHA384
public static final String
ALGO_ID_SIGNATURE_RSA_SHA512
Signature - Optional RSAwithSHA512
public static final String
ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5
HMAC - NOT Recommended HMAC-MD5
public static final String
ALGO_ID_MAC_HMAC_RIPEMD160
HMAC - Optional HMAC-RIPEMD160
public static final String
ALGO_ID_MAC_HMAC_SHA256
HMAC - Optional HMAC-SHA256
public static final String
ALGO_ID_MAC_HMAC_SHA384
HMAC - Optional HMAC-SHA284
public static final String
ALGO_ID_MAC_HMAC_SHA512
HMAC - Optional HMAC-SHA512
private SignedInfo
_signedInfo
ds:Signature.ds:SignedInfo element
private KeyInfo
_keyInfo
ds:Signature.ds:KeyInfo
private boolean
_followManifestsDuringValidation
Checking the digests in References in a Signature are mandatory, but for References inside a Manifest it is application specific. This boolean is to indicate that the References inside Manifests should be validated.
Constructors Summary
public XMLSignature(Document doc, String BaseURI, String SignatureMethodURI)
This creates a new ds:Signature Element and adds an empty ds:SignedInfo. The ds:SignedInfo is initialized with the specified Signature algorithm and Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS which is REQUIRED by the spec. This method's main use is for creating a new signature.

param
doc Document in which the signature will be appended after creation.
param
BaseURI URI to be used as context for all relative URIs.
param
SignatureMethodURI signature algorithm to use.
throws
XMLSecurityException


                                                                            
         
             
      this(doc, BaseURI, SignatureMethodURI, 0,
           Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
   
public XMLSignature(Document doc, String BaseURI, String SignatureMethodURI, int HMACOutputLength)
Constructor XMLSignature

param
doc
param
BaseURI
param
SignatureMethodURI the Signature method to be used.
param
HMACOutputLength
throws
XMLSecurityException

      this(doc, BaseURI, SignatureMethodURI, HMACOutputLength,
           Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
   
public XMLSignature(Document doc, String BaseURI, String SignatureMethodURI, String CanonicalizationMethodURI)
Constructor XMLSignature

param
doc
param
BaseURI
param
SignatureMethodURI the Signature method to be used.
param
CanonicalizationMethodURI the canonicalization algorithm to be used to c14nize the SignedInfo element.
throws
XMLSecurityException

      this(doc, BaseURI, SignatureMethodURI, 0, CanonicalizationMethodURI);
   
public XMLSignature(Document doc, String BaseURI, String SignatureMethodURI, int HMACOutputLength, String CanonicalizationMethodURI)
Constructor XMLSignature

param
doc
param
BaseURI
param
SignatureMethodURI
param
HMACOutputLength
param
CanonicalizationMethodURI
throws
XMLSecurityException


      super(doc);

      XMLUtils.addReturnToElement(this._constructionElement);

      this._baseURI = BaseURI;
      this._signedInfo = new SignedInfo(this._doc, SignatureMethodURI,
                                        HMACOutputLength,
                                        CanonicalizationMethodURI);

      this._constructionElement.appendChild(this._signedInfo.getElement());
      XMLUtils.addReturnToElement(this._constructionElement);

      // create an empty SignatureValue; this is filled by setSignatureValueElement
      Element signatureValueElement =
         XMLUtils.createElementInSignatureSpace(this._doc,
                                                Constants._TAG_SIGNATUREVALUE);

      this._constructionElement.appendChild(signatureValueElement);
      XMLUtils.addReturnToElement(this._constructionElement);
   
public XMLSignature(Document doc, String BaseURI, Element SignatureMethodElem, Element CanonicalizationMethodElem)
Creates a XMLSignature in a Document

param
doc
param
BaseURI
param
SignatureMethodElem
param
CanonicalizationMethodElem
throws
XMLSecurityException


      super(doc);

      XMLUtils.addReturnToElement(this._constructionElement);

      this._baseURI = BaseURI;
      this._signedInfo = new SignedInfo(this._doc, SignatureMethodElem, CanonicalizationMethodElem);

      this._constructionElement.appendChild(this._signedInfo.getElement());
      XMLUtils.addReturnToElement(this._constructionElement);

      // create an empty SignatureValue; this is filled by setSignatureValueElement
      Element signatureValueElement =
         XMLUtils.createElementInSignatureSpace(this._doc,
                                                Constants._TAG_SIGNATUREVALUE);

      this._constructionElement.appendChild(signatureValueElement);
      XMLUtils.addReturnToElement(this._constructionElement);
   
public XMLSignature(Element element, String BaseURI)
This will parse the element and construct the Java Objects. That will allow a user to validate the signature.

param
element ds:Signature element that contains the whole signature
param
BaseURI URI to be prepended to all relative URIs
throws
XMLSecurityException
throws
XMLSignatureException if the signature is badly formatted


      super(element, BaseURI);

      // check out SignedInfo child
      Element signedInfoElem = XMLUtils.selectDsNode(this._constructionElement.getFirstChild(),
                                  Constants._TAG_SIGNEDINFO,0);

      // check to see if it is there
      if (signedInfoElem == null) {
         Object exArgs[] = { Constants._TAG_SIGNEDINFO,
                             Constants._TAG_SIGNATURE };

         throw new XMLSignatureException("xml.WrongContent", exArgs);
      }

      // create a SignedInfo object from that element
      this._signedInfo = new SignedInfo(signedInfoElem, BaseURI);

      // check out SignatureValue child
      Element signatureValueElement = XMLUtils.selectDsNode(this._constructionElement.getFirstChild(),
                                         Constants._TAG_SIGNATUREVALUE,0);

      // check to see if it exists
      if (signatureValueElement == null) {
         Object exArgs[] = { Constants._TAG_SIGNATUREVALUE,
                             Constants._TAG_SIGNATURE };

         throw new XMLSignatureException("xml.WrongContent", exArgs);
      }

      // <element ref="ds:KeyInfo" minOccurs="0"/>
      Element keyInfoElem =XMLUtils.selectDsNode(this._constructionElement.getFirstChild(),
                               Constants._TAG_KEYINFO,0);

      // If it exists use it, but it's not mandatory
      if (keyInfoElem != null) {
         this._keyInfo = new KeyInfo(keyInfoElem, BaseURI);
      }
   
Methods Summary
public voidaddDocument(java.lang.String referenceURI, com.sun.org.apache.xml.internal.security.transforms.Transforms trans, java.lang.String digestURI, java.lang.String ReferenceId, java.lang.String ReferenceType)
Add a Reference with full parameters to this Signature

param
referenceURI URI of the resource to be signed. Can be null in which case the dereferencing is application specific. Can be "" in which it's the parent node (or parent document?). There can only be one "" in each signature.
param
trans Optional list of transformations to be done before digesting
param
digestURI Mandatory URI of the digesting algorithm to use.
param
ReferenceId Optional id attribute for this Reference
param
ReferenceType Optional mimetype for the URI
throws
XMLSignatureException

      this._signedInfo.addDocument(this._baseURI, referenceURI, trans,
                                   digestURI, ReferenceId, ReferenceType);
   
public voidaddDocument(java.lang.String referenceURI, com.sun.org.apache.xml.internal.security.transforms.Transforms trans, java.lang.String digestURI)
This method is a proxy method for the {@link Manifest#addDocument} method.

param
referenceURI URI according to the XML Signature specification.
param
trans List of transformations to be applied.
param
digestURI URI of the digest algorithm to be used.
see
Manifest#addDocument
throws
XMLSignatureException

      this._signedInfo.addDocument(this._baseURI, referenceURI, trans,
                                   digestURI, null, null);
   
public voidaddDocument(java.lang.String referenceURI, com.sun.org.apache.xml.internal.security.transforms.Transforms trans)
Adds a Reference with just the URI and the transforms. This used the SHA1 algorithm as a default digest algorithm.

param
referenceURI URI according to the XML Signature specification.
param
trans List of transformations to be applied.
throws
XMLSignatureException

      this._signedInfo.addDocument(this._baseURI, referenceURI, trans,
                                   Constants.ALGO_ID_DIGEST_SHA1, null, null);
   
public voidaddDocument(java.lang.String referenceURI)
Add a Reference with just this URI. It uses SHA1 by default as the digest algorithm

param
referenceURI URI according to the XML Signature specification.
throws
XMLSignatureException

      this._signedInfo.addDocument(this._baseURI, referenceURI, null,
                                   Constants.ALGO_ID_DIGEST_SHA1, null, null);
   
public voidaddKeyInfo(java.security.cert.X509Certificate cert)
Add an X509 Certificate to the KeyInfo. This will include the whole cert inside X509Data/X509Certificate tags.

param
cert Certificate to be included. This should be the certificate of the key that was used to sign.
throws
XMLSecurityException


      X509Data x509data = new X509Data(this._doc);

      x509data.addCertificate(cert);
      this.getKeyInfo().add(x509data);
   
public voidaddKeyInfo(java.security.PublicKey pk)
Add this public key to the KeyInfo. This will include the complete key in the KeyInfo structure.

param
pk

      this.getKeyInfo().add(pk);
   
public voidaddResourceResolver(com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver resolver)
Adds a {@link ResourceResolver} to enable the retrieval of resources.

param
resolver

      this.getSignedInfo().addResourceResolver(resolver);
   
public voidaddResourceResolver(com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverSpi resolver)
Adds a {@link ResourceResolverSpi} to enable the retrieval of resources.

param
resolver

      this.getSignedInfo().addResourceResolver(resolver);
   
public voidappendObject(com.sun.org.apache.xml.internal.security.signature.ObjectContainer object)
Appends an Object (not a java.lang.Object but an Object element) to the Signature. Please note that this is only possible when signing.

param
object ds:Object to be appended.
throws
XMLSignatureException When this object is used to verify.


      try {
         if (this._state != MODE_SIGN) {
            throw new XMLSignatureException(
               "signature.operationOnlyBeforeSign");
         }

         this._constructionElement.appendChild(object.getElement());
         XMLUtils.addReturnToElement(this._constructionElement);
      } catch (XMLSecurityException ex) {
         throw new XMLSignatureException("empty", ex);
      }
   
public booleancheckSignatureValue(java.security.cert.X509Certificate cert)
Extracts the public key from the certificate and verifies if the signature is valid by re-digesting all References, comparing those against the stored DigestValues and then checking to see if the Signatures match on the SignedInfo.

param
cert Certificate that contains the public key part of the keypair that was used to sign.
return
true if the signature is valid, false otherwise
throws
XMLSignatureException


      // see if cert is null
      if (cert != null) {

         //check the values with the public key from the cert
         return this.checkSignatureValue(cert.getPublicKey());
      } 
      
      Object exArgs[] = { "Didn't get a certificate" };
      throw new XMLSignatureException("empty", exArgs);
      
   
public booleancheckSignatureValue(java.security.Key pk)
Verifies if the signature is valid by redigesting all References, comparing those against the stored DigestValues and then checking to see if the Signatures match on the SignedInfo.

param
pk {@link java.security.PublicKey} part of the keypair or {@link javax.crypto.SecretKey} that was used to sign
return
true if the signature is valid, false otherwise
throws
XMLSignatureException


      //COMMENT: pk suggests it can only be a public key?
      //check to see if the key is not null
      if (pk == null) {
         Object exArgs[] = { "Didn't get a key" };

         throw new XMLSignatureException("empty", exArgs);
      }

      try {

         //create a SignatureAlgorithms from the SignatureMethod inside
         //SignedInfo. This is used to validate the signature.
         SignatureAlgorithm sa =
            new SignatureAlgorithm(this.getSignedInfo()
               .getSignatureMethodElement(), this.getBaseURI());
         if (true) {
         	if (log.isLoggable(java.util.logging.Level.FINE))                                     log.log(java.util.logging.Level.FINE, "SignatureMethodURI = " + sa.getAlgorithmURI());
         	if (log.isLoggable(java.util.logging.Level.FINE))                                     log.log(java.util.logging.Level.FINE, "jceSigAlgorithm    = " + sa.getJCEAlgorithmString());
         	if (log.isLoggable(java.util.logging.Level.FINE))                                     log.log(java.util.logging.Level.FINE, "jceSigProvider     = " + sa.getJCEProviderName());
         	if (log.isLoggable(java.util.logging.Level.FINE))                                     log.log(java.util.logging.Level.FINE, "PublicKey = " + pk);
         }
         sa.initVerify(pk);

         // Get the canonicalized (normalized) SignedInfo
         SignerOutputStream so=new SignerOutputStream(sa);
         OutputStream bos=new UnsyncBufferedOutputStream(so);
         this._signedInfo.signInOctectStream(bos);
         try {
			bos.close();
		} catch (IOException e) {
			//Imposible
		}
         
         //retrieve the byte[] from the stored signature
         byte sigBytes[] = this.getSignatureValue();


         //Have SignatureAlgorithm sign the input bytes and compare them to the
         //bytes that were stored in the signature.
         if (!sa.verify(sigBytes)) {
	    return false;
	 }

         // all references inside the signedinfo need to be dereferenced and
         // digested again to see if the outcome matches the stored value in the
         // SignedInfo.
         // If _followManifestsDuringValidation is true it will do the same for
         // References inside a Manifest.
         return this.getSignedInfo().verify
		(this._followManifestsDuringValidation);
      } catch (XMLSecurityException ex) {
         throw new XMLSignatureException("empty", ex);
      } 
   
public javax.crypto.SecretKeycreateSecretKey(byte[] secretKeyBytes)
Proxy method for {@link SignedInfo#createSecretKey(byte[])}. If you want to create a MAC, this method helps you to obtain the {@link javax.crypto.SecretKey} from octets.

param
secretKeyBytes
return
the secret key created.
see
SignedInfo#createSecretKey(byte[])

      return this.getSignedInfo().createSecretKey(secretKeyBytes);
   
public java.lang.StringgetBaseLocalName()
Get the local name of this element

return
Constant._TAG_SIGNATURE

      return Constants._TAG_SIGNATURE;
   
public java.lang.StringgetId()
Returns the Id attribute

return
the Id attribute

      return this._constructionElement.getAttributeNS(null, Constants._ATT_ID);
   
public com.sun.org.apache.xml.internal.security.keys.KeyInfogetKeyInfo()
Returns the KeyInfo child. If we are in signing mode and the KeyInfo does not exist yet, it is created on demand and added to the Signature.
This allows to add arbitrary content to the KeyInfo during signing.

return
the KeyInfo object


      // check to see if we are signing and if we have to create a keyinfo
      if ((this._state == MODE_SIGN) && (this._keyInfo == null)) {

         // create the KeyInfo
         this._keyInfo = new KeyInfo(this._doc);

         // get the Element from KeyInfo
         Element keyInfoElement = this._keyInfo.getElement();
         Element firstObject=null;
         Node sibling= this._constructionElement.getFirstChild();
         firstObject = XMLUtils.selectDsNode(sibling,Constants._TAG_OBJECT,0);
	   	     
            if (firstObject != null) {

               // add it before the object
               this._constructionElement.insertBefore(keyInfoElement,
                                                      firstObject);
               this._constructionElement
                  .insertBefore(this._doc.createTextNode("\n"), firstObject);
            } else {

               // add it as the last element to the signature
               this._constructionElement.appendChild(keyInfoElement);
               XMLUtils.addReturnToElement(this._constructionElement);
            }         
      }

      return this._keyInfo;
   
public com.sun.org.apache.xml.internal.security.signature.ObjectContainergetObjectItem(int i)
Returns the ith ds:Object child of the signature or null if no such ds:Object element exists.

param
i
return
the ith ds:Object child of the signature or null if no such ds:Object element exists.


      Element objElem = XMLUtils.selectDsNode(this._constructionElement.getFirstChild(),
            Constants._TAG_OBJECT,i);

      try {
         return new ObjectContainer(objElem, this._baseURI);
      } catch (XMLSecurityException ex) {
         return null;
      }
   
public intgetObjectLength()
Returns the number of all ds:Object elements.

return
the number of all ds:Object elements.

      return this.length(Constants.SignatureSpecNS, Constants._TAG_OBJECT);
   
public byte[]getSignatureValue()
Returns the octet value of the SignatureValue element. Throws an XMLSignatureException if it has no or wrong content.

return
the value of the SignatureValue element.
throws
XMLSignatureException If there is no content


      try {
         Element signatureValueElem = XMLUtils.selectDsNode(this._constructionElement.getFirstChild(),
                                         Constants._TAG_SIGNATUREVALUE,0);
         byte[] signatureValue = Base64.decode(signatureValueElem);

         return signatureValue;
      } catch (Base64DecodingException ex) {
         throw new XMLSignatureException("empty", ex);
      }
   
public com.sun.org.apache.xml.internal.security.signature.SignedInfogetSignedInfo()
Returns the completely parsed SignedInfo object.

return
the completely parsed SignedInfo object.

      return this._signedInfo;
   
public voidsetFollowNestedManifests(boolean followManifests)
Signal wether Manifest should be automatically validated. Checking the digests in References in a Signature are mandatory, but for References inside a Manifest it is application specific. This boolean is to indicate that the References inside Manifests should be validated.

param
followManifests
see
Core validation section in the XML Signature Rec.

      this._followManifestsDuringValidation = followManifests;
   
public voidsetId(java.lang.String Id)
Sets the Id attribute

param
Id Id value to be used by the id attribute on the Signature Element


      if ((this._state == MODE_SIGN) && (Id != null)) {
         this._constructionElement.setAttributeNS(null, Constants._ATT_ID, Id);
         IdResolver.registerElementById(this._constructionElement, Id);
      }
   
private voidsetSignatureValueElement(byte[] bytes)
Base64 encodes and sets the bytes as the content of the SignatureValue Node.

param
bytes bytes to be used by SignatureValue before Base64 encoding


      if (this._state == MODE_SIGN) {
         Element signatureValueElem = XMLUtils.selectDsNode(this._constructionElement.getFirstChild(),
                                         Constants._TAG_SIGNATUREVALUE,0);
         while (signatureValueElem.hasChildNodes()) {
            signatureValueElem.removeChild(signatureValueElem.getFirstChild());
         }

         String base64codedValue = Base64.encode(bytes);

         if (base64codedValue.length() > 76) {
            base64codedValue = "\n" + base64codedValue + "\n";
         }

         Text t = this._doc.createTextNode(base64codedValue);

         signatureValueElem.appendChild(t);
      }
   
public voidsign(java.security.Key signingKey)
Digests all References in the SignedInfo, calculates the signature value and sets it in the SignatureValue Element.

param
signingKey the {@link java.security.PrivateKey} or {@link javax.crypto.SecretKey} that is used to sign.
throws
XMLSignatureException


      if (signingKey instanceof PublicKey) {
         throw new IllegalArgumentException(I18n
            .translate("algorithms.operationOnlyVerification"));
      }

      try {
         if (this._state == MODE_SIGN) {

            // XMLUtils.indentSignature(this._constructionElement, "   ", 0);
            // get the SignatureMethodElement
            Element signatureMethodElement =
               this._signedInfo.getSignatureMethodElement();

            //Create a SignatureAlgorithm object
            SignatureAlgorithm sa =
               new SignatureAlgorithm(signatureMethodElement,
                                      this.getBaseURI());

            // initialize SignatureAlgorithm for signing
            sa.initSign(signingKey);

            SignedInfo si = this.getSignedInfo();

            // generate digest values for all References in this SignedInfo
            si.generateDigestValues();
            OutputStream so=new UnsyncBufferedOutputStream(new SignerOutputStream(sa));
            try {
                so.close();
            } catch (IOException e) {
                //Imposible
            }
            // get the canonicalized bytes from SignedInfo
            si.signInOctectStream(so);

            byte jcebytes[] = sa.sign();

            // set them on the SignateValue element
            this.setSignatureValueElement(jcebytes);
         }
      } catch (CanonicalizationException ex) {
         throw new XMLSignatureException("empty", ex);
      } catch (InvalidCanonicalizerException ex) {
         throw new XMLSignatureException("empty", ex);
      } catch (XMLSecurityException ex) {
         throw new XMLSignatureException("empty", ex);
      }