1 13 14 package org.ejbca.core.protocol.xkms.client; 15 16 import gnu.inet.encoding.StringprepException; 17 18 import java.io.IOException ; 19 import java.net.MalformedURLException ; 20 import java.net.URL ; 21 import java.security.Key ; 22 import java.security.PrivateKey ; 23 import java.security.cert.CertPath ; 24 import java.security.cert.CertPathValidator ; 25 import java.security.cert.CertPathValidatorException ; 26 import java.security.cert.CertStore ; 27 import java.security.cert.CertificateFactory ; 28 import java.security.cert.CollectionCertStoreParameters ; 29 import java.security.cert.PKIXParameters ; 30 import java.security.cert.TrustAnchor ; 31 import java.security.cert.X509Certificate ; 32 import java.util.ArrayList ; 33 import java.util.Collection ; 34 import java.util.Date ; 35 import java.util.HashSet ; 36 import java.util.Iterator ; 37 import java.util.List ; 38 import java.util.Set ; 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 ; 47 import javax.xml.parsers.DocumentBuilder ; 48 import javax.xml.parsers.DocumentBuilderFactory ; 49 import javax.xml.parsers.ParserConfigurationException ; 50 import javax.xml.transform.Source ; 51 import javax.xml.transform.TransformerFactoryConfigurationError ; 52 import javax.xml.transform.dom.DOMSource ; 53 import javax.xml.transform.stream.StreamSource ; 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 ; 81 import org.xml.sax.SAXException ; 82 83 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 dbf = null; 101 102 private Collection cacerts = null; 103 104 private static Dispatch<Source > 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 135 public XKMSInvoker(String serviceURL, Collection cacerts){ 136 XKMSService xkmsService; 137 try { 138 xkmsService = new XKMSService(new URL (serviceURL + ".wsdl"),new QName ("http://www.w3.org/2002/03/xkms#wsdl", "XKMSService")); 139 sourceDispatch = xkmsService.createDispatch(new QName ("http://www.w3.org/2002/03/xkms#wsdl", "XKMSPort"), Source .class, Service.Mode.PAYLOAD); 140 } catch (MalformedURLException e) { 141 log.error("Error creating XKMS Service instance",e); 142 } 143 144 this.cacerts = cacerts; 145 if(cacerts==null){ 146 cacerts = new ArrayList (); 147 } 148 } 149 150 159 public LocateResultType locate(LocateRequestType locateRequestType, X509Certificate signCert, Key privateKey) throws XKMSResponseSignatureException{ 160 JAXBElement<LocateRequestType> locateRequest = xKMSObjectFactory.createLocateRequest(locateRequestType); 161 DOMSource domSource = performSigning(locateRequest, locateRequestType.getId(), signCert, privateKey); 162 JAXBElement<LocateResultType> response = invoke(domSource); 163 164 return response.getValue(); 165 } 166 167 176 public ValidateResultType validate(ValidateRequestType validateRequestType, X509Certificate signCert, Key privateKey) throws XKMSResponseSignatureException{ 177 JAXBElement<ValidateRequestType> validateRequest = xKMSObjectFactory.createValidateRequest(validateRequestType); 178 DOMSource domSource = performSigning(validateRequest, validateRequestType.getId(), signCert, privateKey); 179 JAXBElement<ValidateResultType> response = invoke(domSource); 180 181 return response.getValue(); 182 } 183 184 197 public RegisterResultType register(RegisterRequestType registerRequestType, X509Certificate signCert, Key privateKey, String authenticationPassphrase, PrivateKey pOPPrivateKey, String prototypeKeyBindingId) throws XKMSResponseSignatureException, StringprepException{ 198 JAXBElement<RegisterRequestType> registerRequest = xKMSObjectFactory.createRegisterRequest(registerRequestType); 199 DOMSource domSource = performSigning(registerRequest, registerRequestType.getId(), signCert, privateKey, authenticationPassphrase, pOPPrivateKey, prototypeKeyBindingId); 200 JAXBElement<RegisterResultType> response = invoke(domSource); 201 202 return response.getValue(); 203 } 204 205 218 public ReissueResultType reissue(ReissueRequestType reissueRequestType, X509Certificate signCert, Key privateKey, String authenticationPassphrase, PrivateKey pOPPrivateKey, String reissueKeyBindingId) throws XKMSResponseSignatureException, StringprepException{ 219 JAXBElement<ReissueRequestType> reissueRequest = xKMSObjectFactory.createReissueRequest(reissueRequestType); 220 DOMSource domSource = performSigning(reissueRequest, reissueRequestType.getId(), signCert, privateKey, authenticationPassphrase, pOPPrivateKey, reissueKeyBindingId); 221 JAXBElement<ReissueResultType> response = invoke(domSource); 222 223 return response.getValue(); 224 } 225 226 238 public RecoverResultType recover(RecoverRequestType recoverRequestType, X509Certificate signCert, Key privateKey, String authenticationPassphrase, String recoverKeyBindingId) throws XKMSResponseSignatureException, StringprepException{ 239 JAXBElement<RecoverRequestType> recoverRequest = xKMSObjectFactory.createRecoverRequest(recoverRequestType); 240 DOMSource domSource = performSigning(recoverRequest, recoverRequestType.getId(), signCert, privateKey, authenticationPassphrase, null, recoverKeyBindingId); 241 JAXBElement<RecoverResultType> response = invoke(domSource); 242 243 return response.getValue(); 244 } 245 246 258 public RevokeResultType revoke(RevokeRequestType revokeRequestType, X509Certificate signCert, Key privateKey, String authenticationPassphrase, String revokeKeyBindingId) throws XKMSResponseSignatureException, StringprepException{ 259 JAXBElement<RevokeRequestType> revokeRequest = xKMSObjectFactory.createRevokeRequest(revokeRequestType); 260 DOMSource 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 273 private JAXBElement invoke(DOMSource domSource) throws XKMSResponseSignatureException{ 274 JAXBElement result =null; 275 276 try{ 277 Source response = sourceDispatch.invoke(domSource); 278 279 DocumentBuilder db = dbf.newDocumentBuilder(); 280 Document doc = db.parse(((StreamSource ) 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 e) { 287 log.error("Error parsing XKMS response",e); 288 } catch (SAXException e) { 289 log.error("Error parsing XKMS response",e); 290 } catch (IOException e) { 291 log.error("Error parsing XKMS response",e); 292 } 293 294 return result; 295 } 296 297 298 306 private DOMSource performSigning(JAXBElement messageAbstractType, String messageId, X509Certificate signCert, Key privateKey){ 307 DOMSource retval = null; 308 309 try{ 310 retval = performSigning(messageAbstractType, messageId, signCert, privateKey, null, null, null); 311 }catch(StringprepException e){ 312 } 314 315 return retval; 316 } 317 318 330 private DOMSource performSigning(JAXBElement messageAbstractType, String messageId, X509Certificate signCert, Key privateKey, 331 String authenticationPassphrase, PrivateKey pOPPrivateKey, String prototypeKeyBindingId) throws StringprepException{ 332 DOMSource 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 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 (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 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 387 private void verifyResponseSignature(Document doc) throws XKMSResponseSignatureException{ 388 try{ 389 390 boolean signatureExists = false; 391 392 org.w3c.dom.NodeList 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 xmlSigElement = (org.w3c.dom.Element )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 verCert = keyInfo.getX509Certificate(); 403 404 if(xmlVerifySig.checkSignatureValue(verCert)){ 406 407 Collection cACertChain = cacerts; 408 X509Certificate rootCert = null; 410 Iterator iter = cACertChain.iterator(); 411 while(iter.hasNext()){ 412 X509Certificate cert = (X509Certificate ) 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 ("Error Root CA cert not found in cACertChain"); 421 } 422 423 List list = new ArrayList (); 424 list.add(verCert); 425 list.add(cACertChain); 426 427 CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters (list); 428 CertStore store = CertStore.getInstance("Collection", ccsp); 429 430 List certchain = new ArrayList (); 432 certchain.addAll(cACertChain); 433 certchain.add(verCert); 434 CertPath cp = CertificateFactory.getInstance("X.509","BC").generateCertPath(certchain); 435 436 Set trust = new HashSet (); 437 trust.add(new TrustAnchor (rootCert, null)); 438 439 CertPathValidator cpv = CertPathValidator.getInstance("PKIX","BC"); 440 PKIXParameters param = new PKIXParameters (trust); 441 param.addCertStore(store); 442 param.setDate(new Date ()); 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 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 e) { 458 log.error("Error when DOM parsing request.",e); 459 } 460 } 461 } 462 | Popular Tags |