View Javadoc
1 package com.sun.ebxml.registry.security; 2 3 import com.sun.ebxml.registry.*; 4 5 import java.io.*; 6 import java.security.*; 7 import java.security.cert.*; 8 import java.util.*; 9 10 // jaxm 11 import javax.xml.soap.SOAPMessage; 12 import javax.xml.soap.SOAPException; 13 14 // java mail 15 import javax.mail.internet.ParseException; 16 import javax.mail.internet.MimeMultipart; 17 import javax.mail.BodyPart; 18 import javax.mail.MessagingException; 19 20 // jaxp 21 import javax.xml.parsers.ParserConfigurationException; 22 import org.xml.sax.InputSource; 23 import org.xml.sax.SAXException; 24 import org.w3c.dom.*; 25 26 import org.apache.xpath.XPathAPI; 27 28 // XML security 29 import org.apache.xml.security.algorithms.MessageDigestAlgorithm; 30 import org.apache.xml.security.c14n.*; 31 import org.apache.xml.security.exceptions.XMLSecurityException; 32 import org.apache.xml.security.signature.*; 33 import org.apache.xml.security.keys.*; 34 import org.apache.xml.security.keys.content.*; 35 import org.apache.xml.security.keys.content.x509.*; 36 import org.apache.xml.security.keys.keyresolver.*; 37 import org.apache.xml.security.keys.storage.*; 38 import org.apache.xml.security.keys.storage.implementations.*; 39 import org.apache.xml.security.utils.*; 40 import org.apache.xml.security.transforms.*; 41 import org.apache.xml.security.Init; 42 import org.apache.xml.security.utils.resolver.implementations.ResolverFragment; 43 import org.apache.xml.security.utils.resolver.ResourceResolver; 44 import org.apache.xml.serialize.*; 45 46 // xerces 47 import org.apache.xml.serialize.OutputFormat; 48 import org.apache.xml.serialize.XMLSerializer; 49 import org.apache.xml.serialize.LineSeparator; 50 51 import com.sun.ebxml.registry.util.Utility; 52 53 import org.apache.commons.logging.*; 54 55 import com.sun.ebxml.registry.util.*; 56 57 /*** 58 * 59 * Some utility methods related to XML security 60 * 61 * $Header: /cvsroot/ebxmlrr/ebxmlrr/src/share/com/sun/ebxml/registry/security/SecurityUtil.java,v 1.19 2002/11/29 12:34:55 farrukh_najmi Exp $ 62 * 63 */ 64 public class SecurityUtil { 65 private org.apache.commons.logging.Log log = LogFactory.getLog(this.getClass()); 66 67 static { 68 org.apache.xml.security.Init.init(); 69 } 70 71 protected SecurityUtil() {} 72 73 /*** 74 * Sign the SOAP messasge 75 * @param soapStream is the InputStream to String representation of the SOAPMessage 76 * @param signedSoapStream is the OutputStream for signed SOAPMessage of String representation 77 * @param certs the certificate chain for verifying the signature 78 */ 79 public void signSOAPMessage(InputStream soapStream, OutputStream signedSoapStream, PrivateKey privateKey, 80 java.security.cert.Certificate [] certs, String signatureAlgo) throws RegistryException { 81 try { 82 83 //FileWriter fw = new FileWriter("sign_log.txt", true); 84 log.info("Enter signSOAPMessage at: " + System.currentTimeMillis()); 85 86 //long begin = System.currentTimeMillis(); 87 88 89 90 // Firstly get the Document form of the SOAPMessage - Should we pool the DocumentBuilder?????????? 91 javax.xml.parsers.DocumentBuilderFactory dbf = javax.xml.parsers.DocumentBuilderFactory.newInstance(); 92 dbf.setNamespaceAware(true); 93 javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder(); 94 95 //StringBuffer buf = Utility.getInstance().getStringBufferFromInputStream(soapStream); 96 //System.err.println(buf); 97 Document soapDoc = db.parse(new InputSource(soapStream)); 98 99 // Append the signature element to proper location before signing 100 Element headerElement = (Element) soapDoc.getDocumentElement().getElementsByTagNameNS( 101 "http://schemas.xmlsoap.org/soap/envelope/", "Header").item(0); 102 String baseURI = ""; 103 if (!signatureAlgo.equals(XMLSignature.ALGO_ID_SIGNATURE_DSA) && !signatureAlgo.equals(XMLSignature.ALGO_ID_SIGNATURE_RSA )) { 104 throw new RegistryException("Unsupported signature algorithm"); 105 } 106 XMLSignature sig = new XMLSignature(soapDoc, baseURI, signatureAlgo); 107 headerElement.appendChild(sig.getElement()); 108 109 // Start signing here 110 111 /* 112 // Due to the bug in the Apache security lib, it does not allow us to sign whole message and make "enveloped-signature" transform. 113 // It is mandatory requirement but the version we are using yields much better performance. 114 sig.getSignedInfo().addResourceResolver(new ResolverFragment()); 115 Transforms transforms = new Transforms(soapDoc); 116 transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE); 117 // Sign whole message 118 sig.addDocument("", transforms, Constants.ALGO_ID_DIGEST_SHA1); 119 */ 120 121 // only sign the body - IT IS NOT CONFORMED TO THE SPEC!!!!!! 122 sig.addDocument("#Body"); 123 // attach the certs chain 124 for (int i=0; i < certs.length; i++) { 125 sig.addKeyInfo((X509Certificate)certs[i]); 126 } 127 sig.addKeyInfo(((X509Certificate)certs[0]).getPublicKey()); 128 sig.sign(privateKey); 129 130 // Get back SOAPMessage form of the signed message 131 XMLUtils.outputDOMc14nWithComments(soapDoc, signedSoapStream); 132 log.info("Leaving signSOAPMessage at: " + System.currentTimeMillis()); 133 134 //long finish = System.currentTimeMillis(); 135 136 //fw.write("Signing takes " + (finish - begin) / 1000 / 60 + " mins\n"); 137 //fw.flush(); 138 //fw.close(); 139 140 } 141 catch (IOException e) { 142 throw new RegistryException(e); 143 } 144 catch (SAXException e) { 145 throw new RegistryException(e); 146 } 147 catch (ParserConfigurationException e) { 148 throw new RegistryException(e); 149 } 150 catch (XMLSecurityException e) { 151 throw new RegistryException(e); 152 } 153 154 } 155 156 /*** 157 * Sign the payload, and the payload signature is put in the destination 158 * connected by the payloadSigStream parameter. 159 * @param mimeMultipart a MimeMultipart containing a MimeBodyPart, which contains 160 * the payload to be signed. The MimeBodyPart should have content id "payload2". 161 * @param payloadSigStream the destination connected by this OutputStream contains 162 * the payload signature 163 */ 164 public void signPayload(MimeMultipart mp, String id, OutputStream payloadSigStream, 165 PrivateKey privateKey, java.security.cert.Certificate cert, String signingAlgo) throws RegistryException { 166 167 try { 168 if (mp.getCount() != 1) { 169 throw new RegistryException("Cannot sign the payload. The MimeMultipart should have only one MimeBodyPart with content id 'payload2'"); 170 } 171 if (mp.getBodyPart("payload2")==null) { 172 throw new RegistryException("Cannot sign the payload. The MimeBodyPart contained in the MimeMultipart should have content id 'payload2'"); 173 } 174 javax.xml.parsers.DocumentBuilderFactory dbf = javax.xml.parsers.DocumentBuilderFactory.newInstance(); 175 dbf.setNamespaceAware(true); 176 javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder(); 177 // org.w3c.dom.Document sigDoc = db.parse(new InputSource(new StringReader(sigText))); 178 org.w3c.dom.Document sigDoc = db.newDocument(); 179 180 // Append the signature element to proper location before signing 181 String baseURI = ""; 182 if (!signingAlgo.equals(XMLSignature.ALGO_ID_SIGNATURE_DSA) && !signingAlgo.equals(XMLSignature.ALGO_ID_SIGNATURE_RSA )) { 183 throw new RegistryException("Unsupported signature algorithm"); 184 } 185 XMLSignature sig = new XMLSignature(sigDoc, baseURI, signingAlgo); 186 // sigDoc.getDocumentElement().appendChild(sig.getElement()); 187 sigDoc.appendChild(sig.getElement()); 188 189 // here we only add the target cert of the cert chain 190 sig.addKeyInfo((X509Certificate)cert); 191 sig.addKeyInfo(((X509Certificate)cert).getPublicKey()); 192 193 ResourceResolver resolver = new ResourceResolver(new PayloadResolver(mp, id)); 194 //resolver.register("org.apache.xml.security.utils.resolver.implementations.ResolverLocalFilesystem"); 195 sig.addResourceResolver(resolver); 196 197 //sig.addDocument("file:///" + fileName); 198 sig.addDocument("payload2"); 199 200 sig.sign(privateKey); 201 202 // FileOutputStream payloadSigStream = new FileOutputStream("payloadSig.xml"); 203 XMLUtils.outputDOMc14nWithComments(sigDoc, payloadSigStream); 204 payloadSigStream.flush(); 205 payloadSigStream.close(); 206 } 207 catch(IOException e) { 208 throw new RegistryException("Cannot sign the payload", e); 209 } 210 catch(ParserConfigurationException e) { 211 throw new RegistryException("Cannot sign the payload", e); 212 } 213 catch(MessagingException e) { 214 throw new RegistryException("Cannot sign the payload", e); 215 } 216 catch(XMLSecurityException e) { 217 throw new RegistryException("Cannot sign the payload", e); 218 } 219 220 } 221 222 public XMLSignature verifySOAPMessage(SOAPMessage msg) throws RegistryException { 223 XMLSignature signature = null; 224 225 try { 226 //long begin = System.currentTimeMillis(); 227 //FileWriter fw = new FileWriter("sign_log.txt", true); 228 log.info("Entering verifySOAPMessage at: " + System.currentTimeMillis()); 229 230 // Get the Document form of the SOAPMessage 231 ByteArrayOutputStream msgOutStream = new ByteArrayOutputStream(); 232 msg.writeTo(msgOutStream); 233 ByteArrayInputStream msgInStream = new ByteArrayInputStream(msgOutStream.toByteArray()); 234 javax.xml.parsers.DocumentBuilderFactory dbf = javax.xml.parsers.DocumentBuilderFactory.newInstance(); 235 dbf.setNamespaceAware(true); 236 dbf.setAttribute("http://xml.org/sax/features/namespaces", Boolean.TRUE); 237 javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder(); 238 db.setErrorHandler(new org.apache.xml.security.utils.IgnoreAllErrorHandler()); 239 org.w3c.dom.Document doc = db.parse(new InputSource(msgInStream)); 240 241 // Get the signature 242 Element headerElement = (Element) doc.getDocumentElement().getElementsByTagNameNS( 243 "http://schemas.xmlsoap.org/soap/envelope/", "Header").item(0); 244 if (headerElement == null) { 245 throw new RegistryException("Missing SOAP Header"); 246 } 247 Element sigElement = (Element) headerElement.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", "Signature"). 248 item(0); 249 250 if (sigElement != null) { 251 signature = new XMLSignature(sigElement, ""); 252 signature.addResourceResolver(new ResolverFragment()); 253 if (!verifyXMLSignature(signature)) { 254 handleHeaderVerificationException(new RegistryException("Invalid signature. The message is tampered with in transit.")); 255 } 256 } 257 log.info("Leaving verifySOAPMessage at: " + System.currentTimeMillis()); 258 259 //long finish = System.currentTimeMillis(); 260 //fw.write("verification takes " + (finish - begin) / 1000 / 60 + " mins\n"); 261 //fw.flush(); 262 //fw.close(); 263 } 264 catch (Exception e) { 265 handleHeaderVerificationException(e); 266 } 267 268 return signature; 269 } 270 271 private void handleHeaderVerificationException(Exception e) throws RegistryException { 272 boolean ignoreInvalidHeaderSignatures = Boolean.valueOf(RegistryProperties.getInstance().getProperty("ebxmlrr.security.ignoreInvalidHeaderSignatures")).booleanValue(); 273 if (ignoreInvalidHeaderSignatures) { 274 log.error("Invalid header signature. The message is tampered with in transit." + e.toString()); 275 } 276 else { 277 throw new RegistryException("Invalid header signature. The message is tampered with in transit.", e); 278 } 279 } 280 281 /*** 282 * It expects the XMLSignature has been add ResourceResolver appropriately 283 */ 284 protected boolean verifyXMLSignature(XMLSignature signature) throws RegistryException, KeyResolverException, Exception { 285 286 KeyInfo ki = signature.getKeyInfo(); 287 288 if (ki != null) { 289 if (!ki.containsX509Data()) { 290 throw new RegistryException("Missing X509Data element in the KeyInfo element"); 291 } 292 X509Certificate cert = signature.getKeyInfo().getX509Certificate(); 293 if (cert != null) { 294 return signature.checkSignatureValue(cert); 295 } 296 else { 297 throw new RegistryException("Missing X509Certificate element in Signature element"); 298 } 299 } 300 else { 301 throw new RegistryException("Missing KeyIno element in Signature element"); 302 } 303 } 304 305 public boolean verifyPayloadSignature(String id, MimeMultipart multipart) throws RegistryException { 306 boolean isValid = false; 307 try { 308 if (multipart.getCount() != 2) { 309 throw new RegistryException("Cannot verify the payload signature. The MimeMultipart should have two MimeBodyPart"); 310 } 311 BodyPart signaturePart = multipart.getBodyPart("payload1"); 312 if (signaturePart == null) { 313 throw new RegistryException("Cannot verify the payload signature. The MimeMultipart does not have MimeBodyPart with content id 'payload1'"); 314 } 315 BodyPart payloadPart = multipart.getBodyPart("payload2"); 316 if (payloadPart == null) { 317 throw new RegistryException("Cannot verify the payload signature. The MimeMultipart does not have MimeBodyPart with content id 'payload2'"); 318 } 319 320 javax.xml.parsers.DocumentBuilderFactory dbf = javax.xml.parsers.DocumentBuilderFactory.newInstance(); 321 dbf.setNamespaceAware(true); 322 javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder(); 323 org.w3c.dom.Document sigDoc = db.parse(new InputSource(signaturePart.getInputStream())); 324 XMLSignature signature = new XMLSignature(sigDoc.getDocumentElement(), ""); 325 signature.addResourceResolver(new PayloadResolver(multipart, id)); 326 isValid = verifyXMLSignature(signature); 327 328 if (!isValid) { 329 boolean ignoreInvalidPayloadSignatures = Boolean.valueOf(RegistryProperties.getInstance().getProperty("ebxmlrr.security.ignoreInvalidPayloadSignatures")).booleanValue(); 330 if (ignoreInvalidPayloadSignatures) { 331 isValid = true; 332 } 333 } 334 } 335 catch(IOException e) { 336 handlePayloadVerificationException(e); 337 } 338 catch(SAXException e) { 339 handlePayloadVerificationException(e); 340 } 341 catch(MessagingException e) { 342 handlePayloadVerificationException(e); 343 } 344 catch(ParserConfigurationException e) { 345 handlePayloadVerificationException(e); 346 } 347 catch(XMLSignatureException e) { 348 handlePayloadVerificationException(e); 349 } 350 catch(KeyResolverException e) { 351 handlePayloadVerificationException(e); 352 } 353 catch(XMLSecurityException e) { 354 handlePayloadVerificationException(e); 355 } 356 catch(Exception e) { 357 handlePayloadVerificationException(e); 358 } 359 360 return isValid; 361 } 362 363 private void handlePayloadVerificationException(Exception e) throws RegistryException { 364 boolean ignoreInvalidPayloadSignatures = Boolean.valueOf(RegistryProperties.getInstance().getProperty("ebxmlrr.security.ignoreInvalidPayloadSignatures")).booleanValue(); 365 if (ignoreInvalidPayloadSignatures) { 366 log.error("Cannot verify the payload signature. " + e.toString()); 367 } 368 else { 369 throw new RegistryException("Cannot verify the payload signature", e); 370 } 371 } 372 373 /*** 374 * Method main 375 * 376 * @param unused 377 * @throws Exception 378 */ 379 public static void main(String unused[]) throws Exception { 380 } 381 382 public static SecurityUtil getInstance() { 383 if (instance == null) { 384 synchronized (SecurityUtil.class) { 385 if (instance == null) { 386 instance = new SecurityUtil(); 387 } 388 } 389 } 390 return instance; 391 } 392 393 /*** 394 * @link 395 * @shapeType PatternLink 396 * @pattern Singleton 397 * @supplierRole Singleton factory 398 */ 399 400 /* # private SecurityUtil _utility; */ 401 private static SecurityUtil instance = null; 402 403 }

This page was automatically generated by Maven