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