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