001: /*
002: * The contents of this file are subject to the terms
003: * of the Common Development and Distribution License
004: * (the License). You may not use this file except in
005: * compliance with the License.
006: *
007: * You can obtain a copy of the license at
008: * https://glassfish.dev.java.net/public/CDDLv1.0.html.
009: * See the License for the specific language governing
010: * permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL
013: * Header Notice in each file and include the License file
014: * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
015: * If applicable, add the following below the CDDL Header,
016: * with the fields enclosed by brackets [] replaced by
017: * you own identifying information:
018: * "Portions Copyrighted [year] [name of copyright owner]"
019: *
020: * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
021: */
022:
023: package com.sun.xml.ws.security.opt.crypto.dsig;
024:
025: import com.sun.xml.ws.security.opt.impl.JAXBFilterProcessingContext;
026: import com.sun.xml.ws.security.opt.impl.util.NamespaceAndPrefixMapper;
027: import com.sun.xml.ws.security.opt.impl.util.WSSNamespacePrefixMapper;
028: import com.sun.xml.ws.security.opt.crypto.dsig.internal.HmacSHA1;
029: import com.sun.xml.wss.impl.MessageConstants;
030: import com.sun.xml.wss.impl.XWSSecurityRuntimeException;
031: import com.sun.xml.wss.impl.c14n.AttributeNS;
032: import com.sun.xml.wss.impl.c14n.EXC14nStAXReaderBasedCanonicalizer;
033: import com.sun.xml.wss.impl.c14n.StAXEXC14nCanonicalizerImpl;
034: import com.sun.xml.wss.logging.LogDomainConstants;
035: import java.io.ByteArrayOutputStream;
036: import java.io.IOException;
037: import java.security.InvalidKeyException;
038: import java.security.Key;
039: import java.security.NoSuchAlgorithmException;
040: import java.security.PrivateKey;
041: import java.security.PublicKey;
042: import java.security.Signature;
043: import java.security.SignatureException;
044: import java.util.ArrayList;
045: import java.util.List;
046: import java.util.logging.Level;
047: import java.util.logging.Logger;
048: import javax.xml.bind.JAXBContext;
049: import javax.xml.bind.JAXBException;
050: import javax.xml.bind.Marshaller;
051: import javax.xml.stream.XMLStreamException;
052: import com.sun.xml.ws.security.opt.crypto.dsig.internal.SignerOutputStream;
053: import com.sun.xml.ws.security.opt.crypto.dsig.internal.MacOutputStream;
054: import org.jvnet.staxex.NamespaceContextEx;
055: import org.jvnet.staxex.XMLStreamReaderEx;
056: import java.util.Iterator;
057: import javax.xml.crypto.XMLCryptoContext;
058: import com.sun.xml.wss.logging.impl.opt.signature.LogStringsMessages;
059:
060: /**
061: *
062: * @author K.Venugopal@sun.com
063: */
064: public class SignatureProcessor {
065: private static final Logger logger = Logger.getLogger(
066: LogDomainConstants.IMPL_OPT_SIGNATURE_DOMAIN,
067: LogDomainConstants.IMPL_OPT_SIGNATURE_DOMAIN_BUNDLE);
068:
069: private JAXBContext _jaxbContext;
070: StAXEXC14nCanonicalizerImpl _exc14nCanonicalizer = new StAXEXC14nCanonicalizerImpl();
071: EXC14nStAXReaderBasedCanonicalizer _exc14nSBCanonicalizer;
072: XMLCryptoContext context = null;
073: private Signature _rsaSignature;
074: private Signature _dsaSignature;
075:
076: //private Signature _hmacSignature;
077:
078: /**
079: * Creates a new instance of SignatureProcessor
080: */
081: public SignatureProcessor() {
082:
083: }
084:
085: public void setJAXBContext(JAXBContext _jaxbContext) {
086: this ._jaxbContext = _jaxbContext;
087: }
088:
089: public JAXBContext getJAXBContext() {
090: return _jaxbContext;
091: }
092:
093: public void setCryptoContext(XMLCryptoContext context) {
094: this .context = context;
095: }
096:
097: public byte[] performRSASign(Key privateKey, SignedInfo signedInfo)
098: throws InvalidKeyException {
099: if (privateKey == null || signedInfo == null) {
100: throw new NullPointerException();
101: }
102:
103: if (!(privateKey instanceof PrivateKey)) {
104: throw new InvalidKeyException("key must be PrivateKey");
105: }
106:
107: if (_rsaSignature == null) {
108: try {
109: _rsaSignature = Signature.getInstance("SHA1withRSA");
110: } catch (NoSuchAlgorithmException ex) {
111: // shud never come here
112: throw new XWSSecurityRuntimeException(ex);
113: }
114: }
115:
116: _rsaSignature.initSign((PrivateKey) privateKey);
117:
118: SignerOutputStream signerOutputStream = new SignerOutputStream(
119: _rsaSignature);
120: Marshaller marshaller;
121: try {
122: marshaller = getMarshaller();
123: _exc14nCanonicalizer.reset();
124:
125: setNamespaceAndPrefixList();
126:
127: _exc14nCanonicalizer.setStream(signerOutputStream);
128: marshaller.marshal(signedInfo, _exc14nCanonicalizer);
129: if (logger.isLoggable(Level.FINEST)) {
130: java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
131: _exc14nCanonicalizer.reset();
132: _exc14nCanonicalizer.setStream(baos);
133: marshaller.marshal(signedInfo, _exc14nCanonicalizer);
134: logger.log(Level.FINEST, LogStringsMessages
135: .WSS_1756_CANONICALIZED_SIGNEDINFO_VALUE(baos
136: .toString()));
137: }
138: } catch (JAXBException ex) {
139: throw new XWSSecurityRuntimeException(ex);
140: }
141:
142: try {
143: return _rsaSignature.sign();
144:
145: } catch (SignatureException se) {
146: // should never occur!
147: throw new RuntimeException(se.getMessage());
148: }
149: }
150:
151: public byte[] performHMACSign(Key key, SignedInfo signedInfo,
152: int outputLength) throws InvalidKeyException {
153:
154: if (key == null || signedInfo == null) {
155: throw new NullPointerException();
156: }
157: HmacSHA1 hmac = new HmacSHA1();
158: hmac.init(key, outputLength);
159:
160: MacOutputStream macOutputStream = new MacOutputStream(hmac);
161: Marshaller marshaller;
162: try {
163: marshaller = getMarshaller();
164: _exc14nCanonicalizer.reset();
165: setNamespaceAndPrefixList();
166: _exc14nCanonicalizer.setStream(macOutputStream);
167: marshaller.marshal(signedInfo, _exc14nCanonicalizer);
168: if (logger.isLoggable(Level.FINEST)) {
169: marshaller = getMarshaller();
170: _exc14nCanonicalizer.reset();
171: setNamespaceAndPrefixList();
172: ByteArrayOutputStream bos = new ByteArrayOutputStream();
173: _exc14nCanonicalizer.setStream(bos);
174: marshaller.marshal(signedInfo, _exc14nCanonicalizer);
175: logger.log(Level.FINEST, LogStringsMessages
176: .WSS_1756_CANONICALIZED_SIGNEDINFO_VALUE(bos
177: .toString()));
178: }
179: } catch (JAXBException ex) {
180: throw new XWSSecurityRuntimeException(ex);
181: }
182: try {
183: return hmac.sign();
184:
185: } catch (SignatureException se) {
186: // should never occur!
187: throw new RuntimeException(se.getMessage());
188: }
189: }
190:
191: public byte[] performDSASign(Key privateKey, SignedInfo signedInfo)
192: throws InvalidKeyException {
193: if (privateKey == null || signedInfo == null) {
194: throw new NullPointerException();
195: }
196:
197: if (!(privateKey instanceof PrivateKey)) {
198: throw new InvalidKeyException("key must be PrivateKey");
199: }
200:
201: if (_dsaSignature == null) {
202: try {
203: _dsaSignature = Signature.getInstance("SHA1withDSA");
204: } catch (NoSuchAlgorithmException ex) {
205: // shud never come here
206: throw new XWSSecurityRuntimeException(ex);
207: }
208: }
209:
210: _dsaSignature.initSign((PrivateKey) privateKey);
211:
212: SignerOutputStream signerOutputStream = new SignerOutputStream(
213: _dsaSignature);
214: Marshaller marshaller;
215: try {
216: marshaller = getMarshaller();
217: _exc14nCanonicalizer.reset();
218: setNamespaceAndPrefixList();
219: _exc14nCanonicalizer.setStream(signerOutputStream);
220: marshaller.marshal(signedInfo, _exc14nCanonicalizer);
221: } catch (JAXBException ex) {
222: throw new XWSSecurityRuntimeException(ex);
223: }
224:
225: try {
226: return convertASN1toXMLDSIG(_dsaSignature.sign());
227:
228: } catch (SignatureException se) {
229: // should never occur!
230: throw new RuntimeException(se.getMessage());
231: } catch (IOException ioex) {
232: throw new RuntimeException(ioex.getMessage());
233: }
234: }
235:
236: private static byte[] convertASN1toXMLDSIG(byte asn1Bytes[])
237: throws IOException {
238:
239: // THIS CODE IS COPIED FROM APACHE (see copyright at top of file)
240: byte rLength = asn1Bytes[3];
241: int i;
242:
243: for (i = rLength; (i > 0)
244: && (asn1Bytes[(4 + rLength) - i] == 0); i--)
245: ;
246:
247: byte sLength = asn1Bytes[5 + rLength];
248: int j;
249:
250: for (j = sLength; (j > 0)
251: && (asn1Bytes[(6 + rLength + sLength) - j] == 0); j--)
252: ;
253:
254: if ((asn1Bytes[0] != 48)
255: || (asn1Bytes[1] != asn1Bytes.length - 2)
256: || (asn1Bytes[2] != 2) || (i > 20)
257: || (asn1Bytes[4 + rLength] != 2) || (j > 20)) {
258: throw new IOException(
259: "Invalid ASN.1 format of DSA signature");
260: } else {
261: byte xmldsigBytes[] = new byte[40];
262:
263: System.arraycopy(asn1Bytes, (4 + rLength) - i,
264: xmldsigBytes, 20 - i, i);
265: System.arraycopy(asn1Bytes, (6 + rLength + sLength) - j,
266: xmldsigBytes, 40 - j, j);
267:
268: return xmldsigBytes;
269: }
270: }
271:
272: public boolean verifyDSASignature(Key publicKey, SignedInfo si,
273: byte[] signatureValue) throws InvalidKeyException,
274: SignatureException {
275: if (!(publicKey instanceof PublicKey)) {
276: throw new InvalidKeyException("key must be PublicKey");
277: }
278: if (_dsaSignature == null) {
279: try {
280: _dsaSignature = Signature.getInstance("SHA1withDSA");
281: } catch (NoSuchAlgorithmException nsae) {
282: throw new SignatureException(
283: "SHA1withDSA Signature not found");
284: }
285: }
286: _dsaSignature.initVerify((PublicKey) publicKey);
287: SignerOutputStream sos = new SignerOutputStream(_dsaSignature);
288: if (si.getSignedInfo() != null) {
289: XMLStreamReaderEx signedInfo = (XMLStreamReaderEx) si
290: .getSignedInfo();
291: if (_exc14nSBCanonicalizer == null) {
292: _exc14nSBCanonicalizer = new EXC14nStAXReaderBasedCanonicalizer();
293: }
294:
295: NamespaceContextEx nsContext = signedInfo
296: .getNamespaceContext();
297: Iterator<NamespaceContextEx.Binding> itr = nsContext
298: .iterator();
299: ArrayList list = new ArrayList();
300: while (itr.hasNext()) {
301: NamespaceContextEx.Binding binding = itr.next();
302: AttributeNS ans = new AttributeNS();
303: ans.setPrefix(binding.getPrefix());
304: ans.setUri(binding.getNamespaceURI());
305: list.add(ans);
306: }
307:
308: _exc14nSBCanonicalizer.addParentNamespaces(list);
309: try {
310: _exc14nSBCanonicalizer.canonicalize(signedInfo, sos,
311: null);
312: } catch (XMLStreamException ex) {
313: logger
314: .log(
315: Level.SEVERE,
316: LogStringsMessages
317: .WSS_1724_SIGTYPE_VERIFICATION_FAILED("SHA1withDSA"));
318: throw new SignatureException(
319: LogStringsMessages
320: .WSS_1724_SIGTYPE_VERIFICATION_FAILED("SHA1withDSA"),
321: ex);
322: } catch (IOException ex) {
323: logger
324: .log(
325: Level.SEVERE,
326: LogStringsMessages
327: .WSS_1724_SIGTYPE_VERIFICATION_FAILED("SHA1withDSA"));
328: throw new SignatureException(
329: LogStringsMessages
330: .WSS_1724_SIGTYPE_VERIFICATION_FAILED("SHA1withDSA"),
331: ex);
332: }
333: } else {
334: sos.write(si.getCanonicalizedSI());
335: }
336: try {
337: return _dsaSignature
338: .verify(convertXMLDSIGtoASN1(signatureValue));
339: } catch (SignatureException ex) {
340: logger
341: .log(
342: Level.SEVERE,
343: LogStringsMessages
344: .WSS_1724_SIGTYPE_VERIFICATION_FAILED("SHA1withDSA"));
345: throw new SignatureException(
346: LogStringsMessages
347: .WSS_1724_SIGTYPE_VERIFICATION_FAILED("SHA1withDSA"),
348: ex);
349: } catch (IOException ex) {
350: logger
351: .log(
352: Level.SEVERE,
353: LogStringsMessages
354: .WSS_1724_SIGTYPE_VERIFICATION_FAILED("SHA1withDSA"));
355: throw new SignatureException(
356: LogStringsMessages
357: .WSS_1724_SIGTYPE_VERIFICATION_FAILED("SHA1withDSA"),
358: ex);
359: }
360:
361: }
362:
363: public boolean verifyHMACSignature(Key key, SignedInfo si,
364: byte[] signatureValue, int outputLength)
365: throws InvalidKeyException, SignatureException {
366: if (key == null || si == null || signatureValue == null) {
367: throw new NullPointerException(
368: "key, signedinfo or signature data can't be null");
369: }
370: HmacSHA1 hmac = new HmacSHA1();
371: hmac.init(key, outputLength);
372:
373: MacOutputStream mos = new MacOutputStream(hmac);
374: if (si.getSignedInfo() != null) {
375: XMLStreamReaderEx signedInfo = (XMLStreamReaderEx) si
376: .getSignedInfo();
377: if (_exc14nSBCanonicalizer == null) {
378: _exc14nSBCanonicalizer = new EXC14nStAXReaderBasedCanonicalizer();
379: }
380: NamespaceContextEx nsContext = signedInfo
381: .getNamespaceContext();
382: Iterator<NamespaceContextEx.Binding> itr = nsContext
383: .iterator();
384: ArrayList list = new ArrayList();
385: while (itr.hasNext()) {
386: NamespaceContextEx.Binding binding = itr.next();
387: AttributeNS ans = new AttributeNS();
388: ans.setPrefix(binding.getPrefix());
389: ans.setUri(binding.getNamespaceURI());
390: list.add(ans);
391: }
392:
393: _exc14nSBCanonicalizer.addParentNamespaces(list);
394: _exc14nSBCanonicalizer.addParentNamespaces(list);
395:
396: try {
397: _exc14nSBCanonicalizer.canonicalize(signedInfo, mos,
398: null);
399: } catch (XMLStreamException ex) {
400: logger
401: .log(
402: Level.SEVERE,
403: LogStringsMessages
404: .WSS_1724_SIGTYPE_VERIFICATION_FAILED("HMAC_SHA1"));
405: throw new SignatureException(
406: LogStringsMessages
407: .WSS_1724_SIGTYPE_VERIFICATION_FAILED("HMAC_SHA1"),
408: ex);
409: } catch (IOException ex) {
410: logger
411: .log(
412: Level.SEVERE,
413: LogStringsMessages
414: .WSS_1724_SIGTYPE_VERIFICATION_FAILED("HMAC_SHA1"));
415: throw new SignatureException(
416: LogStringsMessages
417: .WSS_1724_SIGTYPE_VERIFICATION_FAILED("HMAC_SHA1"),
418: ex);
419: }
420: } else {
421: mos.write(si.getCanonicalizedSI());
422: }
423: return hmac.verify(signatureValue);
424: }
425:
426: public boolean verifyRSASignature(Key publicKey, SignedInfo si,
427: byte[] signatureValue) throws InvalidKeyException,
428: SignatureException {
429:
430: if (!(publicKey instanceof PublicKey)) {
431: throw new InvalidKeyException("key must be PublicKey");
432: }
433: if (_rsaSignature == null) {
434: try {
435: _rsaSignature = Signature.getInstance("SHA1withRSA");
436: } catch (NoSuchAlgorithmException nsae) {
437: throw new SignatureException(
438: "SHA1withRSA Signature not found");
439: }
440: }
441: _rsaSignature.initVerify((PublicKey) publicKey);
442: SignerOutputStream sos = new SignerOutputStream(_rsaSignature);
443: if (si.getSignedInfo() != null) {
444: XMLStreamReaderEx signedInfo = (XMLStreamReaderEx) si
445: .getSignedInfo();
446: if (_exc14nSBCanonicalizer == null) {
447: _exc14nSBCanonicalizer = new EXC14nStAXReaderBasedCanonicalizer();
448: }
449: NamespaceContextEx nsContext = signedInfo
450: .getNamespaceContext();
451: Iterator<NamespaceContextEx.Binding> itr = nsContext
452: .iterator();
453: ArrayList list = new ArrayList();
454: while (itr.hasNext()) {
455: NamespaceContextEx.Binding binding = itr.next();
456: AttributeNS ans = new AttributeNS();
457: ans.setPrefix(binding.getPrefix());
458: ans.setUri(binding.getNamespaceURI());
459: list.add(ans);
460: }
461:
462: // _exc14nSBCanonicalizer.addParentNamespaces(list);
463: _exc14nSBCanonicalizer.addParentNamespaces(list);
464: try {
465: _exc14nSBCanonicalizer.canonicalize(signedInfo, sos,
466: null);
467: } catch (XMLStreamException ex) {
468: logger
469: .log(
470: Level.SEVERE,
471: LogStringsMessages
472: .WSS_1724_SIGTYPE_VERIFICATION_FAILED("SHA1WithRSA"));
473: throw new SignatureException(
474: LogStringsMessages
475: .WSS_1724_SIGTYPE_VERIFICATION_FAILED("SHA1WithRSA"),
476: ex);
477: } catch (IOException ex) {
478: logger
479: .log(
480: Level.SEVERE,
481: LogStringsMessages
482: .WSS_1724_SIGTYPE_VERIFICATION_FAILED("SHA1WithRSA"));
483: throw new SignatureException(
484: LogStringsMessages
485: .WSS_1724_SIGTYPE_VERIFICATION_FAILED("SHA1WithRSA"),
486: ex);
487: }
488: } else {
489: sos.write(si.getCanonicalizedSI());
490: }
491: return _rsaSignature.verify(signatureValue);
492: }
493:
494: private static byte[] convertXMLDSIGtoASN1(byte xmldsigBytes[])
495: throws IOException {
496:
497: // THIS CODE IS COPIED FROM APACHE (see copyright at top of file)
498: if (xmldsigBytes.length != 40) {
499: throw new IOException(
500: "Invalid XMLDSIG format of DSA signature");
501: }
502:
503: int i;
504:
505: for (i = 20; (i > 0) && (xmldsigBytes[20 - i] == 0); i--)
506: ;
507:
508: int j = i;
509:
510: if (xmldsigBytes[20 - i] < 0) {
511: j += 1;
512: }
513:
514: int k;
515:
516: for (k = 20; (k > 0) && (xmldsigBytes[40 - k] == 0); k--)
517: ;
518:
519: int l = k;
520:
521: if (xmldsigBytes[40 - k] < 0) {
522: l += 1;
523: }
524:
525: byte asn1Bytes[] = new byte[6 + j + l];
526:
527: asn1Bytes[0] = 48;
528: asn1Bytes[1] = (byte) (4 + j + l);
529: asn1Bytes[2] = 2;
530: asn1Bytes[3] = (byte) j;
531:
532: System.arraycopy(xmldsigBytes, 20 - i, asn1Bytes, (4 + j) - i,
533: i);
534:
535: asn1Bytes[4 + j] = 2;
536: asn1Bytes[5 + j] = (byte) l;
537:
538: System.arraycopy(xmldsigBytes, 40 - k, asn1Bytes, (6 + j + l)
539: - k, k);
540:
541: return asn1Bytes;
542: }
543:
544: private Marshaller getMarshaller() throws JAXBException {
545: JAXBFilterProcessingContext wssContext = (JAXBFilterProcessingContext) context
546: .get(MessageConstants.WSS_PROCESSING_CONTEXT);
547: Marshaller marshaller = _jaxbContext.createMarshaller();
548: marshaller
549: .setProperty("com.sun.xml.bind.xmlDeclaration", false);
550: if (wssContext != null)
551: marshaller
552: .setProperty(
553: "com.sun.xml.bind.namespacePrefixMapper",
554: new WSSNamespacePrefixMapper(wssContext
555: .isSOAP12()));
556: else
557: marshaller.setProperty(
558: "com.sun.xml.bind.namespacePrefixMapper",
559: new WSSNamespacePrefixMapper());
560: marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
561: return marshaller;
562: }
563:
564: private void setNamespaceAndPrefixList() {
565:
566: NamespaceAndPrefixMapper nsMapper = (NamespaceAndPrefixMapper) context
567: .get(NamespaceAndPrefixMapper.NS_PREFIX_MAPPER);
568: if (nsMapper != null) {
569: NamespaceContextEx nc = nsMapper.getNamespaceContext();
570: Iterator<NamespaceContextEx.Binding> itr = nc.iterator();
571: while (itr.hasNext()) {
572: final NamespaceContextEx.Binding nd = itr.next();
573: try {
574: _exc14nCanonicalizer.writeNamespace(nd.getPrefix(),
575: nd.getNamespaceURI());
576: } catch (XMLStreamException ex) {
577: throw new XWSSecurityRuntimeException(ex);
578: }
579: }
580: List incList = nsMapper.getInlusivePrefixList();
581: _exc14nCanonicalizer.setInclusivePrefixList(incList);
582: }
583: }
584:
585: }
|