1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Copyright 1999-2004 The Apache Software Foundation. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 */ 21 package com.sun.org.apache.xml.internal.security.signature; 22 23 24 25 import java.io.IOException; 26 import java.io.OutputStream; 27 import java.security.Key; 28 import java.security.PublicKey; 29 import java.security.cert.X509Certificate; 30 31 import javax.crypto.SecretKey; 32 33 import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithm; 34 import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException; 35 import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer; 36 import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException; 37 import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException; 38 import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; 39 import com.sun.org.apache.xml.internal.security.keys.KeyInfo; 40 import com.sun.org.apache.xml.internal.security.keys.content.X509Data; 41 import com.sun.org.apache.xml.internal.security.transforms.Transforms; 42 import com.sun.org.apache.xml.internal.security.utils.Base64; 43 import com.sun.org.apache.xml.internal.security.utils.Constants; 44 import com.sun.org.apache.xml.internal.security.utils.I18n; 45 import com.sun.org.apache.xml.internal.security.utils.IdResolver; 46 import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; 47 import com.sun.org.apache.xml.internal.security.utils.SignerOutputStream; 48 import com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream; 49 import com.sun.org.apache.xml.internal.security.utils.XMLUtils; 50 import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver; 51 import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverSpi; 52 import org.w3c.dom.Attr; 53 import org.w3c.dom.Document; 54 import org.w3c.dom.Element; 55 import org.w3c.dom.Node; 56 import org.w3c.dom.NodeList; 57 import org.w3c.dom.Text; 58 59 60 /** 61 * Handles <code><ds:Signature></code> elements. 62 * This is the main class that deals with creating and verifying signatures. 63 * 64 * <p>There are 2 types of constructors for this class. The ones that take a 65 * document, baseURI and 1 or more Java Objects. This is mostly used for 66 * signing purposes. 67 * The other constructor is the one that takes a DOM Element and a BaseURI. 68 * This is used mostly with for verifying, when you have a SignatureElement. 69 * 70 * There are a few different types of methods: 71 * <ul><li>The addDocument* methods are used to add References with optional 72 * transforms during signing. </li> 73 * <li>addKeyInfo* methods are to add Certificates and Keys to the 74 * KeyInfo tags during signing. </li> 75 * <li>appendObject allows a user to add any XML Structure as an 76 * ObjectContainer during signing.</li> 77 * <li>sign and checkSignatureValue methods are used to sign and validate the 78 * signature. </li></ul> 79 * 80 * @author $Author: mullan $ 81 */ 82 public final class XMLSignature extends SignatureElementProxy { 83 84 /** {@link java.util.logging} logging facility */ 85 static java.util.logging.Logger log = 86 java.util.logging.Logger.getLogger(XMLSignature.class.getName()); 87 88 //J- 89 /** MAC - Required HMAC-SHA1 */ 90 public static final String ALGO_ID_MAC_HMAC_SHA1 = Constants.SignatureSpecNS + "hmac-sha1"; 91 92 /** Signature - Required DSAwithSHA1 (DSS) */ 93 public static final String ALGO_ID_SIGNATURE_DSA = Constants.SignatureSpecNS + "dsa-sha1"; 94 95 /** Signature - Recommended RSAwithSHA1 */ 96 public static final String ALGO_ID_SIGNATURE_RSA = Constants.SignatureSpecNS + "rsa-sha1"; 97 /** Signature - Recommended RSAwithSHA1 */ 98 public static final String ALGO_ID_SIGNATURE_RSA_SHA1 = Constants.SignatureSpecNS + "rsa-sha1"; 99 /** Signature - NOT Recommended RSAwithMD5 */ 100 public static final String ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5 = Constants.MoreAlgorithmsSpecNS + "rsa-md5"; 101 /** Signature - Optional RSAwithRIPEMD160 */ 102 public static final String ALGO_ID_SIGNATURE_RSA_RIPEMD160 = Constants.MoreAlgorithmsSpecNS + "rsa-ripemd160"; 103 /** Signature - Optional RSAwithSHA256 */ 104 public static final String ALGO_ID_SIGNATURE_RSA_SHA256 = Constants.MoreAlgorithmsSpecNS + "rsa-sha256"; 105 /** Signature - Optional RSAwithSHA384 */ 106 public static final String ALGO_ID_SIGNATURE_RSA_SHA384 = Constants.MoreAlgorithmsSpecNS + "rsa-sha384"; 107 /** Signature - Optional RSAwithSHA512 */ 108 public static final String ALGO_ID_SIGNATURE_RSA_SHA512 = Constants.MoreAlgorithmsSpecNS + "rsa-sha512"; 109 110 /** HMAC - NOT Recommended HMAC-MD5 */ 111 public static final String ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5 = Constants.MoreAlgorithmsSpecNS + "hmac-md5"; 112 /** HMAC - Optional HMAC-RIPEMD160 */ 113 public static final String ALGO_ID_MAC_HMAC_RIPEMD160 = Constants.MoreAlgorithmsSpecNS + "hmac-ripemd160"; 114 /** HMAC - Optional HMAC-SHA256 */ 115 public static final String ALGO_ID_MAC_HMAC_SHA256 = Constants.MoreAlgorithmsSpecNS + "hmac-sha256"; 116 /** HMAC - Optional HMAC-SHA284 */ 117 public static final String ALGO_ID_MAC_HMAC_SHA384 = Constants.MoreAlgorithmsSpecNS + "hmac-sha384"; 118 /** HMAC - Optional HMAC-SHA512 */ 119 public static final String ALGO_ID_MAC_HMAC_SHA512 = Constants.MoreAlgorithmsSpecNS + "hmac-sha512"; 120 /**Signature - Optional ECDSAwithSHA1 */ 121 public static final String ALGO_ID_SIGNATURE_ECDSA_SHA1 = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1"; 122 123 124 //J+ 125 126 /** ds:Signature.ds:SignedInfo element */ 127 private SignedInfo _signedInfo = null; 128 129 /** ds:Signature.ds:KeyInfo */ 130 private KeyInfo _keyInfo = null; 131 132 /** 133 * Checking the digests in References in a Signature are mandatory, but for 134 * References inside a Manifest it is application specific. This boolean is 135 * to indicate that the References inside Manifests should be validated. 136 */ 137 private boolean _followManifestsDuringValidation = false; 138 139 private Element signatureValueElement; 140 141 /** 142 * This creates a new <CODE>ds:Signature</CODE> Element and adds an empty 143 * <CODE>ds:SignedInfo</CODE>. 144 * The <code>ds:SignedInfo</code> is initialized with the specified Signature 145 * algorithm and Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS which is REQUIRED 146 * by the spec. This method's main use is for creating a new signature. 147 * 148 * @param doc Document in which the signature will be appended after creation. 149 * @param BaseURI URI to be used as context for all relative URIs. 150 * @param SignatureMethodURI signature algorithm to use. 151 * @throws XMLSecurityException 152 */ 153 public XMLSignature(Document doc, String BaseURI, String SignatureMethodURI) 154 throws XMLSecurityException { 155 this(doc, BaseURI, SignatureMethodURI, 0, 156 Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS); 157 } 158 159 /** 160 * Constructor XMLSignature 161 * 162 * @param doc 163 * @param BaseURI 164 * @param SignatureMethodURI the Signature method to be used. 165 * @param HMACOutputLength 166 * @throws XMLSecurityException 167 */ 168 public XMLSignature( 169 Document doc, String BaseURI, String SignatureMethodURI, int HMACOutputLength) 170 throws XMLSecurityException { 171 this(doc, BaseURI, SignatureMethodURI, HMACOutputLength, 172 Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS); 173 } 174 175 /** 176 * Constructor XMLSignature 177 * 178 * @param doc 179 * @param BaseURI 180 * @param SignatureMethodURI the Signature method to be used. 181 * @param CanonicalizationMethodURI the canonicalization algorithm to be used to c14nize the SignedInfo element. 182 * @throws XMLSecurityException 183 */ 184 public XMLSignature( 185 Document doc, String BaseURI, String SignatureMethodURI, String CanonicalizationMethodURI) 186 throws XMLSecurityException { 187 this(doc, BaseURI, SignatureMethodURI, 0, CanonicalizationMethodURI); 188 } 189 190 /** 191 * Constructor XMLSignature 192 * 193 * @param doc 194 * @param BaseURI 195 * @param SignatureMethodURI 196 * @param HMACOutputLength 197 * @param CanonicalizationMethodURI 198 * @throws XMLSecurityException 199 */ 200 public XMLSignature( 201 Document doc, String BaseURI, String SignatureMethodURI, int HMACOutputLength, String CanonicalizationMethodURI) 202 throws XMLSecurityException { 203 204 super(doc); 205 206 String xmlnsDsPrefix = getDefaultPrefix(Constants.SignatureSpecNS); 207 if (xmlnsDsPrefix == null) { 208 this._constructionElement.setAttributeNS 209 (Constants.NamespaceSpecNS, "xmlns", Constants.SignatureSpecNS); 210 } else { 211 this._constructionElement.setAttributeNS 212 (Constants.NamespaceSpecNS, "xmlns:" + xmlnsDsPrefix, Constants.SignatureSpecNS); 213 } 214 XMLUtils.addReturnToElement(this._constructionElement); 215 216 this._baseURI = BaseURI; 217 this._signedInfo = new SignedInfo(this._doc, SignatureMethodURI, 218 HMACOutputLength, 219 CanonicalizationMethodURI); 220 221 this._constructionElement.appendChild(this._signedInfo.getElement()); 222 XMLUtils.addReturnToElement(this._constructionElement); 223 224 // create an empty SignatureValue; this is filled by setSignatureValueElement 225 signatureValueElement = 226 XMLUtils.createElementInSignatureSpace(this._doc, 227 Constants._TAG_SIGNATUREVALUE); 228 229 this._constructionElement.appendChild(signatureValueElement); 230 XMLUtils.addReturnToElement(this._constructionElement); 231 } 232 /** 233 * Creates a XMLSignature in a Document 234 * @param doc 235 * @param BaseURI 236 * @param SignatureMethodElem 237 * @param CanonicalizationMethodElem 238 * @throws XMLSecurityException 239 */ 240 public XMLSignature( 241 Document doc, String BaseURI, Element SignatureMethodElem, Element CanonicalizationMethodElem) 242 throws XMLSecurityException { 243 244 super(doc); 245 246 String xmlnsDsPrefix = getDefaultPrefix(Constants.SignatureSpecNS); 247 if (xmlnsDsPrefix == null) { 248 this._constructionElement.setAttributeNS 249 (Constants.NamespaceSpecNS, "xmlns", Constants.SignatureSpecNS); 250 } else { 251 this._constructionElement.setAttributeNS 252 (Constants.NamespaceSpecNS, "xmlns:" + xmlnsDsPrefix, Constants.SignatureSpecNS); 253 } 254 XMLUtils.addReturnToElement(this._constructionElement); 255 256 this._baseURI = BaseURI; 257 this._signedInfo = new SignedInfo(this._doc, SignatureMethodElem, CanonicalizationMethodElem); 258 259 this._constructionElement.appendChild(this._signedInfo.getElement()); 260 XMLUtils.addReturnToElement(this._constructionElement); 261 262 // create an empty SignatureValue; this is filled by setSignatureValueElement 263 signatureValueElement = 264 XMLUtils.createElementInSignatureSpace(this._doc, 265 Constants._TAG_SIGNATUREVALUE); 266 267 this._constructionElement.appendChild(signatureValueElement); 268 XMLUtils.addReturnToElement(this._constructionElement); 269 } 270 271 /** 272 * This will parse the element and construct the Java Objects. 273 * That will allow a user to validate the signature. 274 * 275 * @param element ds:Signature element that contains the whole signature 276 * @param BaseURI URI to be prepended to all relative URIs 277 * @throws XMLSecurityException 278 * @throws XMLSignatureException if the signature is badly formatted 279 */ 280 public XMLSignature(Element element, String BaseURI) 281 throws XMLSignatureException, XMLSecurityException { 282 283 super(element, BaseURI); 284 285 // check out SignedInfo child 286 Element signedInfoElem = XMLUtils.getNextElement(element.getFirstChild());// XMLUtils.selectDsNode(this._constructionElement.getFirstChild(), 287 //Constants._TAG_SIGNEDINFO,0); 288 289 // check to see if it is there 290 if (signedInfoElem == null) { 291 Object exArgs[] = { Constants._TAG_SIGNEDINFO, 292 Constants._TAG_SIGNATURE }; 293 294 throw new XMLSignatureException("xml.WrongContent", exArgs); 295 } 296 297 // create a SignedInfo object from that element 298 this._signedInfo = new SignedInfo(signedInfoElem, BaseURI); 299 300 // check out SignatureValue child 301 this.signatureValueElement =XMLUtils.getNextElement(signedInfoElem.getNextSibling()); //XMLUtils.selectDsNode(this._constructionElement.getFirstChild(), 302 // Constants._TAG_SIGNATUREVALUE,0); 303 304 // check to see if it exists 305 if (signatureValueElement == null) { 306 Object exArgs[] = { Constants._TAG_SIGNATUREVALUE, 307 Constants._TAG_SIGNATURE }; 308 309 throw new XMLSignatureException("xml.WrongContent", exArgs); 310 } 311 Attr signatureValueAttr = signatureValueElement.getAttributeNodeNS(null, "Id"); 312 if (signatureValueAttr != null) { 313 signatureValueElement.setIdAttributeNode(signatureValueAttr, true); 314 } 315 316 // <element ref="ds:KeyInfo" minOccurs="0"/> 317 Element keyInfoElem = XMLUtils.getNextElement(signatureValueElement.getNextSibling());//XMLUtils.selectDsNode(this._constructionElement.getFirstChild(), 318 // Constants._TAG_KEYINFO,0); 319 320 // If it exists use it, but it's not mandatory 321 if ((keyInfoElem != null) && (keyInfoElem.getNamespaceURI().equals(Constants.SignatureSpecNS) && 322 keyInfoElem.getLocalName().equals(Constants._TAG_KEYINFO)) ) { 323 this._keyInfo = new KeyInfo(keyInfoElem, BaseURI); 324 } 325 326 // <element ref="ds:Object" minOccurs="0" maxOccurs="unbounded"/> 327 Element objectElem = 328 XMLUtils.getNextElement(signatureValueElement.getNextSibling()); 329 while (objectElem != null) { 330 Attr objectAttr = objectElem.getAttributeNodeNS(null, "Id"); 331 if (objectAttr != null) { 332 objectElem.setIdAttributeNode(objectAttr, true); 333 } 334 335 NodeList nodes = objectElem.getChildNodes(); 336 int length = nodes.getLength(); 337 // Register Ids of the Object child elements 338 for (int i = 0; i < length; i++) { 339 Node child = nodes.item(i); 340 if (child.getNodeType() == Node.ELEMENT_NODE) { 341 Element childElem = (Element)child; 342 String tag = childElem.getLocalName(); 343 if (tag.equals("Manifest")) { 344 new Manifest(childElem, BaseURI); 345 } else if (tag.equals("SignatureProperties")) { 346 new SignatureProperties(childElem, BaseURI); 347 } 348 } 349 } 350 351 objectElem = XMLUtils.getNextElement(objectElem.getNextSibling()); 352 } 353 } 354 355 /** 356 * Sets the <code>Id</code> attribute 357 * 358 * @param Id Id value to be used by the id attribute on the Signature Element 359 */ 360 public void setId(String Id) { 361 362 if (Id != null) { 363 setLocalIdAttribute(Constants._ATT_ID, Id); 364 } 365 } 366 367 /** 368 * Returns the <code>Id</code> attribute 369 * 370 * @return the <code>Id</code> attribute 371 */ 372 public String getId() { 373 return this._constructionElement.getAttributeNS(null, Constants._ATT_ID); 374 } 375 376 /** 377 * Returns the completely parsed <code>SignedInfo</code> object. 378 * 379 * @return the completely parsed <code>SignedInfo</code> object. 380 */ 381 public SignedInfo getSignedInfo() { 382 return this._signedInfo; 383 } 384 385 /** 386 * Returns the octet value of the SignatureValue element. 387 * Throws an XMLSignatureException if it has no or wrong content. 388 * 389 * @return the value of the SignatureValue element. 390 * @throws XMLSignatureException If there is no content 391 */ 392 public byte[] getSignatureValue() throws XMLSignatureException { 393 394 try { 395 byte[] signatureValue = Base64.decode(signatureValueElement); 396 397 return signatureValue; 398 } catch (Base64DecodingException ex) { 399 throw new XMLSignatureException("empty", ex); 400 } 401 } 402 403 /** 404 * Base64 encodes and sets the bytes as the content of the SignatureValue 405 * Node. 406 * 407 * @param bytes bytes to be used by SignatureValue before Base64 encoding 408 */ 409 private void setSignatureValueElement(byte[] bytes) { 410 411 while (signatureValueElement.hasChildNodes()) { 412 signatureValueElement.removeChild 413 (signatureValueElement.getFirstChild()); 414 } 415 416 String base64codedValue = Base64.encode(bytes); 417 418 if (base64codedValue.length() > 76 && !XMLUtils.ignoreLineBreaks()) { 419 base64codedValue = "\n" + base64codedValue + "\n"; 420 } 421 422 Text t = this._doc.createTextNode(base64codedValue); 423 signatureValueElement.appendChild(t); 424 } 425 426 /** 427 * Returns the KeyInfo child. If we are in signing mode and the KeyInfo 428 * does not exist yet, it is created on demand and added to the Signature. 429 * <br> 430 * This allows to add arbitrary content to the KeyInfo during signing. 431 * 432 * @return the KeyInfo object 433 */ 434 public KeyInfo getKeyInfo() { 435 436 // check to see if we are signing and if we have to create a keyinfo 437 if ( (this._keyInfo == null)) { 438 439 // create the KeyInfo 440 this._keyInfo = new KeyInfo(this._doc); 441 442 // get the Element from KeyInfo 443 Element keyInfoElement = this._keyInfo.getElement(); 444 Element firstObject=null; 445 Node sibling= this._constructionElement.getFirstChild(); 446 firstObject = XMLUtils.selectDsNode(sibling,Constants._TAG_OBJECT,0); 447 448 if (firstObject != null) { 449 450 // add it before the object 451 this._constructionElement.insertBefore(keyInfoElement, 452 firstObject); 453 XMLUtils.addReturnBeforeChild(this._constructionElement, firstObject); 454 } else { 455 456 // add it as the last element to the signature 457 this._constructionElement.appendChild(keyInfoElement); 458 XMLUtils.addReturnToElement(this._constructionElement); 459 } 460 } 461 462 return this._keyInfo; 463 } 464 465 /** 466 * Appends an Object (not a <code>java.lang.Object</code> but an Object 467 * element) to the Signature. Please note that this is only possible 468 * when signing. 469 * 470 * @param object ds:Object to be appended. 471 * @throws XMLSignatureException When this object is used to verify. 472 */ 473 public void appendObject(ObjectContainer object) 474 throws XMLSignatureException { 475 476 //try { 477 //if (this._state != MODE_SIGN) { 478 // throw new XMLSignatureException( 479 // "signature.operationOnlyBeforeSign"); 480 //} 481 482 this._constructionElement.appendChild(object.getElement()); 483 XMLUtils.addReturnToElement(this._constructionElement); 484 //} catch (XMLSecurityException ex) { 485 // throw new XMLSignatureException("empty", ex); 486 //} 487 } 488 489 /** 490 * Returns the <code>i<code>th <code>ds:Object</code> child of the signature 491 * or null if no such <code>ds:Object</code> element exists. 492 * 493 * @param i 494 * @return the <code>i<code>th <code>ds:Object</code> child of the signature or null if no such <code>ds:Object</code> element exists. 495 */ 496 public ObjectContainer getObjectItem(int i) { 497 498 Element objElem = XMLUtils.selectDsNode(this._constructionElement.getFirstChild(), 499 Constants._TAG_OBJECT,i); 500 501 try { 502 return new ObjectContainer(objElem, this._baseURI); 503 } catch (XMLSecurityException ex) { 504 return null; 505 } 506 } 507 508 /** 509 * Returns the number of all <code>ds:Object</code> elements. 510 * 511 * @return the number of all <code>ds:Object</code> elements. 512 */ 513 public int getObjectLength() { 514 return this.length(Constants.SignatureSpecNS, Constants._TAG_OBJECT); 515 } 516 517 /** 518 * Digests all References in the SignedInfo, calculates the signature value and 519 * sets it in the SignatureValue Element. 520 * 521 * @param signingKey the {@link java.security.PrivateKey} or {@link javax.crypto.SecretKey} that is used to sign. 522 * @throws XMLSignatureException 523 */ 524 public void sign(Key signingKey) throws XMLSignatureException { 525 526 if (signingKey instanceof PublicKey) { 527 throw new IllegalArgumentException(I18n 528 .translate("algorithms.operationOnlyVerification")); 529 } 530 531 try { 532 // if (this._state == MODE_SIGN) { 533 //Create a SignatureAlgorithm object 534 SignedInfo si = this.getSignedInfo(); 535 SignatureAlgorithm sa = si.getSignatureAlgorithm(); 536 // initialize SignatureAlgorithm for signing 537 sa.initSign(signingKey); 538 539 // generate digest values for all References in this SignedInfo 540 si.generateDigestValues(); 541 OutputStream so=new UnsyncBufferedOutputStream(new SignerOutputStream(sa)); 542 try { 543 so.close(); 544 } catch (IOException e) { 545 //Imposible 546 } 547 // get the canonicalized bytes from SignedInfo 548 si.signInOctectStream(so); 549 550 byte jcebytes[] = sa.sign(); 551 552 // set them on the SignateValue element 553 this.setSignatureValueElement(jcebytes); 554 //} 555 } catch (CanonicalizationException ex) { 556 throw new XMLSignatureException("empty", ex); 557 } catch (InvalidCanonicalizerException ex) { 558 throw new XMLSignatureException("empty", ex); 559 } catch (XMLSecurityException ex) { 560 throw new XMLSignatureException("empty", ex); 561 } 562 } 563 564 /** 565 * Adds a {@link ResourceResolver} to enable the retrieval of resources. 566 * 567 * @param resolver 568 */ 569 public void addResourceResolver(ResourceResolver resolver) { 570 this.getSignedInfo().addResourceResolver(resolver); 571 } 572 573 /** 574 * Adds a {@link ResourceResolverSpi} to enable the retrieval of resources. 575 * 576 * @param resolver 577 */ 578 public void addResourceResolver(ResourceResolverSpi resolver) { 579 this.getSignedInfo().addResourceResolver(resolver); 580 } 581 582 /** 583 * Extracts the public key from the certificate and verifies if the signature 584 * is valid by re-digesting all References, comparing those against the 585 * stored DigestValues and then checking to see if the Signatures match on 586 * the SignedInfo. 587 * 588 * @param cert Certificate that contains the public key part of the keypair that was used to sign. 589 * @return true if the signature is valid, false otherwise 590 * @throws XMLSignatureException 591 */ 592 public boolean checkSignatureValue(X509Certificate cert) 593 throws XMLSignatureException { 594 595 // see if cert is null 596 if (cert != null) { 597 598 //check the values with the public key from the cert 599 return this.checkSignatureValue(cert.getPublicKey()); 600 } 601 602 Object exArgs[] = { "Didn't get a certificate" }; 603 throw new XMLSignatureException("empty", exArgs); 604 605 } 606 607 /** 608 * Verifies if the signature is valid by redigesting all References, 609 * comparing those against the stored DigestValues and then checking to see 610 * if the Signatures match on the SignedInfo. 611 * 612 * @param pk {@link java.security.PublicKey} part of the keypair or {@link javax.crypto.SecretKey} that was used to sign 613 * @return true if the signature is valid, false otherwise 614 * @throws XMLSignatureException 615 */ 616 public boolean checkSignatureValue(Key pk) throws XMLSignatureException { 617 618 //COMMENT: pk suggests it can only be a public key? 619 //check to see if the key is not null 620 if (pk == null) { 621 Object exArgs[] = { "Didn't get a key" }; 622 623 throw new XMLSignatureException("empty", exArgs); 624 } 625 // all references inside the signedinfo need to be dereferenced and 626 // digested again to see if the outcome matches the stored value in the 627 // SignedInfo. 628 // If _followManifestsDuringValidation is true it will do the same for 629 // References inside a Manifest. 630 try { 631 SignedInfo si=this.getSignedInfo(); 632 //create a SignatureAlgorithms from the SignatureMethod inside 633 //SignedInfo. This is used to validate the signature. 634 SignatureAlgorithm sa =si.getSignatureAlgorithm(); 635 if (log.isLoggable(java.util.logging.Level.FINE)) { 636 log.log(java.util.logging.Level.FINE, "SignatureMethodURI = " + sa.getAlgorithmURI()); 637 log.log(java.util.logging.Level.FINE, "jceSigAlgorithm = " + sa.getJCEAlgorithmString()); 638 log.log(java.util.logging.Level.FINE, "jceSigProvider = " + sa.getJCEProviderName()); 639 log.log(java.util.logging.Level.FINE, "PublicKey = " + pk); 640 } 641 sa.initVerify(pk); 642 643 // Get the canonicalized (normalized) SignedInfo 644 SignerOutputStream so=new SignerOutputStream(sa); 645 OutputStream bos=new UnsyncBufferedOutputStream(so); 646 si.signInOctectStream(bos); 647 try { 648 bos.close(); 649 } catch (IOException e) { 650 //Imposible 651 } 652 653 //retrieve the byte[] from the stored signature 654 byte sigBytes[] = this.getSignatureValue(); 655 656 //Have SignatureAlgorithm sign the input bytes and compare them to the 657 //bytes that were stored in the signature. 658 if (!sa.verify(sigBytes)) { 659 log.log(java.util.logging.Level.WARNING, "Signature verification failed."); 660 return false; 661 } 662 663 return si.verify(this._followManifestsDuringValidation); 664 } catch (XMLSecurityException ex) { 665 throw new XMLSignatureException("empty", ex); 666 } 667 } 668 669 /** 670 * Add a Reference with full parameters to this Signature 671 * 672 * @param referenceURI URI of the resource to be signed. Can be null in which 673 * case the dereferencing is application specific. Can be "" in which it's 674 * the parent node (or parent document?). There can only be one "" in each 675 * signature. 676 * @param trans Optional list of transformations to be done before digesting 677 * @param digestURI Mandatory URI of the digesting algorithm to use. 678 * @param ReferenceId Optional id attribute for this Reference 679 * @param ReferenceType Optional mimetype for the URI 680 * @throws XMLSignatureException 681 */ 682 public void addDocument( 683 String referenceURI, Transforms trans, String digestURI, String ReferenceId, String ReferenceType) 684 throws XMLSignatureException { 685 this._signedInfo.addDocument(this._baseURI, referenceURI, trans, 686 digestURI, ReferenceId, ReferenceType); 687 } 688 689 /** 690 * This method is a proxy method for the {@link Manifest#addDocument} method. 691 * 692 * @param referenceURI URI according to the XML Signature specification. 693 * @param trans List of transformations to be applied. 694 * @param digestURI URI of the digest algorithm to be used. 695 * @see Manifest#addDocument 696 * @throws XMLSignatureException 697 */ 698 public void addDocument( 699 String referenceURI, Transforms trans, String digestURI) 700 throws XMLSignatureException { 701 this._signedInfo.addDocument(this._baseURI, referenceURI, trans, 702 digestURI, null, null); 703 } 704 705 /** 706 * Adds a Reference with just the URI and the transforms. This used the 707 * SHA1 algorithm as a default digest algorithm. 708 * 709 * @param referenceURI URI according to the XML Signature specification. 710 * @param trans List of transformations to be applied. 711 * @throws XMLSignatureException 712 */ 713 public void addDocument(String referenceURI, Transforms trans) 714 throws XMLSignatureException { 715 this._signedInfo.addDocument(this._baseURI, referenceURI, trans, 716 Constants.ALGO_ID_DIGEST_SHA1, null, null); 717 } 718 719 /** 720 * Add a Reference with just this URI. It uses SHA1 by default as the digest 721 * algorithm 722 * 723 * @param referenceURI URI according to the XML Signature specification. 724 * @throws XMLSignatureException 725 */ 726 public void addDocument(String referenceURI) throws XMLSignatureException { 727 this._signedInfo.addDocument(this._baseURI, referenceURI, null, 728 Constants.ALGO_ID_DIGEST_SHA1, null, null); 729 } 730 731 /** 732 * Add an X509 Certificate to the KeyInfo. This will include the whole cert 733 * inside X509Data/X509Certificate tags. 734 * 735 * @param cert Certificate to be included. This should be the certificate of the key that was used to sign. 736 * @throws XMLSecurityException 737 */ 738 public void addKeyInfo(X509Certificate cert) throws XMLSecurityException { 739 740 X509Data x509data = new X509Data(this._doc); 741 742 x509data.addCertificate(cert); 743 this.getKeyInfo().add(x509data); 744 } 745 746 /** 747 * Add this public key to the KeyInfo. This will include the complete key in 748 * the KeyInfo structure. 749 * 750 * @param pk 751 */ 752 public void addKeyInfo(PublicKey pk) { 753 this.getKeyInfo().add(pk); 754 } 755 756 /** 757 * Proxy method for {@link SignedInfo#createSecretKey(byte[])}. If you want to 758 * create a MAC, this method helps you to obtain the {@link javax.crypto.SecretKey} 759 * from octets. 760 * 761 * @param secretKeyBytes 762 * @return the secret key created. 763 * @see SignedInfo#createSecretKey(byte[]) 764 */ 765 public SecretKey createSecretKey(byte[] secretKeyBytes) 766 { 767 return this.getSignedInfo().createSecretKey(secretKeyBytes); 768 } 769 770 /** 771 * Signal wether Manifest should be automatically validated. 772 * Checking the digests in References in a Signature are mandatory, but for 773 * References inside a Manifest it is application specific. This boolean is 774 * to indicate that the References inside Manifests should be validated. 775 * 776 * @param followManifests 777 * @see <a href="http://www.w3.org/TR/xmldsig-core/#sec-CoreValidation">Core validation section in the XML Signature Rec.</a> 778 */ 779 public void setFollowNestedManifests(boolean followManifests) { 780 this._followManifestsDuringValidation = followManifests; 781 } 782 783 /** 784 * Get the local name of this element 785 * 786 * @return Constant._TAG_SIGNATURE 787 */ 788 public String getBaseLocalName() { 789 return Constants._TAG_SIGNATURE; 790 } 791 }