1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Copyright 2005 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 /* 22 * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. 23 */ 24 /* 25 * $Id: DOMSignedInfo.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ 26 */ 27 package org.jcp.xml.dsig.internal.dom; 28 29 import javax.xml.crypto.*; 30 import javax.xml.crypto.dom.DOMCryptoContext; 31 import javax.xml.crypto.dsig.*; 32 33 import java.io.ByteArrayInputStream; 34 import java.io.ByteArrayOutputStream; 35 import java.io.InputStream; 36 import java.io.IOException; 37 import java.io.InputStreamReader; 38 import java.io.OutputStream; 39 import java.security.Provider; 40 import java.util.*; 41 import java.util.logging.Level; 42 import java.util.logging.Logger; 43 import org.w3c.dom.Document; 44 import org.w3c.dom.Element; 45 import org.w3c.dom.Node; 46 47 import com.sun.org.apache.xml.internal.security.utils.Base64; 48 import com.sun.org.apache.xml.internal.security.utils.Constants; 49 import com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream; 50 import com.sun.org.apache.xml.internal.security.utils.XMLUtils; 51 52 /** 53 * DOM-based implementation of SignedInfo. 54 * 55 * @author Sean Mullan 56 */ 57 public final class DOMSignedInfo extends DOMStructure implements SignedInfo { 58 59 /** 60 * The maximum number of references per Manifest, if secure validation is 61 * enabled. 62 */ 63 public static final int MAXIMUM_REFERENCE_COUNT = 30; 64 65 private static Logger log = Logger.getLogger("org.jcp.xml.dsig.internal.dom"); 66 67 /** Signature - NOT Recommended RSAwithMD5 */ 68 private static final String ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5 = 69 Constants.MoreAlgorithmsSpecNS + "rsa-md5"; 70 71 /** HMAC - NOT Recommended HMAC-MD5 */ 72 private static final String ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5 = 73 Constants.MoreAlgorithmsSpecNS + "hmac-md5"; 74 75 private List references; 76 private CanonicalizationMethod canonicalizationMethod; 77 private SignatureMethod signatureMethod; 78 private String id; 79 private Document ownerDoc; 80 private Element localSiElem; 81 private InputStream canonData; 82 83 /** 84 * Creates a <code>DOMSignedInfo</code> from the specified parameters. Use 85 * this constructor when the <code>Id</code> is not specified. 86 * 87 * @param cm the canonicalization method 88 * @param sm the signature method 89 * @param references the list of references. The list is copied. 90 * @throws NullPointerException if 91 * <code>cm</code>, <code>sm</code>, or <code>references</code> is 92 * <code>null</code> 93 * @throws IllegalArgumentException if <code>references</code> is empty 94 * @throws ClassCastException if any of the references are not of 95 * type <code>Reference</code> 96 */ 97 public DOMSignedInfo(CanonicalizationMethod cm, SignatureMethod sm, 98 List references) { 99 if (cm == null || sm == null || references == null) { 100 throw new NullPointerException(); 101 } 102 this.canonicalizationMethod = cm; 103 this.signatureMethod = sm; 104 this.references = Collections.unmodifiableList 105 (new ArrayList(references)); 106 if (this.references.isEmpty()) { 107 throw new IllegalArgumentException("list of references must " + 108 "contain at least one entry"); 109 } 110 for (int i = 0, size = this.references.size(); i < size; i++) { 111 Object obj = this.references.get(i); 112 if (!(obj instanceof Reference)) { 113 throw new ClassCastException("list of references contains " + 114 "an illegal type"); 115 } 116 } 117 } 118 119 /** 120 * Creates a <code>DOMSignedInfo</code> from the specified parameters. 121 * 122 * @param cm the canonicalization method 123 * @param sm the signature method 124 * @param references the list of references. The list is copied. 125 * @param id an optional identifer that will allow this 126 * <code>SignedInfo</code> to be referenced by other signatures and 127 * objects 128 * @throws NullPointerException if <code>cm</code>, <code>sm</code>, 129 * or <code>references</code> is <code>null</code> 130 * @throws IllegalArgumentException if <code>references</code> is empty 131 * @throws ClassCastException if any of the references are not of 132 * type <code>Reference</code> 133 */ 134 public DOMSignedInfo(CanonicalizationMethod cm, SignatureMethod sm, 135 List references, String id) { 136 this(cm, sm, references); 137 this.id = id; 138 } 139 140 /** 141 * Creates a <code>DOMSignedInfo</code> from an element. 142 * 143 * @param siElem a SignedInfo element 144 */ 145 public DOMSignedInfo(Element siElem, XMLCryptoContext context, 146 Provider provider) throws MarshalException { 147 localSiElem = siElem; 148 ownerDoc = siElem.getOwnerDocument(); 149 150 // get Id attribute, if specified 151 id = DOMUtils.getAttributeValue(siElem, "Id"); 152 153 // unmarshal CanonicalizationMethod 154 Element cmElem = DOMUtils.getFirstChildElement(siElem); 155 canonicalizationMethod = new DOMCanonicalizationMethod 156 (cmElem, context, provider); 157 158 // unmarshal SignatureMethod 159 Element smElem = DOMUtils.getNextSiblingElement(cmElem); 160 signatureMethod = DOMSignatureMethod.unmarshal(smElem); 161 162 boolean secVal = Utils.secureValidation(context); 163 String sigMethAlg = signatureMethod.getAlgorithm(); 164 if (secVal && ((ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5.equals(sigMethAlg) 165 || ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5.equals(sigMethAlg)))) 166 { 167 throw new MarshalException("It is forbidden to use algorithm " + 168 signatureMethod + 169 " when secure validation is enabled"); 170 } 171 172 // unmarshal References 173 ArrayList refList = new ArrayList(5); 174 Element refElem = DOMUtils.getNextSiblingElement(smElem); 175 int refCount = 0; 176 while (refElem != null) { 177 refList.add(new DOMReference(refElem, context, provider)); 178 refElem = DOMUtils.getNextSiblingElement(refElem); 179 180 refCount++; 181 if (secVal && (refCount > MAXIMUM_REFERENCE_COUNT)) { 182 String error = "A maxiumum of " + MAXIMUM_REFERENCE_COUNT + 183 " references per SignedInfo are allowed with" + 184 " secure validation"; 185 throw new MarshalException(error); 186 } 187 } 188 references = Collections.unmodifiableList(refList); 189 } 190 191 public CanonicalizationMethod getCanonicalizationMethod() { 192 return canonicalizationMethod; 193 } 194 195 public SignatureMethod getSignatureMethod() { 196 return signatureMethod; 197 } 198 199 public String getId() { 200 return id; 201 } 202 203 public List getReferences() { 204 return references; 205 } 206 207 public InputStream getCanonicalizedData() { 208 return canonData; 209 } 210 211 public void canonicalize(XMLCryptoContext context,ByteArrayOutputStream bos) 212 throws XMLSignatureException { 213 214 if (context == null) { 215 throw new NullPointerException("context cannot be null"); 216 } 217 218 OutputStream os = new UnsyncBufferedOutputStream(bos); 219 try { 220 os.close(); 221 } catch (IOException e) { 222 // Impossible 223 } 224 225 DOMSubTreeData subTree = new DOMSubTreeData(localSiElem, true); 226 227 try { 228 Data data = ((DOMCanonicalizationMethod) 229 canonicalizationMethod).canonicalize(subTree, context, os); 230 } catch (TransformException te) { 231 throw new XMLSignatureException(te); 232 } 233 234 byte[] signedInfoBytes = bos.toByteArray(); 235 236 // this whole block should only be done if logging is enabled 237 if (log.isLoggable(Level.FINE)) { 238 InputStreamReader isr = new InputStreamReader 239 (new ByteArrayInputStream(signedInfoBytes)); 240 char[] siBytes = new char[signedInfoBytes.length]; 241 try { 242 isr.read(siBytes); 243 log.log(Level.FINE, "Canonicalized SignedInfo:\n" 244 + new String(siBytes)); 245 } catch (IOException ioex) { 246 log.log(Level.FINE, "IOException reading SignedInfo bytes"); 247 } 248 log.log(Level.FINE, "Data to be signed/verified:" 249 + Base64.encode(signedInfoBytes)); 250 } 251 252 this.canonData = new ByteArrayInputStream(signedInfoBytes); 253 } 254 255 public void marshal(Node parent, String dsPrefix, DOMCryptoContext context) 256 throws MarshalException { 257 ownerDoc = DOMUtils.getOwnerDocument(parent); 258 259 Element siElem = DOMUtils.createElement 260 (ownerDoc, "SignedInfo", XMLSignature.XMLNS, dsPrefix); 261 262 // create and append CanonicalizationMethod element 263 DOMCanonicalizationMethod dcm = 264 (DOMCanonicalizationMethod) canonicalizationMethod; 265 dcm.marshal(siElem, dsPrefix, context); 266 267 // create and append SignatureMethod element 268 ((DOMSignatureMethod) signatureMethod).marshal 269 (siElem, dsPrefix, context); 270 271 // create and append Reference elements 272 for (int i = 0, size = references.size(); i < size; i++) { 273 DOMReference reference = (DOMReference) references.get(i); 274 reference.marshal(siElem, dsPrefix, context); 275 } 276 277 // append Id attribute 278 DOMUtils.setAttributeID(siElem, "Id", id); 279 280 parent.appendChild(siElem); 281 localSiElem = siElem; 282 } 283 284 public boolean equals(Object o) { 285 if (this == o) { 286 return true; 287 } 288 289 if (!(o instanceof SignedInfo)) { 290 return false; 291 } 292 SignedInfo osi = (SignedInfo) o; 293 294 boolean idEqual = (id == null ? osi.getId() == null : 295 id.equals(osi.getId())); 296 297 return (canonicalizationMethod.equals(osi.getCanonicalizationMethod()) 298 && signatureMethod.equals(osi.getSignatureMethod()) && 299 references.equals(osi.getReferences()) && idEqual); 300 } 301 } | 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 /* 24 * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. 25 */ 26 /* 27 * $Id: DOMSignedInfo.java 1333415 2012-05-03 12:03:51Z coheigea $ 28 */ 29 package org.jcp.xml.dsig.internal.dom; 30 31 import javax.xml.crypto.*; 32 import javax.xml.crypto.dom.DOMCryptoContext; 33 import javax.xml.crypto.dsig.*; 34 35 import java.io.ByteArrayInputStream; 36 import java.io.ByteArrayOutputStream; 37 import java.io.InputStream; 38 import java.io.OutputStream; 39 import java.io.IOException; 40 import java.security.Provider; 41 import java.util.*; 42 43 import org.w3c.dom.Document; 44 import org.w3c.dom.Element; 45 import org.w3c.dom.Node; 46 47 import com.sun.org.apache.xml.internal.security.utils.Base64; 48 import com.sun.org.apache.xml.internal.security.utils.Constants; 49 import com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream; 50 51 /** 52 * DOM-based implementation of SignedInfo. 53 * 54 * @author Sean Mullan 55 */ 56 public final class DOMSignedInfo extends DOMStructure implements SignedInfo { 57 58 /** 59 * The maximum number of references per Manifest, if secure validation is enabled. 60 */ 61 public static final int MAXIMUM_REFERENCE_COUNT = 30; 62 63 private static java.util.logging.Logger log = 64 java.util.logging.Logger.getLogger("org.jcp.xml.dsig.internal.dom"); 65 66 /** Signature - NOT Recommended RSAwithMD5 */ 67 private static final String ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5 = 68 Constants.MoreAlgorithmsSpecNS + "rsa-md5"; 69 70 /** HMAC - NOT Recommended HMAC-MD5 */ 71 private static final String ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5 = 72 Constants.MoreAlgorithmsSpecNS + "hmac-md5"; 73 74 private List<Reference> references; 75 private CanonicalizationMethod canonicalizationMethod; 76 private SignatureMethod signatureMethod; 77 private String id; 78 private Document ownerDoc; 79 private Element localSiElem; 80 private InputStream canonData; 81 82 /** 83 * Creates a <code>DOMSignedInfo</code> from the specified parameters. Use 84 * this constructor when the <code>Id</code> is not specified. 85 * 86 * @param cm the canonicalization method 87 * @param sm the signature method 88 * @param references the list of references. The list is copied. 89 * @throws NullPointerException if 90 * <code>cm</code>, <code>sm</code>, or <code>references</code> is 91 * <code>null</code> 92 * @throws IllegalArgumentException if <code>references</code> is empty 93 * @throws ClassCastException if any of the references are not of 94 * type <code>Reference</code> 95 */ 96 public DOMSignedInfo(CanonicalizationMethod cm, SignatureMethod sm, 97 List<? extends Reference> references) { 98 if (cm == null || sm == null || references == null) { 99 throw new NullPointerException(); 100 } 101 this.canonicalizationMethod = cm; 102 this.signatureMethod = sm; 103 this.references = Collections.unmodifiableList( 104 new ArrayList<Reference>(references)); 105 if (this.references.isEmpty()) { 106 throw new IllegalArgumentException("list of references must " + 107 "contain at least one entry"); 108 } 109 for (int i = 0, size = this.references.size(); i < size; i++) { 110 Object obj = this.references.get(i); 111 if (!(obj instanceof Reference)) { 112 throw new ClassCastException("list of references contains " + 113 "an illegal type"); 114 } 115 } 116 } 117 118 /** 119 * Creates a <code>DOMSignedInfo</code> from the specified parameters. 120 * 121 * @param cm the canonicalization method 122 * @param sm the signature method 123 * @param references the list of references. The list is copied. 124 * @param id an optional identifer that will allow this 125 * <code>SignedInfo</code> to be referenced by other signatures and 126 * objects 127 * @throws NullPointerException if <code>cm</code>, <code>sm</code>, 128 * or <code>references</code> is <code>null</code> 129 * @throws IllegalArgumentException if <code>references</code> is empty 130 * @throws ClassCastException if any of the references are not of 131 * type <code>Reference</code> 132 */ 133 public DOMSignedInfo(CanonicalizationMethod cm, SignatureMethod sm, 134 List<? extends Reference> references, String id) { 135 this(cm, sm, references); 136 this.id = id; 137 } 138 139 /** 140 * Creates a <code>DOMSignedInfo</code> from an element. 141 * 142 * @param siElem a SignedInfo element 143 */ 144 public DOMSignedInfo(Element siElem, XMLCryptoContext context, Provider provider) 145 throws MarshalException { 146 localSiElem = siElem; 147 ownerDoc = siElem.getOwnerDocument(); 148 149 // get Id attribute, if specified 150 id = DOMUtils.getAttributeValue(siElem, "Id"); 151 152 // unmarshal CanonicalizationMethod 153 Element cmElem = DOMUtils.getFirstChildElement(siElem); 154 canonicalizationMethod = new DOMCanonicalizationMethod(cmElem, context, provider); 155 156 // unmarshal SignatureMethod 157 Element smElem = DOMUtils.getNextSiblingElement(cmElem); 158 signatureMethod = DOMSignatureMethod.unmarshal(smElem); 159 160 boolean secVal = Utils.secureValidation(context); 161 162 String signatureMethodAlgorithm = signatureMethod.getAlgorithm(); 163 if (secVal && ((ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5.equals(signatureMethodAlgorithm) 164 || ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5.equals(signatureMethodAlgorithm)))) { 165 throw new MarshalException( 166 "It is forbidden to use algorithm " + signatureMethod + " when secure validation is enabled" 167 ); 168 } 169 170 // unmarshal References 171 ArrayList<Reference> refList = new ArrayList<Reference>(5); 172 Element refElem = DOMUtils.getNextSiblingElement(smElem); 173 174 int refCount = 0; 175 while (refElem != null) { 176 refList.add(new DOMReference(refElem, context, provider)); 177 refElem = DOMUtils.getNextSiblingElement(refElem); 178 179 refCount++; 180 if (secVal && (refCount > MAXIMUM_REFERENCE_COUNT)) { 181 String error = "A maxiumum of " + MAXIMUM_REFERENCE_COUNT + " " 182 + "references per Manifest are allowed with secure validation"; 183 throw new MarshalException(error); 184 } 185 } 186 references = Collections.unmodifiableList(refList); 187 } 188 189 public CanonicalizationMethod getCanonicalizationMethod() { 190 return canonicalizationMethod; 191 } 192 193 public SignatureMethod getSignatureMethod() { 194 return signatureMethod; 195 } 196 197 public String getId() { 198 return id; 199 } 200 201 public List getReferences() { 202 return references; 203 } 204 205 public InputStream getCanonicalizedData() { 206 return canonData; 207 } 208 209 public void canonicalize(XMLCryptoContext context, ByteArrayOutputStream bos) 210 throws XMLSignatureException { 211 if (context == null) { 212 throw new NullPointerException("context cannot be null"); 213 } 214 215 OutputStream os = new UnsyncBufferedOutputStream(bos); 216 try { 217 os.close(); 218 } catch (IOException e) { 219 if (log.isLoggable(java.util.logging.Level.FINE)) { 220 log.log(java.util.logging.Level.FINE, e.getMessage(), e); 221 } 222 // Impossible 223 } 224 225 DOMSubTreeData subTree = new DOMSubTreeData(localSiElem, true); 226 227 try { 228 ((DOMCanonicalizationMethod) 229 canonicalizationMethod).canonicalize(subTree, context, bos); 230 } catch (TransformException te) { 231 throw new XMLSignatureException(te); 232 } 233 234 byte[] signedInfoBytes = bos.toByteArray(); 235 236 // this whole block should only be done if logging is enabled 237 if (log.isLoggable(java.util.logging.Level.FINE)) { 238 log.log(java.util.logging.Level.FINE, "Canonicalized SignedInfo:"); 239 StringBuilder sb = new StringBuilder(signedInfoBytes.length); 240 for (int i = 0; i < signedInfoBytes.length; i++) { 241 sb.append((char)signedInfoBytes[i]); 242 } 243 log.log(java.util.logging.Level.FINE, sb.toString()); 244 log.log(java.util.logging.Level.FINE, "Data to be signed/verified:" + Base64.encode(signedInfoBytes)); 245 } 246 247 this.canonData = new ByteArrayInputStream(signedInfoBytes); 248 } 249 250 public void marshal(Node parent, String dsPrefix, DOMCryptoContext context) 251 throws MarshalException 252 { 253 ownerDoc = DOMUtils.getOwnerDocument(parent); 254 Element siElem = DOMUtils.createElement(ownerDoc, "SignedInfo", 255 XMLSignature.XMLNS, dsPrefix); 256 257 // create and append CanonicalizationMethod element 258 DOMCanonicalizationMethod dcm = 259 (DOMCanonicalizationMethod)canonicalizationMethod; 260 dcm.marshal(siElem, dsPrefix, context); 261 262 // create and append SignatureMethod element 263 ((DOMStructure)signatureMethod).marshal(siElem, dsPrefix, context); 264 265 // create and append Reference elements 266 for (Reference reference : references) { 267 ((DOMReference)reference).marshal(siElem, dsPrefix, context); 268 } 269 270 // append Id attribute 271 DOMUtils.setAttributeID(siElem, "Id", id); 272 273 parent.appendChild(siElem); 274 localSiElem = siElem; 275 } 276 277 @Override 278 public boolean equals(Object o) { 279 if (this == o) { 280 return true; 281 } 282 283 if (!(o instanceof SignedInfo)) { 284 return false; 285 } 286 SignedInfo osi = (SignedInfo)o; 287 288 boolean idEqual = (id == null ? osi.getId() == null 289 : id.equals(osi.getId())); 290 291 return (canonicalizationMethod.equals(osi.getCanonicalizationMethod()) 292 && signatureMethod.equals(osi.getSignatureMethod()) && 293 references.equals(osi.getReferences()) && idEqual); 294 } 295 296 @Override 297 public int hashCode() { 298 int result = 17; 299 if (id != null) { 300 result = 31 * result + id.hashCode(); 301 } 302 result = 31 * result + canonicalizationMethod.hashCode(); 303 result = 31 * result + signatureMethod.hashCode(); 304 result = 31 * result + references.hashCode(); 305 306 return result; 307 } 308 } |