XMLSignaturepublic 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.
|
Fields Summary |
---|
static Logger | log{@link java.util.logging} logging facility | public static final String | ALGO_ID_MAC_HMAC_SHA1MAC - Required HMAC-SHA1 | public static final String | ALGO_ID_SIGNATURE_DSASignature - Required DSAwithSHA1 (DSS) | public static final String | ALGO_ID_SIGNATURE_RSASignature - Recommended RSAwithSHA1 | public static final String | ALGO_ID_SIGNATURE_RSA_SHA1Signature - Recommended RSAwithSHA1 | public static final String | ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5Signature - NOT Recommended RSAwithMD5 | public static final String | ALGO_ID_SIGNATURE_RSA_RIPEMD160Signature - Optional RSAwithRIPEMD160 | public static final String | ALGO_ID_SIGNATURE_RSA_SHA256Signature - Optional RSAwithSHA256 | public static final String | ALGO_ID_SIGNATURE_RSA_SHA384Signature - Optional RSAwithSHA384 | public static final String | ALGO_ID_SIGNATURE_RSA_SHA512Signature - Optional RSAwithSHA512 | public static final String | ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5HMAC - NOT Recommended HMAC-MD5 | public static final String | ALGO_ID_MAC_HMAC_RIPEMD160HMAC - Optional HMAC-RIPEMD160 | public static final String | ALGO_ID_MAC_HMAC_SHA256HMAC - Optional HMAC-SHA256 | public static final String | ALGO_ID_MAC_HMAC_SHA384HMAC - Optional HMAC-SHA284 | public static final String | ALGO_ID_MAC_HMAC_SHA512HMAC - Optional HMAC-SHA512 | private SignedInfo | _signedInfods:Signature.ds:SignedInfo element | private KeyInfo | _keyInfods:Signature.ds:KeyInfo | private boolean | _followManifestsDuringValidationChecking 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.
this(doc, BaseURI, SignatureMethodURI, 0,
Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
| public XMLSignature(Document doc, String BaseURI, String SignatureMethodURI, int HMACOutputLength)Constructor XMLSignature
this(doc, BaseURI, SignatureMethodURI, HMACOutputLength,
Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
| public XMLSignature(Document doc, String BaseURI, String SignatureMethodURI, String CanonicalizationMethodURI)Constructor XMLSignature
this(doc, BaseURI, SignatureMethodURI, 0, CanonicalizationMethodURI);
| public XMLSignature(Document doc, String BaseURI, String SignatureMethodURI, int HMACOutputLength, String CanonicalizationMethodURI)Constructor XMLSignature
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
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.
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 void | addDocument(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
this._signedInfo.addDocument(this._baseURI, referenceURI, trans,
digestURI, ReferenceId, ReferenceType);
| public void | addDocument(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.
this._signedInfo.addDocument(this._baseURI, referenceURI, trans,
digestURI, null, null);
| public void | addDocument(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.
this._signedInfo.addDocument(this._baseURI, referenceURI, trans,
Constants.ALGO_ID_DIGEST_SHA1, null, null);
| public void | addDocument(java.lang.String referenceURI)Add a Reference with just this URI. It uses SHA1 by default as the digest
algorithm
this._signedInfo.addDocument(this._baseURI, referenceURI, null,
Constants.ALGO_ID_DIGEST_SHA1, null, null);
| public void | addKeyInfo(java.security.cert.X509Certificate cert)Add an X509 Certificate to the KeyInfo. This will include the whole cert
inside X509Data/X509Certificate tags.
X509Data x509data = new X509Data(this._doc);
x509data.addCertificate(cert);
this.getKeyInfo().add(x509data);
| public void | addKeyInfo(java.security.PublicKey pk)Add this public key to the KeyInfo. This will include the complete key in
the KeyInfo structure.
this.getKeyInfo().add(pk);
| public void | addResourceResolver(com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver resolver)Adds a {@link ResourceResolver} to enable the retrieval of resources.
this.getSignedInfo().addResourceResolver(resolver);
| public void | addResourceResolver(com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverSpi resolver)Adds a {@link ResourceResolverSpi} to enable the retrieval of resources.
this.getSignedInfo().addResourceResolver(resolver);
| public void | appendObject(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.
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 boolean | checkSignatureValue(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.
// 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 boolean | checkSignatureValue(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.
//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.SecretKey | createSecretKey(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.
return this.getSignedInfo().createSecretKey(secretKeyBytes);
| public java.lang.String | getBaseLocalName()Get the local name of this element
return Constants._TAG_SIGNATURE;
| public java.lang.String | getId()Returns the Id attribute
return this._constructionElement.getAttributeNS(null, Constants._ATT_ID);
| public com.sun.org.apache.xml.internal.security.keys.KeyInfo | getKeyInfo()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.
// 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.ObjectContainer | getObjectItem(int i)Returns 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 int | getObjectLength()Returns 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.
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.SignedInfo | getSignedInfo()Returns the completely parsed SignedInfo object.
return this._signedInfo;
| public void | setFollowNestedManifests(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.
this._followManifestsDuringValidation = followManifests;
| public void | setId(java.lang.String Id)Sets the Id attribute
if ((this._state == MODE_SIGN) && (Id != null)) {
this._constructionElement.setAttributeNS(null, Constants._ATT_ID, Id);
IdResolver.registerElementById(this._constructionElement, Id);
}
| private void | setSignatureValueElement(byte[] bytes)Base64 encodes and sets the bytes as the content of the SignatureValue
Node.
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 void | sign(java.security.Key signingKey)Digests all References in the SignedInfo, calculates the signature value and
sets it in the SignatureValue Element.
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);
}
|
|