KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ejbca > core > protocol > xkms > client > XKMSInvoker


1 /*************************************************************************
2  * *
3  * EJBCA: The OpenSource Certificate Authority *
4  * *
5  * This software is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU Lesser General Public *
7  * License as published by the Free Software Foundation; either *
8  * version 2.1 of the License, or any later version. *
9  * *
10  * See terms of license at gnu.org. *
11  * *
12  *************************************************************************/

13
14 package org.ejbca.core.protocol.xkms.client;
15
16 import gnu.inet.encoding.StringprepException;
17
18 import java.io.IOException JavaDoc;
19 import java.net.MalformedURLException JavaDoc;
20 import java.net.URL JavaDoc;
21 import java.security.Key JavaDoc;
22 import java.security.PrivateKey JavaDoc;
23 import java.security.cert.CertPath JavaDoc;
24 import java.security.cert.CertPathValidator JavaDoc;
25 import java.security.cert.CertPathValidatorException JavaDoc;
26 import java.security.cert.CertStore JavaDoc;
27 import java.security.cert.CertificateFactory JavaDoc;
28 import java.security.cert.CollectionCertStoreParameters JavaDoc;
29 import java.security.cert.PKIXParameters JavaDoc;
30 import java.security.cert.TrustAnchor JavaDoc;
31 import java.security.cert.X509Certificate JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Collection JavaDoc;
34 import java.util.Date JavaDoc;
35 import java.util.HashSet JavaDoc;
36 import java.util.Iterator JavaDoc;
37 import java.util.List JavaDoc;
38 import java.util.Set JavaDoc;
39
40 import javax.xml.bind.JAXBContext;
41 import javax.xml.bind.JAXBElement;
42 import javax.xml.bind.JAXBException;
43 import javax.xml.bind.Marshaller;
44 import javax.xml.bind.PropertyException;
45 import javax.xml.bind.Unmarshaller;
46 import javax.xml.namespace.QName JavaDoc;
47 import javax.xml.parsers.DocumentBuilder JavaDoc;
48 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
49 import javax.xml.parsers.ParserConfigurationException JavaDoc;
50 import javax.xml.transform.Source JavaDoc;
51 import javax.xml.transform.TransformerFactoryConfigurationError JavaDoc;
52 import javax.xml.transform.dom.DOMSource JavaDoc;
53 import javax.xml.transform.stream.StreamSource JavaDoc;
54 import javax.xml.ws.Dispatch;
55 import javax.xml.ws.Service;
56
57 import org.apache.log4j.Logger;
58 import org.apache.xml.security.exceptions.XMLSecurityException;
59 import org.apache.xml.security.signature.XMLSignatureException;
60 import org.apache.xml.security.transforms.TransformationException;
61 import org.ejbca.core.protocol.xkms.XKMSService;
62 import org.ejbca.core.protocol.xkms.common.XKMSConstants;
63 import org.ejbca.core.protocol.xkms.common.XKMSNamespacePrefixMapper;
64 import org.ejbca.core.protocol.xkms.common.XKMSUtil;
65 import org.ejbca.util.CertTools;
66 import org.w3._2002._03.xkms_.LocateRequestType;
67 import org.w3._2002._03.xkms_.LocateResultType;
68 import org.w3._2002._03.xkms_.ObjectFactory;
69 import org.w3._2002._03.xkms_.RecoverRequestType;
70 import org.w3._2002._03.xkms_.RecoverResultType;
71 import org.w3._2002._03.xkms_.RegisterRequestType;
72 import org.w3._2002._03.xkms_.RegisterResultType;
73 import org.w3._2002._03.xkms_.ReissueRequestType;
74 import org.w3._2002._03.xkms_.ReissueResultType;
75 import org.w3._2002._03.xkms_.RequestAbstractType;
76 import org.w3._2002._03.xkms_.RevokeRequestType;
77 import org.w3._2002._03.xkms_.RevokeResultType;
78 import org.w3._2002._03.xkms_.ValidateRequestType;
79 import org.w3._2002._03.xkms_.ValidateResultType;
80 import org.w3c.dom.Document JavaDoc;
81 import org.xml.sax.SAXException JavaDoc;
82
83 /**
84  * Helper class that performs the prefix replacements
85  * and does the dispatch invokation.
86  *
87  *
88  * @author Philip Vendil 2006 dec 19
89  *
90  * @version $Id: XKMSInvoker.java,v 1.2 2007/01/05 05:32:54 herrvendil Exp $
91  */

92
93 public class XKMSInvoker {
94
95     private static Logger log = Logger.getLogger(XKMSInvoker.class);
96
97     private static JAXBContext jAXBContext = null;
98     private static Marshaller marshaller = null;
99     private static Unmarshaller unmarshaller = null;
100     private static DocumentBuilderFactory JavaDoc dbf = null;
101     
102     private Collection JavaDoc cacerts = null;
103
104     private static Dispatch<Source JavaDoc> sourceDispatch = null;
105     private ObjectFactory xKMSObjectFactory = new ObjectFactory();
106
107     static{
108         try {
109             org.apache.xml.security.Init.init();
110             CertTools.installBCProvider();
111
112             jAXBContext = JAXBContext.newInstance("org.w3._2002._03.xkms_:org.w3._2001._04.xmlenc_:org.w3._2000._09.xmldsig_");
113             marshaller = jAXBContext.createMarshaller();
114             try {
115                 marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper",new XKMSNamespacePrefixMapper());
116             } catch( PropertyException e ) {
117                 log.error("Error registering namespace mapper property",e);
118             }
119             dbf = DocumentBuilderFactory.newInstance();
120             dbf.setNamespaceAware(true);
121             unmarshaller = jAXBContext.createUnmarshaller();
122
123         } catch (JAXBException e) {
124             log.error("Error initializing RequestAbstractTypeResponseGenerator",e);
125         }
126
127     }
128         
129     /**
130      * Creates an invoker to the web service at the specified URL
131      *
132      * @param serviceURL the url to the web service.
133      * @param cacerts a collection of trusted CA signing responses. Use null if signed responeses isn't required.
134      */

135     public XKMSInvoker(String JavaDoc serviceURL, Collection JavaDoc cacerts){
136         XKMSService xkmsService;
137         try {
138             xkmsService = new XKMSService(new URL JavaDoc(serviceURL + ".wsdl"),new QName JavaDoc("http://www.w3.org/2002/03/xkms#wsdl", "XKMSService"));
139             sourceDispatch = xkmsService.createDispatch(new QName JavaDoc("http://www.w3.org/2002/03/xkms#wsdl", "XKMSPort"), Source JavaDoc.class, Service.Mode.PAYLOAD);
140         } catch (MalformedURLException JavaDoc e) {
141           log.error("Error creating XKMS Service instance",e);
142         }
143         
144         this.cacerts = cacerts;
145         if(cacerts==null){
146             cacerts = new ArrayList JavaDoc();
147         }
148     }
149
150     /**
151      * Creates a locate call to the web service
152      *
153      * @param locateRequestType the request
154      * @param signCert the certificate that should sign the request, or null of no signing should be performed
155      * @param privateKey the key doing the signing, or null of no signing should be performed
156      * @return a LocateResultType
157      * @throws XKMSResponseSignatureException if the response signature didn't verify
158      */

159     public LocateResultType locate(LocateRequestType locateRequestType, X509Certificate JavaDoc signCert, Key JavaDoc privateKey) throws XKMSResponseSignatureException{
160         JAXBElement<LocateRequestType> locateRequest = xKMSObjectFactory.createLocateRequest(locateRequestType);
161         DOMSource JavaDoc domSource = performSigning(locateRequest, locateRequestType.getId(), signCert, privateKey);
162         JAXBElement<LocateResultType> response = invoke(domSource);
163                 
164         return response.getValue();
165     }
166     
167     /**
168      * Creates a validate call to the web service
169      *
170      * @param validateRequestType the request
171      * @param signCert the certificate that should sign the request, or null of no signing should be performed
172      * @param privateKey the key doing the signing, or null of no signing should be performed
173      * @return a ValidateResultType
174      * @throws XKMSResponseSignatureException if the response signature didn't verify
175      */

176     public ValidateResultType validate(ValidateRequestType validateRequestType, X509Certificate JavaDoc signCert, Key JavaDoc privateKey) throws XKMSResponseSignatureException{
177         JAXBElement<ValidateRequestType> validateRequest = xKMSObjectFactory.createValidateRequest(validateRequestType);
178         DOMSource JavaDoc domSource = performSigning(validateRequest, validateRequestType.getId(), signCert, privateKey);
179         JAXBElement<ValidateResultType> response = invoke(domSource);
180         
181         return response.getValue();
182     }
183     
184     /**
185      * Creates a register call to the web service
186      *
187      * @param registerRequestType the request
188      * @param signCert the certificate that should sign the request, or null of no signing should be performed
189      * @param privateKey the key doing the signing, or null of no signing should be performed
190      * @param authenticationPassphrase the authenticationkeybinding passphrase, use null if it shouldn't be used.
191      * @param pOPPrivateKey private key to sign POP Element, use null to not append POPElement
192      * @param prototypeKeyBindingId is of the PrototypeKeyBinding tag.
193      * @return a RegisterResultType
194      * @throws XKMSResponseSignatureException if the response signature didn't verify
195      * @throws StringprepException if the passphrase doesn't fullfull the SASLPrep profile
196      */

197     public RegisterResultType register(RegisterRequestType registerRequestType, X509Certificate JavaDoc signCert, Key JavaDoc privateKey, String JavaDoc authenticationPassphrase, PrivateKey JavaDoc pOPPrivateKey, String JavaDoc prototypeKeyBindingId) throws XKMSResponseSignatureException, StringprepException{
198         JAXBElement<RegisterRequestType> registerRequest = xKMSObjectFactory.createRegisterRequest(registerRequestType);
199         DOMSource JavaDoc domSource = performSigning(registerRequest, registerRequestType.getId(), signCert, privateKey, authenticationPassphrase, pOPPrivateKey, prototypeKeyBindingId);
200         JAXBElement<RegisterResultType> response = invoke(domSource);
201         
202         return response.getValue();
203     }
204     
205     /**
206      * Creates a reissue call to the web service
207      *
208      * @param reissueRequestType the request
209      * @param signCert the certificate that should sign the request, or null of no signing should be performed
210      * @param privateKey the key doing the signing, or null of no signing should be performed
211      * @param authenticationPassphrase the authenticationkeybinding passphrase, use null if it shouldn't be used.
212      * @param pOPPrivateKey private key to sign POP Element, use null to not append POPElement
213      * @param reissueKeyBindingId is of the PrototypeKeyBinding tag.
214      * @return a ReissueResultType
215      * @throws XKMSResponseSignatureException if the response signature didn't verify
216      * @throws StringprepException if the passphrase doesn't fullfull the SASLPrep profile
217      */

218     public ReissueResultType reissue(ReissueRequestType reissueRequestType, X509Certificate JavaDoc signCert, Key JavaDoc privateKey, String JavaDoc authenticationPassphrase, PrivateKey JavaDoc pOPPrivateKey, String JavaDoc reissueKeyBindingId) throws XKMSResponseSignatureException, StringprepException{
219         JAXBElement<ReissueRequestType> reissueRequest = xKMSObjectFactory.createReissueRequest(reissueRequestType);
220         DOMSource JavaDoc domSource = performSigning(reissueRequest, reissueRequestType.getId(), signCert, privateKey, authenticationPassphrase, pOPPrivateKey, reissueKeyBindingId);
221         JAXBElement<ReissueResultType> response = invoke(domSource);
222         
223         return response.getValue();
224     }
225     
226     /**
227      * Creates a recover call to the web service
228      *
229      * @param recoverRequestType the request
230      * @param signCert the certificate that should sign the request, or null of no signing should be performed
231      * @param privateKey the key doing the signing, or null of no signing should be performed
232      * @param authenticationPassphrase the authenticationkeybinding passphrase, use null if it shouldn't be used.
233      * @param reissueKeyBindingId is of the PrototypeKeyBinding tag.
234      * @return a ReissueResultType
235      * @throws XKMSResponseSignatureException if the response signature didn't verify
236      * @throws StringprepException if the passphrase doesn't fullfull the SASLPrep profile
237      */

238     public RecoverResultType recover(RecoverRequestType recoverRequestType, X509Certificate JavaDoc signCert, Key JavaDoc privateKey, String JavaDoc authenticationPassphrase, String JavaDoc recoverKeyBindingId) throws XKMSResponseSignatureException, StringprepException{
239         JAXBElement<RecoverRequestType> recoverRequest = xKMSObjectFactory.createRecoverRequest(recoverRequestType);
240         DOMSource JavaDoc domSource = performSigning(recoverRequest, recoverRequestType.getId(), signCert, privateKey, authenticationPassphrase, null, recoverKeyBindingId);
241         JAXBElement<RecoverResultType> response = invoke(domSource);
242         
243         return response.getValue();
244     }
245     
246     /**
247      * Creates a revoke call to the web service
248      *
249      * @param recvokeRequestType the request
250      * @param signCert the certificate that should sign the request, or null of no signing should be performed
251      * @param privateKey the key doing the signing, or null of no signing should be performed
252      * @param authenticationPassphrase the authenticationkeybinding passphrase, use null if it shouldn't be used.
253      * @param revokeKeyBindingId is of the PrototypeKeyBinding tag.
254      * @return a RevokeResultType
255      * @throws XKMSResponseSignatureException if the response signature didn't verify
256      * @throws StringprepException if the passphrase doesn't fullfull the SASLPrep profile
257      */

258     public RevokeResultType revoke(RevokeRequestType revokeRequestType, X509Certificate JavaDoc signCert, Key JavaDoc privateKey, String JavaDoc authenticationPassphrase, String JavaDoc revokeKeyBindingId) throws XKMSResponseSignatureException, StringprepException{
259         JAXBElement<RevokeRequestType> revokeRequest = xKMSObjectFactory.createRevokeRequest(revokeRequestType);
260         DOMSource JavaDoc domSource = performSigning(revokeRequest, revokeRequestType.getId(), signCert, privateKey, authenticationPassphrase, null, revokeKeyBindingId);
261         JAXBElement<RevokeResultType> response = invoke(domSource);
262         
263         return response.getValue();
264     }
265     
266     
267     /**
268      * Method that performs the actual invokation.
269      * @param abstractMessageType
270      * @return
271      * @throws XKMSResponseSignatureException
272      */

273     private JAXBElement invoke(DOMSource JavaDoc domSource) throws XKMSResponseSignatureException{
274         JAXBElement result =null;
275    
276         try{
277             Source JavaDoc response = sourceDispatch.invoke(domSource);
278             
279             DocumentBuilder JavaDoc db = dbf.newDocumentBuilder();
280             Document JavaDoc doc = db.parse(((StreamSource JavaDoc) response).getInputStream());
281                         
282             verifyResponseSignature(doc);
283             result = (JAXBElement) unmarshaller.unmarshal(doc);
284         } catch(JAXBException e){
285             log.error("Error marshalling XKMS request",e);
286         } catch (ParserConfigurationException JavaDoc e) {
287             log.error("Error parsing XKMS response",e);
288         } catch (SAXException JavaDoc e) {
289             log.error("Error parsing XKMS response",e);
290         } catch (IOException JavaDoc e) {
291             log.error("Error parsing XKMS response",e);
292         }
293         
294         return result;
295     }
296     
297     
298     /**
299      * Creates a signature on a request and returns a DOM source.
300      *
301      * @param messageAbstractType the request to sign
302      * @param signCert the certificate that should sign the request, or null of no signing should be performed
303      * @param privateKey the key doing the signing, or null of no signing should be performed
304      * @return a DOMSource or null if request was invalid
305      */

306     private DOMSource JavaDoc performSigning(JAXBElement messageAbstractType, String JavaDoc messageId, X509Certificate JavaDoc signCert, Key JavaDoc privateKey){
307         DOMSource JavaDoc retval = null;
308         
309         try{
310             retval = performSigning(messageAbstractType, messageId, signCert, privateKey, null, null, null);
311         }catch(StringprepException e){
312             // Should never happen
313
}
314         
315         return retval;
316     }
317     
318     /**
319      * Creates a signature on a request and returns a DOM source.
320      *
321      * @param messageAbstractType the request to sign
322      * @param signCert the certificate that should sign the request, or null of no signing should be performed
323      * @param privateKey the key doing the signing, or null of no signing should be performed
324      * @param authenticationPassphrase the authenticationkeybinding passphrase, use null if it shouldn't be used.
325      * @param pOPPrivateKey private key to sign POP Element, use null to not append POPElement
326      * @param prototypeKeyBindingId is of the PrototypeKeyBinding tag.
327      * @return a DOMSource or null if request was invalid
328      * @throws StringprepException if the passphrase doesn't fullfull the SASLPrep profile
329      */

330     private DOMSource JavaDoc performSigning(JAXBElement messageAbstractType, String JavaDoc messageId, X509Certificate JavaDoc signCert, Key JavaDoc privateKey,
331                                      String JavaDoc authenticationPassphrase, PrivateKey JavaDoc pOPPrivateKey, String JavaDoc prototypeKeyBindingId) throws StringprepException{
332             DOMSource JavaDoc retval = null;
333         
334             try{
335                 if(signCert != null && privateKey != null ){
336                     RequestAbstractType requestAbstractType = (RequestAbstractType) messageAbstractType.getValue();
337                     requestAbstractType.getResponseMechanism().add(XKMSConstants.RESPONSMEC_REQUESTSIGNATUREVALUE);
338                 }
339                 
340                 Document JavaDoc doc = dbf.newDocumentBuilder().newDocument();
341                 marshaller.marshal( messageAbstractType, doc );
342                 
343                 if(authenticationPassphrase != null){
344                     doc = XKMSUtil.appendKeyBindingAuthentication(doc, authenticationPassphrase, prototypeKeyBindingId);
345                 }
346                 
347                 if(pOPPrivateKey != null){
348                     doc = XKMSUtil.appendProofOfPossession(doc, pOPPrivateKey, prototypeKeyBindingId);
349                 }
350
351                 if(signCert != null && privateKey != null ){
352                     org.apache.xml.security.signature.XMLSignature xmlSig = new org.apache.xml.security.signature.XMLSignature(doc, "", org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1, org.apache.xml.security.c14n.Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
353                     org.apache.xml.security.transforms.Transforms transforms = new org.apache.xml.security.transforms.Transforms(doc);
354                     transforms.addTransform(org.apache.xml.security.transforms.Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
355                     transforms.addTransform(org.apache.xml.security.transforms.Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
356                     xmlSig.addDocument("#" + messageId, transforms, org.apache.xml.security.utils.Constants.ALGO_ID_DIGEST_SHA1);
357                     xmlSig.addKeyInfo(signCert);
358                     doc.getDocumentElement().insertBefore( xmlSig.getElement() ,doc.getDocumentElement().getFirstChild());
359                     xmlSig.sign(privateKey);
360                 }
361
362                 retval = new DOMSource JavaDoc(doc);
363             
364             }catch(XMLSignatureException e){
365                 log.error("Error performing XML Signature ",e);
366             } catch (TransformationException e) {
367                 log.error("Error parsing XML request ",e);
368             } catch (JAXBException e) {
369                 log.error("Error parsing XML request ",e);
370             } catch (ParserConfigurationException JavaDoc e) {
371                 log.error("Error parsing XML request ",e);
372             } catch (XMLSecurityException e) {
373                 log.error("Error performing XML Signature ",e);
374             }
375         
376         return retval;
377     }
378     
379     /**
380      * Method that verifies the response signature,
381      *
382      * doesn't check the revokation status of the server certificate.
383      *
384      * @param response, the response from the service
385      * @throws {@link XKMSResponseSignatureException} if the signature doesn't verify
386      */

387     private void verifyResponseSignature(Document JavaDoc doc) throws XKMSResponseSignatureException{
388         try{
389
390             boolean signatureExists = false;
391
392             org.w3c.dom.NodeList JavaDoc xmlSigs = doc.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", "Signature");
393             signatureExists = xmlSigs.getLength() > 0;
394         
395             if(signatureExists && cacerts != null){
396
397                 try{
398                     org.w3c.dom.Element JavaDoc xmlSigElement = (org.w3c.dom.Element JavaDoc)xmlSigs.item(0);
399                     org.apache.xml.security.signature.XMLSignature xmlVerifySig = new org.apache.xml.security.signature.XMLSignature(xmlSigElement, null);
400
401                     org.apache.xml.security.keys.KeyInfo keyInfo = xmlVerifySig.getKeyInfo();
402                     java.security.cert.X509Certificate JavaDoc verCert = keyInfo.getX509Certificate();
403
404                     // Check signature
405
if(xmlVerifySig.checkSignatureValue(verCert)){
406                         
407                         Collection JavaDoc cACertChain = cacerts;
408                         // Check issuer and validity
409
X509Certificate JavaDoc rootCert = null;
410                         Iterator JavaDoc iter = cACertChain.iterator();
411                         while(iter.hasNext()){
412                             X509Certificate JavaDoc cert = (X509Certificate JavaDoc) iter.next();
413                             if(cert.getIssuerDN().equals(cert.getSubjectDN())){
414                                 rootCert = cert;
415                                 break;
416                             }
417                         }
418
419                         if(rootCert == null){
420                             throw new CertPathValidatorException JavaDoc("Error Root CA cert not found in cACertChain");
421                         }
422
423                         List JavaDoc list = new ArrayList JavaDoc();
424                         list.add(verCert);
425                         list.add(cACertChain);
426
427                         CollectionCertStoreParameters JavaDoc ccsp = new CollectionCertStoreParameters JavaDoc(list);
428                         CertStore JavaDoc store = CertStore.getInstance("Collection", ccsp);
429
430                         //validating path
431
List JavaDoc certchain = new ArrayList JavaDoc();
432                         certchain.addAll(cACertChain);
433                         certchain.add(verCert);
434                         CertPath JavaDoc cp = CertificateFactory.getInstance("X.509","BC").generateCertPath(certchain);
435
436                         Set JavaDoc trust = new HashSet JavaDoc();
437                         trust.add(new TrustAnchor JavaDoc(rootCert, null));
438
439                         CertPathValidator JavaDoc cpv = CertPathValidator.getInstance("PKIX","BC");
440                         PKIXParameters JavaDoc param = new PKIXParameters JavaDoc(trust);
441                         param.addCertStore(store);
442                         param.setDate(new Date JavaDoc());
443                         param.setRevocationEnabled(false);
444
445                         cpv.validate(cp, param);
446                     }else{
447                         throw new XKMSResponseSignatureException("Error XKMS request signature doesn't verify.");
448                     }
449                 }catch(Exception JavaDoc e){
450                     throw new XKMSResponseSignatureException("Error when verifying signature request.",e);
451                 }
452             }else{
453                 if(cacerts != null){
454                     throw new XKMSResponseSignatureException("Error XKMS response didn't return and signed response");
455                 }
456             }
457         } catch (TransformerFactoryConfigurationError JavaDoc e) {
458             log.error("Error when DOM parsing request.",e);
459         }
460     }
461 }
462
Popular Tags