All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.certificateservices.messages.pkimessages.DefaultPKIMessageParser Maven / Gradle / Ivy

The newest version!
/************************************************************************
*                                                                       *
*  Certificate Service - Messages                                       *
*                                                                       *
*  This software is free software; you can redistribute it and/or       *
*  modify it under the terms of the GNU Lesser General Public License   *
*  License as published by the Free Software Foundation; either         *
*  version 3   of the License, or any later version.                    *
*                                                                       *
*  See terms of license at gnu.org.                                     *
*                                                                       *
*************************************************************************/
package org.certificateservices.messages.pkimessages;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.xml.security.exceptions.Base64DecodingException;
import org.apache.xml.security.utils.Base64;
import org.certificateservices.messages.MessageException;
import org.certificateservices.messages.MessageProcessingException;
import org.certificateservices.messages.MessageSecurityProvider;
import org.certificateservices.messages.csmessages.DefaultCSMessageParser;
import org.certificateservices.messages.pkimessages.jaxb.ChangeCredentialStatusRequest;
import org.certificateservices.messages.pkimessages.jaxb.ChangeCredentialStatusResponse;
import org.certificateservices.messages.pkimessages.jaxb.Credential;
import org.certificateservices.messages.pkimessages.jaxb.CredentialStatusList;
import org.certificateservices.messages.pkimessages.jaxb.FetchHardTokenDataRequest;
import org.certificateservices.messages.pkimessages.jaxb.FetchHardTokenDataResponse;
import org.certificateservices.messages.pkimessages.jaxb.GetCredentialRequest;
import org.certificateservices.messages.pkimessages.jaxb.GetCredentialResponse;
import org.certificateservices.messages.pkimessages.jaxb.GetCredentialStatusListRequest;
import org.certificateservices.messages.pkimessages.jaxb.GetCredentialStatusListResponse;
import org.certificateservices.messages.pkimessages.jaxb.GetIssuerCredentialsRequest;
import org.certificateservices.messages.pkimessages.jaxb.GetIssuerCredentialsResponse;
import org.certificateservices.messages.pkimessages.jaxb.IsIssuerRequest;
import org.certificateservices.messages.pkimessages.jaxb.IsIssuerResponse;
import org.certificateservices.messages.pkimessages.jaxb.IssueCredentialStatusListRequest;
import org.certificateservices.messages.pkimessages.jaxb.IssueCredentialStatusListResponse;
import org.certificateservices.messages.pkimessages.jaxb.IssueTokenCredentialsRequest;
import org.certificateservices.messages.pkimessages.jaxb.IssueTokenCredentialsResponse;
import org.certificateservices.messages.pkimessages.jaxb.ObjectFactory;
import org.certificateservices.messages.pkimessages.jaxb.Originator;
import org.certificateservices.messages.pkimessages.jaxb.PKIMessage;
import org.certificateservices.messages.pkimessages.jaxb.PKIMessage.Payload;
import org.certificateservices.messages.pkimessages.jaxb.PKIResponse;
import org.certificateservices.messages.pkimessages.jaxb.RemoveCredentialRequest;
import org.certificateservices.messages.pkimessages.jaxb.RemoveCredentialResponse;
import org.certificateservices.messages.pkimessages.jaxb.RequestStatus;
import org.certificateservices.messages.pkimessages.jaxb.StoreHardTokenDataRequest;
import org.certificateservices.messages.pkimessages.jaxb.StoreHardTokenDataResponse;
import org.certificateservices.messages.pkimessages.jaxb.TokenRequest;
import org.certificateservices.messages.utils.MessageGenerateUtils;
import org.certificateservices.messages.utils.SettingsUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.ls.LSInput;
import org.w3c.dom.ls.LSResourceResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * Default implementation of a PKI Message parser generating and signing messages
 * accordning to the specification.
 * 
 * 
 * @author Philip Vendil
 *
 */
@SuppressWarnings({ "deprecation" })
public class DefaultPKIMessageParser implements PKIMessageParser {

	public static final String SETTING_SOURCEID = "pkimessage.sourceid";
	public static final String SETTING_SIGN = "pkimessage.sign";
	public static final String SETTING_REQUIRESIGNATURE = "pkimessage.requiresignature";
	
	public static final String SETTING_MESSAGE_NAME_CATALOGUE_IMPL = "pkimessage.messagenamecatalogue.impl";
	public static final String DEFAULT_MESSAGE_NAME_CATALOGUE_IMPL = DefaultMessageNameCatalogue.class.getName();

	private static final String PKIMESSAGE_VERSION_1_0 = "1.0";
	private static final String PKIMESSAGE_VERSION_1_1 = "1.1";
	
	private static final String PKIMESSAGE_XSD_SCHEMA_1_0_RESOURCE_LOCATION = "/pkimessages_schema1_0.xsd";
	private static final String PKIMESSAGE_XSD_SCHEMA_1_1_RESOURCE_LOCATION = "/pkimessages_schema1_1.xsd";
	
	private static final String PKIMESSAGE_XSD_SCHEMA_1_0_URI = "http://certificateservices.org/xsd/pkimessages1_0 pkimessages_schema1_0.xsd";	
	
	private static final Map pkiMessageSchemaMap = new HashMap();
	static{
		pkiMessageSchemaMap.put(PKIMESSAGE_VERSION_1_0, PKIMESSAGE_XSD_SCHEMA_1_0_RESOURCE_LOCATION);
		pkiMessageSchemaMap.put(PKIMESSAGE_VERSION_1_1, PKIMESSAGE_XSD_SCHEMA_1_1_RESOURCE_LOCATION);
	}
	
	private static final Map pkiMessageSchemaUriMap = new HashMap();
	static{
		pkiMessageSchemaUriMap.put(PKIMESSAGE_VERSION_1_0, PKIMESSAGE_XSD_SCHEMA_1_0_URI);
		pkiMessageSchemaUriMap.put(PKIMESSAGE_VERSION_1_1, PKIMESSAGE_XSD_SCHEMA_1_0_URI);
	}
	
	private static final String XMLDSIG_XSD_SCHEMA_RESOURCE_LOCATION = "/xmldsig-core-schema.xsd";
	

	private static final String[] SUPPORTED_PKIMESSAGE_VERSIONS = {"1.0","1.1"};
	

	private Map pkixMessageMarshallers = new HashMap();
	private Map pkixMessageUnmarshallers = new HashMap();
	
	private ObjectFactory objectFactory = new ObjectFactory();
	
	private Properties properties = null;
	private MessageSecurityProvider securityProvider = null;
	private MessageNameCatalogue messageNameCatalogue = null;
	
	private String sourceId = null;
	
	private String defaultVersion = PKIMESSAGE_VERSION_1_1;
		
	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#init(org.certificateservices.messages.MessageSecurityProvider, java.util.Properties)
	 */
	
	public void init(MessageSecurityProvider securityProvider,
			Properties config) throws MessageException {
		this.properties = config;
		this.securityProvider = securityProvider;
		this.messageNameCatalogue = getMessageNameCatalogue(config);
		

		// Initialize all marshallers for all supported version.
		for(String version : SUPPORTED_PKIMESSAGE_VERSIONS){
			getPKIMessageMarshaller(version);
			getPKIMessageUnmarshaller(version);
		}

		sourceId = SettingsUtils.getProperty(config, SETTING_SOURCEID, DefaultCSMessageParser.SETTING_SOURCEID);
		if(sourceId == null || sourceId.trim().equals("")){
			throw new MessageException("Error setting " + DefaultCSMessageParser.SETTING_SOURCEID + " must be set.");
		}

		
	}

	Marshaller createMarshaller(JAXBContext jaxbContext, String schemaLocation) throws JAXBException{
		Marshaller retval = jaxbContext.createMarshaller();
		
		retval.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, schemaLocation);
		retval.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
		return retval;
	}
	
	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#parseMessage(byte[])
	 */
	
	public synchronized PKIMessage parseMessage(byte[] messageData)
			throws IllegalArgumentException, MessageException {
		try{
			
			
			String version = getVersionFromMessage(messageData);
			verifyPKIMessageVersion(version);
			
			
			Object object = getPKIMessageUnmarshaller(version).unmarshal(new ByteArrayInputStream(messageData));
			validatePKIMessage(object, new String(messageData,"UTF-8"));
			return (PKIMessage) object;
		}catch(JAXBException e){
			throw new IllegalArgumentException("Error parsing PKI Message: " + e.getMessage(),e);
		} catch (UnsupportedEncodingException e) {
			throw new IllegalArgumentException("Error parsing PKI Message: " + e.getMessage(),e);
		}
		
	}
	
	/**
	 * Verifies that the given version is supported.
	 * @param version the version to check.
	 * @throws IllegalArgumentException if version is unsupported.
	 */
	private void verifyPKIMessageVersion(String version) throws IllegalArgumentException{
		boolean foundVersion = false;
		for(String supportedVersion : SUPPORTED_PKIMESSAGE_VERSIONS){
			if(supportedVersion.equals(version)){
				foundVersion=true;
				break;
			}
		}
		if(!foundVersion){
			throw new IllegalArgumentException("Error unsupported protocol version " + version);
		}
	}

	/**
	 * Method that validates the fields of the message that isn't already validated by the schema
	 * and the digital signature of the message.
	 * @param object the message to validate.
	 * @param message string representation of the message data.
	 * @throws IllegalArgumentException if the message contained bad format.
	 * @throws MessageException if internal problems occurred validating the message.
	 */
	private void validatePKIMessage(Object object, String message) throws IllegalArgumentException, MessageException {
		
		if(!(object instanceof PKIMessage)){
			throw new IllegalArgumentException("Error: parsed object not a PKI Message.");
		}
		PKIMessage pkiMessage = (PKIMessage) object;
		validatePKIMessageHeader(pkiMessage, message);
	}

	/**
	 * Method that validates the "header" parts of the pki message.
	 * @param pkiMessage the pki message to validate, never null
	 * @param message string representation of the message data.
	 * @throws IllegalArgumentException if the header contained illegal arguments.
	 */
	private void validatePKIMessageHeader(PKIMessage pkiMessage, String message) throws IllegalArgumentException, MessageException{
		

		
		validateSignature(message);
		
		
	}

	private void validateSignature(String message) throws IllegalArgumentException, MessageException {
		if(requireSignature()){
			try{
				DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
				factory.setNamespaceAware(true);
				DocumentBuilder builder = factory.newDocumentBuilder();
				Document doc = builder.parse(new InputSource(new StringReader(message)));

				Node signature = doc.getElementsByTagName("ds:Signature").item(0);

				if(signature == null){
					throw new IllegalArgumentException("Required digital signature not found in message.");
				}

				DOMValidateContext validationContext = new DOMValidateContext(new X509DataOnlyKeySelector(securityProvider), signature);
				validationContext.setIdAttributeNS(doc.getDocumentElement(), null, "ID");
				XMLSignatureFactory signatureFactory = XMLSignatureFactory.getInstance("DOM",new org.apache.jcp.xml.dsig.internal.dom.XMLDSigRI());
				XMLSignature sig =  signatureFactory.unmarshalXMLSignature(validationContext);
				if(!sig.validate(validationContext)){
					throw new IllegalArgumentException("Error, signed message didn't pass validation.");
				}
				//sig.getKeyInfo().getContent().g
			}catch(Exception e){
				if(e instanceof IllegalArgumentException ){
					throw (IllegalArgumentException) e;
				}
				if(e instanceof MessageException){
					throw (MessageException) e;
				}
				throw new IllegalArgumentException("Error validating signature of message: " + e.getMessage(),e);
			}
		}				
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genIssueTokenCredentialsRequest(String, String, TokenRequest)
	 */
	public byte[] genIssueTokenCredentialsRequest(String requestId, String destinationId, String organisation, 
			TokenRequest tokenRequest, Credential originator) throws IllegalArgumentException,
			MessageException {
		IssueTokenCredentialsRequest payload = objectFactory.createIssueTokenCredentialsRequest();
		payload.setTokenRequest(tokenRequest);
		PKIMessage pkiMessage = genPKIMessage(defaultVersion, requestId, destinationId, organisation, originator, payload);		
		return marshallAndSignPKIMessage( pkiMessage);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genIssueTokenCredentialsResponse(PKIMessage, List, List)
	 */
	
	public PKIMessageResponseData genIssueTokenCredentialsResponse(String relatedEndEntity, PKIMessage request,
			List credentials, List revokedCredentials) throws IllegalArgumentException,
			MessageException {
		IssueTokenCredentialsRequest issueTokenCredentialsRequest = request.getPayload().getIssueTokenCredentialsRequest();
		if(issueTokenCredentialsRequest == null){
			throw new IllegalArgumentException("Error IssueTokenCredentialsResponse requires a IssueTokenCredentialsRequest in request payload.");
		}
		
		IssueTokenCredentialsResponse payload = objectFactory.createIssueTokenCredentialsResponse();
		populateSuccessfulResponse(payload, request);
		payload.setTokenRequest(issueTokenCredentialsRequest.getTokenRequest());
		payload.setCredentials(new IssueTokenCredentialsResponse.Credentials());
		for(Credential cred : credentials){
		  payload.getCredentials().getCredential().add(cred);
		}
		if(revokedCredentials != null){
			payload.setRevokedCredentials(new IssueTokenCredentialsResponse.Credentials());
			for(Credential cred : revokedCredentials){
				payload.getRevokedCredentials().getCredential().add(cred);
			}
		}
		
		PKIMessage pkiMessage = genPKIMessage(request.getVersion(), request.getName(),null, request.getSourceId(), request.getOrganisation(), getOriginatorFromRequest(request), payload);		
		byte[] responseData = marshallAndSignPKIMessage(pkiMessage);
		return new PKIMessageResponseData(pkiMessage.getID(),pkiMessage.getName(), relatedEndEntity, pkiMessage.getDestinationId(),responseData, true);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genChangeCredentialStatusRequest(String, String, String, String, int, String)
	 */
	
	public byte[] genChangeCredentialStatusRequest(String requestId, String destinationId,String organisation, 
			String issuerId, String serialNumber, int newCredentialStatus,
			String reasonInformation, Credential originator) throws IllegalArgumentException,
			MessageException {
		ChangeCredentialStatusRequest payload = objectFactory.createChangeCredentialStatusRequest();
		payload.setIssuerId(issuerId);
		payload.setSerialNumber(serialNumber);
		payload.setNewCredentialStatus(newCredentialStatus);
		payload.setReasonInformation(reasonInformation);
		PKIMessage pkiMessage = genPKIMessage(defaultVersion, requestId, destinationId, organisation, originator, payload);		
		return marshallAndSignPKIMessage(pkiMessage);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genChangeCredentialStatusResponse(PKIMessage, String, String, int, String, Date)
	 */
	
	public PKIMessageResponseData genChangeCredentialStatusResponse(String relatedEndEntity, PKIMessage request,
			String issuerId, String serialNumber, int credentialStatus,
			String reasonInformation, Date revocationDate)
			throws IllegalArgumentException, MessageException {
		ChangeCredentialStatusRequest changeCredentialStatusRequest = request.getPayload().getChangeCredentialStatusRequest();
		if(changeCredentialStatusRequest == null){
			throw new IllegalArgumentException("Error ChangeCredentialStatusResponse requires a ChangeCredentialStatusRequest in request payload.");
		}
		
		ChangeCredentialStatusResponse payload = objectFactory.createChangeCredentialStatusResponse();
		populateSuccessfulResponse(payload, request);
		payload.setIssuerId(issuerId);
		payload.setSerialNumber(serialNumber);
		payload.setCredentialStatus(credentialStatus);
		payload.setReasonInformation(reasonInformation);
		payload.setRevocationDate(PKIMessageGenerateUtils.dateToXMLGregorianCalendar(revocationDate));
		PKIMessage pkiMessage = genPKIMessage(request.getVersion(), request.getName(),null, request.getSourceId(), request.getOrganisation(), getOriginatorFromRequest(request), payload);		
		byte[] responseData = marshallAndSignPKIMessage( pkiMessage);
		return new PKIMessageResponseData(pkiMessage.getID(),pkiMessage.getName(), relatedEndEntity, pkiMessage.getDestinationId(),responseData, true);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genGetCredentialRequest(String, String, String, String, String)
	 */
	
	public byte[] genGetCredentialRequest(String requestId, String destinationId, String organisation, String credentialSubType, String issuerId,
			String serialNumber, Credential originator) throws IllegalArgumentException,
			MessageException {
		GetCredentialRequest payload = objectFactory.createGetCredentialRequest();
		payload.setCredentialSubType(credentialSubType);
		payload.setIssuerId(issuerId);
		payload.setSerialNumber(serialNumber);
		PKIMessage pkiMessage = genPKIMessage(defaultVersion, requestId, destinationId, organisation, originator, payload);		
		return marshallAndSignPKIMessage(pkiMessage);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genGetCredentialResponse(PKIMessage, Credential)
	 */
	
	public PKIMessageResponseData genGetCredentialResponse(String relatedEndEntity,PKIMessage request,
			Credential credential) throws IllegalArgumentException,
			MessageException {
		GetCredentialRequest getCredentialRequest = request.getPayload().getGetCredentialRequest();
		if(getCredentialRequest == null){
			throw new IllegalArgumentException("Error GetCredentialResponse requires a GetCredentialRequest in request payload.");
		}
		
		GetCredentialResponse payload = objectFactory.createGetCredentialResponse();
		populateSuccessfulResponse(payload, request);
		payload.setCredential(credential);		
		PKIMessage pkiMessage = genPKIMessage(request.getVersion(),request.getName(),null, request.getSourceId(), request.getOrganisation(), getOriginatorFromRequest(request), payload);		
		byte[] responseData = marshallAndSignPKIMessage(pkiMessage);
		return new PKIMessageResponseData(pkiMessage.getID(),pkiMessage.getName(), relatedEndEntity, pkiMessage.getDestinationId(),responseData);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genGetCredentialStatusListRequest(String, String, String, Long, String)
	 */
	
	public byte[] genGetCredentialStatusListRequest(String requestId, String destinationId,String organisation, 
			String issuerId, Long serialNumber, String credentialStatusListType, Credential originator)
			throws IllegalArgumentException, MessageException {
		GetCredentialStatusListRequest payload = objectFactory.createGetCredentialStatusListRequest();
		payload.setIssuerId(issuerId);
		payload.setSerialNumber(serialNumber);
		payload.setCredentialStatusListType(credentialStatusListType);
		PKIMessage pkiMessage = genPKIMessage(defaultVersion, requestId, destinationId, organisation, originator, payload);		
		return marshallAndSignPKIMessage(pkiMessage);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genGetCredentialStatusListResponse(org.certificateservices.messages.pkimessages.jaxb.PKIMessage, org.certificateservices.messages.pkimessages.jaxb.CredentialStatusList)
	 */
	
	public PKIMessageResponseData genGetCredentialStatusListResponse(String relatedEndEntity,PKIMessage request,
			CredentialStatusList credentialStatusList)
			throws IllegalArgumentException, MessageException {
		GetCredentialStatusListRequest getCredentialStatusListRequest = request.getPayload().getGetCredentialStatusListRequest();
		if(getCredentialStatusListRequest == null){
			throw new IllegalArgumentException("Error GetCredentialStatusListResponse requires a GetCredentialStatusListRequest in request payload.");
		}
		
		GetCredentialStatusListResponse payload = objectFactory.createGetCredentialStatusListResponse();
		populateSuccessfulResponse(payload, request);
		payload.setCredentialStatusList(credentialStatusList);	
		PKIMessage pkiMessage = genPKIMessage(request.getVersion(),request.getName(),null, request.getSourceId(), request.getOrganisation(), getOriginatorFromRequest(request), payload);		
		byte[] responseData = marshallAndSignPKIMessage(pkiMessage);
		return new PKIMessageResponseData(pkiMessage.getID(),pkiMessage.getName(), relatedEndEntity, pkiMessage.getDestinationId(),responseData);
	}
	
	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genGetIssuerCredentialsRequest(String, String, String)
	 */
	
	public byte[] genGetIssuerCredentialsRequest(String requestId,String destinationId,String organisation, 
			String issuerId, Credential originator) throws IllegalArgumentException,
			MessageException {
		GetIssuerCredentialsRequest payload = objectFactory.createGetIssuerCredentialsRequest();
		payload.setIssuerId(issuerId);
		PKIMessage pkiMessage = genPKIMessage(defaultVersion, requestId, destinationId, organisation, originator, payload);		
		return marshallAndSignPKIMessage(pkiMessage);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genGetIssuerCredentialsResponse(PKIMessage, Credential)
	 */
	
	public PKIMessageResponseData genGetIssuerCredentialsResponse(String relatedEndEntity, PKIMessage request,
			Credential issuerCredential) throws IllegalArgumentException,
			MessageException {
		GetIssuerCredentialsRequest getIssuerCredentialsRequest = request.getPayload().getGetIssuerCredentialsRequest();
		if(getIssuerCredentialsRequest == null){
			throw new IllegalArgumentException("Error GetIssuerCredentialsResponse requires a GetIssuerCredentialsRequest in request payload.");
		}
		
		GetIssuerCredentialsResponse payload = objectFactory.createGetIssuerCredentialsResponse();
		populateSuccessfulResponse(payload, request);
		payload.setCredential(issuerCredential);		
		PKIMessage pkiMessage = genPKIMessage(request.getVersion(),request.getName(),null, request.getSourceId(), request.getOrganisation(), getOriginatorFromRequest(request), payload);		
		byte[] responseData = marshallAndSignPKIMessage(pkiMessage);
		return new PKIMessageResponseData(pkiMessage.getID(),pkiMessage.getName(), relatedEndEntity,pkiMessage.getDestinationId(),responseData);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genIsIssuerRequest(String, String, String)
	 */
	
	public byte[] genIsIssuerRequest(String requestId,String destinationId, String organisation,  String issuerId, Credential originator)
			throws IllegalArgumentException, MessageException {
		IsIssuerRequest payload = objectFactory.createIsIssuerRequest();
		payload.setIssuerId(issuerId);
		PKIMessage pkiMessage = genPKIMessage(defaultVersion,requestId,destinationId, organisation, originator, payload);		
		return marshallAndSignPKIMessage(pkiMessage);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genIsIssuerResponse(org.certificateservices.messages.pkimessages.jaxb.PKIMessage, boolean)
	 */
	
	public PKIMessageResponseData genIsIssuerResponse(String relatedEndEntity,PKIMessage request, boolean isIssuer)
			throws IllegalArgumentException, MessageException {
		IsIssuerRequest isIssuerRequest = request.getPayload().getIsIssuerRequest();
		if(isIssuerRequest == null){
			throw new IllegalArgumentException("Error IsIssuerResponse requires a IsIssuerRequest in request payload.");
		}
		
		IsIssuerResponse payload = objectFactory.createIsIssuerResponse();
		populateSuccessfulResponse(payload, request);
		payload.setIsIssuer(isIssuer);		
		PKIMessage pkiMessage = genPKIMessage(request.getVersion(),request.getName(),null, request.getSourceId(), request.getOrganisation(), getOriginatorFromRequest(request), payload);		
		byte[] responseData = marshallAndSignPKIMessage(pkiMessage);
		return new PKIMessageResponseData(pkiMessage.getID(),pkiMessage.getName(), relatedEndEntity,pkiMessage.getDestinationId(),responseData);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genIssueCredentialStatusListRequest(String, String, String, String, Boolean, Date, Date)
	 */
	
	public byte[] genIssueCredentialStatusListRequest(String requestId,String destinationId,String organisation, 
			String issuerId, String credentialStatusListType, Boolean force,
			Date requestedValidFromDate, Date requestedNotAfterDate, Credential originator )
			throws IllegalArgumentException, MessageException {
		IssueCredentialStatusListRequest payload = objectFactory.createIssueCredentialStatusListRequest();
		payload.setIssuerId(issuerId);
		payload.setCredentialStatusListType(credentialStatusListType);
		payload.setForce(force);
		payload.setRequestedNotAfterDate(PKIMessageGenerateUtils.dateToXMLGregorianCalendar(requestedNotAfterDate));
		payload.setRequestedValidFromDate(PKIMessageGenerateUtils.dateToXMLGregorianCalendar(requestedValidFromDate));
		PKIMessage pkiMessage = genPKIMessage(defaultVersion,requestId, destinationId, organisation, originator, payload);		
		return marshallAndSignPKIMessage(pkiMessage);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genIssueCredentialStatusListResponse(org.certificateservices.messages.pkimessages.jaxb.PKIMessage, org.certificateservices.messages.pkimessages.jaxb.CredentialStatusList)
	 */
	
	public PKIMessageResponseData genIssueCredentialStatusListResponse(String relatedEndEntity,PKIMessage request,
			CredentialStatusList credentialStatusList)
			throws IllegalArgumentException, MessageException {
		IssueCredentialStatusListRequest issueCredentialStatusListRequest = request.getPayload().getIssueCredentialStatusListRequest();
		if(issueCredentialStatusListRequest == null){
			throw new IllegalArgumentException("Error IssueCredentialStatusListResponse requires a IssueCredentialStatusListRequest in request payload.");
		}
		
		IssueCredentialStatusListResponse payload = objectFactory.createIssueCredentialStatusListResponse();
		populateSuccessfulResponse(payload, request);
		payload.setCredentialStatusList(credentialStatusList);
		PKIMessage pkiMessage = genPKIMessage(request.getVersion(),request.getName(),null, request.getSourceId(), request.getOrganisation(), getOriginatorFromRequest(request), payload);		
		byte[] responseData = marshallAndSignPKIMessage(pkiMessage);
		return new PKIMessageResponseData(pkiMessage.getID(),pkiMessage.getName(), relatedEndEntity, pkiMessage.getDestinationId(),responseData, true);
	}
	
	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genIssueCredentialStatusListResponseWithoutRequest(String, String, CredentialStatusList)
	 */
	
	public PKIMessageResponseData genIssueCredentialStatusListResponseWithoutRequest(String relatedEndEntity, String destination, String name, String organisation,
			CredentialStatusList credentialStatusList, Credential originator)
			throws IllegalArgumentException, MessageException {
		String responseId = MessageGenerateUtils.generateRandomUUID();
		IssueCredentialStatusListResponse payload = objectFactory.createIssueCredentialStatusListResponse();
		payload.setFailureMessage(null);
		payload.setStatus(RequestStatus.SUCCESS);
		payload.setInResponseTo(responseId);
		payload.setCredentialStatusList(credentialStatusList);
		PKIMessage pkiMessage = genPKIMessage(defaultVersion,name,responseId, destination, organisation, originator, payload);		
		byte[] responseData = marshallAndSignPKIMessage(pkiMessage);
		return new PKIMessageResponseData(pkiMessage.getID(),pkiMessage.getName(), relatedEndEntity, pkiMessage.getDestinationId(),responseData, true);
	}
	
	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genRemoveCredentialRequest(String, String, String, String)
	 */
	
	public byte[] genRemoveCredentialRequest(String requestId,String destinationId,String organisation, 
			String issuerId, String serialNumber, Credential originator)
			throws IllegalArgumentException, MessageException {
		RemoveCredentialRequest payload = objectFactory.createRemoveCredentialRequest();
		payload.setIssuerId(issuerId);
		payload.setSerialNumber(serialNumber);
		PKIMessage pkiMessage = genPKIMessage(defaultVersion, requestId, destinationId, organisation, originator, payload);		
		return marshallAndSignPKIMessage(pkiMessage);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genRemoveCredentialResponse(org.certificateservices.messages.pkimessages.jaxb.PKIMessage)
	 */
	
	public PKIMessageResponseData genRemoveCredentialResponse(String relatedEndEntity,PKIMessage request)
			throws IllegalArgumentException, MessageException {
		RemoveCredentialRequest removeCredentialRequest = request.getPayload().getRemoveCredentialRequest();
		if(removeCredentialRequest == null){
			throw new IllegalArgumentException("Error RemoveCredentialResponse requires a RemoveCredentialRequest in request payload.");
		}
		
		RemoveCredentialResponse payload = objectFactory.createRemoveCredentialResponse();
		populateSuccessfulResponse(payload, request);
		PKIMessage pkiMessage = genPKIMessage(request.getVersion(),request.getName(),null, request.getSourceId(), request.getOrganisation(), getOriginatorFromRequest(request), payload);		
		byte[] responseData = marshallAndSignPKIMessage(pkiMessage);
		return new PKIMessageResponseData(pkiMessage.getID(),pkiMessage.getName(), relatedEndEntity,pkiMessage.getDestinationId(),responseData);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genFetchHardTokenDataRequest(String, String, String, String, String, Credential)
	 */
	
	public byte[] genFetchHardTokenDataRequest(String requestId,String destinationId, String organisation,
			String tokenSerial, String relatedCredentialSerialNumber,
			String relatedCredentialIssuerId, Credential adminCredential, Credential originator)
			throws IllegalArgumentException, MessageException {
		FetchHardTokenDataRequest payload = objectFactory.createFetchHardTokenDataRequest();
		payload.setTokenSerial(tokenSerial);
		payload.setRelatedCredentialSerialNumber(relatedCredentialSerialNumber);
		payload.setRelatedCredentialIssuerId(relatedCredentialIssuerId);
		payload.setAdminCredential(adminCredential);
		PKIMessage pkiMessage = genPKIMessage(defaultVersion, requestId, destinationId, organisation, originator, payload);		
		return marshallAndSignPKIMessage(pkiMessage);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genFetchHardTokenDataResponse(org.certificateservices.messages.pkimessages.jaxb.PKIMessage, java.lang.String, byte[])
	 */
	
	public PKIMessageResponseData genFetchHardTokenDataResponse(String relatedEndEntity,PKIMessage request,
			String tokenSerial, byte[] encryptedData)
			throws IllegalArgumentException, MessageException {
		FetchHardTokenDataRequest fetchHardTokenDataRequest = request.getPayload().getFetchHardTokenDataRequest();
		if(fetchHardTokenDataRequest == null){
			throw new IllegalArgumentException("Error FetchHardTokenDataResponse requires a FetchHardTokenDataRequest in request payload.");
		}
		
		FetchHardTokenDataResponse payload = objectFactory.createFetchHardTokenDataResponse();
		populateSuccessfulResponse(payload, request);
		payload.setTokenSerial(tokenSerial);
		payload.setEncryptedData(encryptedData);
		PKIMessage pkiMessage = genPKIMessage(request.getVersion(),request.getName(),null,request.getSourceId(), request.getOrganisation(), getOriginatorFromRequest(request), payload);		
		byte[] responseData = marshallAndSignPKIMessage(pkiMessage);
		return new PKIMessageResponseData(pkiMessage.getID(),pkiMessage.getName(), relatedEndEntity,pkiMessage.getDestinationId(),responseData);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genStoreHardTokenDataRequest(String, String, String, String, String, byte[])
	 */
	
	public byte[] genStoreHardTokenDataRequest(String requestId, String destinationId, String organisation,
			String tokenSerial, String relatedCredentialSerialNumber,
			String relatedCredentialIssuerId, byte[] encryptedData, 
			Credential originator)
			throws IllegalArgumentException, MessageException {
		StoreHardTokenDataRequest payload = objectFactory.createStoreHardTokenDataRequest();
		payload.setTokenSerial(tokenSerial);
		payload.setRelatedCredentialSerialNumber(relatedCredentialSerialNumber);
		payload.setRelatedCredentialIssuerId(relatedCredentialIssuerId);
		payload.setEncryptedData(encryptedData);
		PKIMessage pkiMessage = genPKIMessage(defaultVersion, requestId,destinationId, organisation, originator, payload);		
		return marshallAndSignPKIMessage(pkiMessage);
	}

	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genStoreHardTokenDataResponse(org.certificateservices.messages.pkimessages.jaxb.PKIMessage)
	 */
	
	public PKIMessageResponseData genStoreHardTokenDataResponse(String relatedEndEntity,PKIMessage request)
			throws IllegalArgumentException, MessageException {
		StoreHardTokenDataRequest storeHardTokenDataRequest = request.getPayload().getStoreHardTokenDataRequest();
		if(storeHardTokenDataRequest == null){
			throw new IllegalArgumentException("Error StoreHardTokenDataResponse requires a StoreHardTokenDataRequest in request payload.");
		}
		
		StoreHardTokenDataResponse payload = objectFactory.createStoreHardTokenDataResponse();
		populateSuccessfulResponse(payload, request);
		PKIMessage pkiMessage = genPKIMessage(request.getVersion(),request.getName(),null,request.getSourceId(), request.getOrganisation(), getOriginatorFromRequest(request), payload);		
		byte[] responseData = marshallAndSignPKIMessage(pkiMessage);
		return new PKIMessageResponseData(pkiMessage.getID(),pkiMessage.getName(), relatedEndEntity,pkiMessage.getDestinationId(),responseData);
	}





	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genPKIResponse(org.certificateservices.messages.pkimessages.jaxb.PKIMessage, org.certificateservices.messages.pkimessages.jaxb.RequestStatus, java.lang.String)
	 */
	
	public PKIMessageResponseData genPKIResponse(String relatedEndEntity,byte[] request, RequestStatus status,
			String failureMessage, Credential originator) throws IllegalArgumentException,
			MessageException {

		return genPKIResponse(relatedEndEntity,request, status, failureMessage, null,originator);

	}
	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#genPKIResponse(org.certificateservices.messages.pkimessages.jaxb.PKIMessage, org.certificateservices.messages.pkimessages.jaxb.RequestStatus, java.lang.String, java.lang.String)
	 */
	
	public PKIMessageResponseData genPKIResponse(String relatedEndEntity,byte[] request, RequestStatus status,
			String failureMessage, String destinationID, Credential originator) throws IllegalArgumentException,
			MessageException {
		try {
			DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
			domFactory.setNamespaceAware(true);
			DocumentBuilder builder = domFactory.newDocumentBuilder();
			Document doc = builder.parse(new ByteArrayInputStream(request));
			
    		Node pkiMessageNode = doc.getFirstChild();
    		String version=null;
    		if(pkiMessageNode != null){
    			Node versionNode = pkiMessageNode.getAttributes().getNamedItem("version");
    			if(versionNode != null){
    				version = versionNode.getNodeValue();
    			}
    		}  
    		if(version == null || version.trim().equals("")){
    			throw new IllegalArgumentException("Error unsupported protocol version when generating PKIResponse, version: " + version);
    		}

			XPathFactory factory = XPathFactory.newInstance();
			XPath xpath = factory.newXPath();
			if(destinationID == null){
				XPathExpression expr = xpath.compile("//*[local-name()='sourceId']/text()");
				String result = (String) expr.evaluate(doc, XPathConstants.STRING);
				if(result != null){
				  destinationID = result;
				}
			}

			XPathExpression expr = xpath.compile("//*[local-name()='PKIMessage']/@ID");
			Object result = expr.evaluate(doc, XPathConstants.STRING);			   
			String responseToRequestID = (String) result;

			expr = xpath.compile("//*[local-name()='organisation']/text()");
			result = expr.evaluate(doc, XPathConstants.STRING);;
			String organisation = (String) result;
			
			expr = xpath.compile("//*[local-name()='name']/text()");
			result = expr.evaluate(doc, XPathConstants.STRING);;
			String requestName = (String) result;
			
			if(organisation == null || responseToRequestID == null || destinationID == null || requestName==null){
				throw new IllegalArgumentException("Error generating PKI Message Response from request, due to missing fields organisation, sourceId, name or ID in request.");
			}
			
			PKIResponse payload = objectFactory.createPKIResponse();
			payload.setStatus(status);
			payload.setFailureMessage(failureMessage);
			payload.setInResponseTo(responseToRequestID);

			PKIMessage pkiMessage = genPKIMessage(version,requestName, null,destinationID, organisation, originator, payload);

			byte[] responseData = marshallAndSignPKIMessage(pkiMessage);
			return new PKIMessageResponseData(pkiMessage.getID(),pkiMessage.getName(), relatedEndEntity, pkiMessage.getDestinationId(),responseData, false );
		} catch (ParserConfigurationException e) {
			throw new MessageException("Error configuring the XML SAX Parser : " + e.getMessage());
		} catch (SAXException e) {
			throw new IllegalArgumentException("Error parsing request XML message: " + e.getMessage());
		} catch (IOException e) {
			throw new MessageException("Error reading the XML request data : " + e.getMessage());
		} catch (XPathExpressionException e) {
			throw new MessageException("Error constructing XPath expression when generating PKI Message responses : " + e.getMessage());
		}
	}
	
	/**
	 * @see org.certificateservices.messages.pkimessages.PKIMessageParser#getSigningCertificate(PKIMessage)	 
	 */	
	public X509Certificate getSigningCertificate(byte[] request)
			throws IllegalArgumentException, MessageException {
		X509Certificate retval = null;
		if(requireSignature()){
			try{
				DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
				domFactory.setNamespaceAware(true);
				DocumentBuilder builder = domFactory.newDocumentBuilder();
				Document doc = builder.parse(new ByteArrayInputStream(request));

				XPathFactory factory = XPathFactory.newInstance();
				XPath xpath = factory.newXPath();
				
				XPathExpression expr = xpath.compile("//*[local-name()='KeyInfo']/*[local-name()='X509Data']/*[local-name()='X509Certificate']/text()");
				String result = (String) expr.evaluate(doc, XPathConstants.STRING);
				if(result != null && !result.equals("")){
					CertificateFactory cf = 
							CertificateFactory.getInstance("X.509");
					retval = (X509Certificate) 
							cf.generateCertificate(new ByteArrayInputStream(Base64.decode(result.getBytes())));					
				}
				
			}catch(CertificateException e){
				
			} catch (ParserConfigurationException e) {
				throw new MessageException("Error building XPath Expression when fetching signing certificate: " + e.getMessage(),e);
			} catch (SAXException e) {
				throw new IllegalArgumentException("Error reading signing certificate found in PKI Message request: " + e.getMessage(),e);
			} catch (IOException e) {
				throw new IllegalArgumentException("Error reading signing certificate found in PKI Message request: " + e.getMessage(),e);
			} catch (XPathExpressionException e) {
				throw new MessageException("Error building XPath Expression when fetching signing certificate: " + e.getMessage(),e);
			} catch (Base64DecodingException e) {
				throw new MessageException("Error reading signing certificate base 64 decoding exception: " + e.getMessage(),e);
			}
			
			
			if(retval == null){
				throw new IllegalArgumentException("Error, no signing certificate found in PKI Message request.");
			}			
	}
		return retval;
	}
	
	/**
	 * Method to return the default version.
	 * @return the version used to generate requests by default.
	 */
	public String getDefaultVersion(){
		return defaultVersion;
	}

	/**
	 * Method the set the version to set in generated requests.
	 * 
	 * @param defaultVersion the version.
	 */
	public void setDefaultVersion(String defaultVersion){
		this.defaultVersion = defaultVersion;
	}
	
	/**
	 * Method that populates all fields except the signature of a PKI message
	 * @param messageId the id of the message, if null is a random id generated.
	 * @param destinationID the destination Id to use.
	 * @param organisation the related organisation
	 * @param originator the originator of the message if applicable.
	 * @param payload the payload object to set in the object
	 * @throws IllegalArgumentException if input data contained invalid format.
	 * @throws MessageException if internal problems occurred processing the pki message.
	 */
	private PKIMessage genPKIMessage(String version, String messageId, String destinationID, String organisation, Credential originator, Object payload) throws IllegalArgumentException, MessageException{
		return genPKIMessage(version,null, messageId, destinationID, organisation, originator, payload);
	}
	
	/**
	 * Method that populates all fields except the signature of a PKI message.
	 * 
	 * @param requestName the name in the request, or null if no related request exists
	 * @param messageId the id of the message, if null is a random id generated.
	 * @param destinationID the destination Id to use.
	 * @param organisation the related organisation
	 * @param originator the originator of the message if applicable.
	 * @param payload the payload object to set in the object
	 * @throws IllegalArgumentException if input data contained invalid format.
	 * @throws MessageException if internal problems occurred processing the pki message.
	 */
	private PKIMessage genPKIMessage(String version, String requestName, String messageId, String destinationID, String organisation, Credential originator, Object payload) throws IllegalArgumentException, MessageException{
		PKIMessage retval = objectFactory.createPKIMessage();
		retval.setVersion(version);
		if(messageId == null){
		  retval.setID(MessageGenerateUtils.generateRandomUUID());
		}else{
		  retval.setID(messageId);
		}
		retval.setTimeStamp(PKIMessageGenerateUtils.dateToXMLGregorianCalendar(new Date()));
		retval.setName(messageNameCatalogue.lookupName(requestName, payload));
		retval.setDestinationId(destinationID);
		retval.setSourceId(sourceId);
		retval.setOrganisation(organisation);
		if(originator != null){
			Originator originatorElement = objectFactory.createOriginator();
			originatorElement.setCredential(originator);
		    retval.setOriginator(originatorElement);
		}
		retval.setPayload(getPayLoadObject(payload));
			
		return retval;
	}
	
	/**
	 * Message generating a Message.Payload object from a standalone payload object. 
	 * @param payload the payload object to create a message Payload for.
	 * @return a new PKIMessage.Payload instance with the payload object set.
	 * @throws MessageException 
	 */
	private Payload getPayLoadObject(Object payload) throws MessageException,IllegalArgumentException {
		
		try {
			Payload retval = new Payload();
			if(payload.getClass().getSimpleName().equals("PKIResponse")){
				retval.setFailureResponse((PKIResponse) payload);
			}else{
			  Method m = retval.getClass().getMethod("set" + payload.getClass().getSimpleName(), payload.getClass());
			  m.invoke(retval,payload);
			}
			return retval;
		} catch (NoSuchMethodException e) {
			throw new IllegalArgumentException("Invalid payload object: " + payload.getClass().getSimpleName() + ", " + e.getMessage(),e);
		} catch (SecurityException e) {
			throw new MessageException("Internal error populating payload object: " + e.getMessage(),e);
		} catch (IllegalAccessException e) {
			throw new MessageException("Internal error populating payload object: " + e.getMessage(),e);
		} catch (InvocationTargetException e) {
			throw new MessageException("Internal error populating payload object: " + e.getMessage(),e);
		}
		
	}

	/**
	 * Method that generates the signature and marshalls the message to byte array in UTF-8 format.
	 * @param pkiMessage the PKIMessage to sign and marshall, never null.
	 * @return a marshalled and signed message.
	 * @throws MessageException if problems occurred when processing the message.
	 */
	public synchronized byte[] marshallAndSignPKIMessage(PKIMessage pkiMessage) throws MessageException{
		if(pkiMessage == null){
			throw new MessageException("Error marshalling PKI Message, message cannot be null.");
		}

		try {
			Document doc = getDocumentBuilder().newDocument();		
			String version = pkiMessage.getVersion();
			getPKIMessageMarshaller(version).marshal(pkiMessage, doc);
			if(signMessages()){
	
				XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM",new org.apache.jcp.xml.dsig.internal.dom.XMLDSigRI());
				DigestMethod digestMethod = fac.newDigestMethod 
						("http://www.w3.org/2001/04/xmlenc#sha256", null);

				List transFormList = new ArrayList();
				transFormList.add(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null));				
				Reference ref = fac.newReference("#" + pkiMessage.getID(),digestMethod, transFormList, null, null);

				ArrayList refList = new ArrayList();
				refList.add(ref);
				CanonicalizationMethod cm =  fac.newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE,(C14NMethodParameterSpec) null);
				SignatureMethod sm = fac.newSignatureMethod("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",null);
				SignedInfo signedInfo =fac.newSignedInfo(cm,sm,refList);
				DOMSignContext signContext = null;
				signContext = new DOMSignContext(securityProvider.getSigningKey(),doc.getDocumentElement());

				signContext.setIdAttributeNS(doc.getDocumentElement(), null, "ID");
				
				KeyInfoFactory kif = KeyInfoFactory.getInstance("DOM",new org.apache.jcp.xml.dsig.internal.dom.XMLDSigRI());
				List certs = new ArrayList();
				X509Certificate cert = securityProvider.getSigningCertificate();
				certs.add(cert);
				X509Data x509Data = kif.newX509Data(certs);
				KeyInfo ki = kif.newKeyInfo(Collections.singletonList(x509Data)); 

				XMLSignature signature = fac.newXMLSignature(signedInfo,ki);
				signature.sign(signContext);

				org.w3c.dom.Node signatureElement = doc.getElementsByTagName("Signature").item(0);
				signatureElement.setPrefix("ds");
			}
			TransformerFactory tf = TransformerFactory.newInstance();
			Transformer transformer = tf.newTransformer();
			StringWriter writer = new StringWriter();
			transformer.transform(new DOMSource(doc), new StreamResult(writer));
			String output = writer.getBuffer().toString();	
			return output.getBytes("UTF-8");
		}catch (MessageProcessingException e) {
			throw new MessageException("Error marshalling PKI Message, " + e.getMessage(),e);
		}  catch (JAXBException e) {
			throw new MessageException("Error marshalling PKI Message, " + e.getMessage(),e);
		} catch (ParserConfigurationException e) {
			throw new MessageException("Error marshalling PKI Message, " + e.getMessage(),e);
		} catch (UnsupportedEncodingException e) {
			throw new MessageException("Error marshalling PKI Message, " + e.getMessage(),e);
		} catch (TransformerException e) {
			throw new MessageException("Error marshalling PKI Message, " + e.getMessage(),e);
		} catch (NoSuchAlgorithmException e) {
			throw new MessageException("Error signing the PKI Message, " + e.getMessage(),e);
		} catch (InvalidAlgorithmParameterException e) {
			throw new MessageException("Error signing the PKI Message, " + e.getMessage(),e);
		} catch (MarshalException e) {
			throw new MessageException("Error signing the PKI Message, " + e.getMessage(),e);
		} catch (XMLSignatureException e) {
			throw new MessageException("Error signing the PKI Message, " + e.getMessage(),e);
		}
	}
	

	private DocumentBuilder getDocumentBuilder() throws ParserConfigurationException {
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		dbf.setNamespaceAware(true);

		return dbf.newDocumentBuilder();
	}
	
	
	private Boolean signMessages;
	private boolean signMessages() throws MessageException{
		if(signMessages == null){
			signMessages = PKISettingsUtils.parseBooleanWithDefault(properties, SETTING_SIGN, true);
		}
		return signMessages;
	}
	
	private Boolean requireSignature;
	private boolean requireSignature() throws MessageException{
		if(requireSignature == null){
			requireSignature = PKISettingsUtils.parseBooleanWithDefault(properties, SETTING_REQUIRESIGNATURE, true);
		}
		return requireSignature;
	}

	/**
	 * Help method that sets status to success and the in response to ID.
	 * @param response the response object to populate
	 * @param request the related request.
	 */
	private void populateSuccessfulResponse(
			PKIResponse response, PKIMessage request) {
		response.setFailureMessage(null);
		response.setStatus(RequestStatus.SUCCESS);
		response.setInResponseTo(request.getID());		
	}


	/**
	 * Method that generates a configured message name catalogue or uses the default
	 * one if not configured
	 * @param config the configuration.
	 * @return a newly generated MessageNameCatalogue
	 * @throws MessageException if problems occurred generating a MessageNameCatalogue
	 */
    private MessageNameCatalogue getMessageNameCatalogue(Properties config) throws MessageException{
    	try{
    		MessageNameCatalogue retval =  (MessageNameCatalogue) this.getClass().getClassLoader().loadClass(config.getProperty(SETTING_MESSAGE_NAME_CATALOGUE_IMPL, DEFAULT_MESSAGE_NAME_CATALOGUE_IMPL)).newInstance();
    		retval.init(config);
    		return retval;
    	}catch(Exception e){
    		throw new MessageException("Error creating creating name catalogue " + e.getClass().getName() + ": " + e.getMessage());
    	}
    }
    
    /**
     * Method that tries to parse the xml version from a message
     * @param messageData the messageData to extract version from.
     * @return the version in the version attribute of the message.
     * @throws IllegalArgumentException didn't contains a valid version attribute.
     * @throws MessageException if internal problems occurred.
     */
    private String getVersionFromMessage(byte[] messageData) throws IllegalArgumentException, MessageException{
    	String retval=null;
    	try{
    		Document doc = getDocumentBuilder().parse(new ByteArrayInputStream(messageData));
    		
    		Node pkiMessage = doc.getFirstChild();
    		if(pkiMessage != null){
    			Node versionNode = pkiMessage.getAttributes().getNamedItem("version");
    			if(versionNode != null){
    				retval = versionNode.getNodeValue();
    			}
    		}    		

    	}catch(Exception e){
    		throw new IllegalArgumentException("Error parsing XML data: " + e.getMessage(),e);
    	}

    	if(retval == null || retval.trim().equals("")){
    	  throw new IllegalArgumentException("Error no version attribute found in PKI Message.");
    	}
    	return retval;
    }
    
    /**
     * Method that returns a marshaller for a given version,
     * @param version the version of the PKI Message protocol to fetch.
     * @return related marshaller
     * @throws MessageException if problems occurred creating the PKI Message Marshaller for the given version.
     */
    private Marshaller getPKIMessageMarshaller(String version) throws MessageException{
    	if(version == null){
    		throw new IllegalArgumentException("Invalid PKI Message, version is missing.");
    	}
    	
    	Marshaller retval = pkixMessageMarshallers.get(version);
    	if(retval == null){
    		String schemaURL = pkiMessageSchemaUriMap.get(version);
    		try{
    			retval = createMarshaller(getJAXBContext(), schemaURL);
    			retval.setSchema(generatePKIMessageSchema(version)); 
    			pkixMessageMarshallers.put(version, retval);
    		}catch(Exception e){
    			throw new MessageException("Error creating XML Marshaller for PKI Message version: " + version, e);
    		}
    	}
    	return retval;
    	
    }
    
	public static Credential getOriginatorFromRequest(PKIMessage request) {
		Credential retval = null;
		if(request!= null && request.getOriginator() != null){
			retval = request.getOriginator().getCredential();
		}
		return retval;
	}
    
    /**
     * Method that returns a unmarshaller for a given version,
     * @param version the version of the PKI Message protocol to fetch.
     * @return related unmarshaller
     * @throws MessageException if problems occurred creating the PKI Message Marshaller for the given version.
     */
    private Unmarshaller getPKIMessageUnmarshaller(String version) throws MessageException{
    	if(version == null){
    		throw new IllegalArgumentException("Invalid PKI Message, version is missing.");
    	}
    	
    	Unmarshaller retval = pkixMessageUnmarshallers.get(version);
    	if(retval == null){
    		try{
    			retval = jaxbContext.createUnmarshaller();
    			retval.setSchema(generatePKIMessageSchema(version));
    			pkixMessageUnmarshallers.put(version, retval);
    		}catch(Exception e){
    			throw new MessageException("Error creating XML Unmarshaller for PKI Message version: " + version);
    		}
    	}
    	return retval;
    	
    }
    
    /**
     * Help method to generate a PKIMessage Schema for a given version.
     * @param version the version to look up.
     * @return
     * @throws IllegalArgumentException
     * @throws SAXException
     * @throws MessageException
     */
    private Schema generatePKIMessageSchema(String version) throws IllegalArgumentException, SAXException, MessageException{
    	String schemaLocation = pkiMessageSchemaMap.get(version);
		URL xsdURL = getClass().getResource(schemaLocation);
		SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
		URL xsdURL2 = getClass().getResource(XMLDSIG_XSD_SCHEMA_RESOURCE_LOCATION);
		String xsdContent = null;
		try {		
			InputStream resourceAsStream = xsdURL2.openStream();
			synchronized (resourceAsStream) {
				byte[] i = new byte[resourceAsStream.available()];
				resourceAsStream.read(i);
				xsdContent = new String(i);
			}
		} catch (IOException e) {
			throw new MessageException("Error reading DigSig XSD config");
		}
	    final String digSigXSD = xsdContent;
	    // A Custom resolver for the dig-sig XSD to avoid time-out resolving external resources using HTTP.
        schemaFactory.setResourceResolver(new LSResourceResolver() {
			
			
			public LSInput resolveResource(String type,
                    String namespaceURI,
                    String publicId,
                    String systemId,
                    String baseURI) {
				if(systemId.contains("xmldsig-core-schema.xsd")){						
					return new XSDLSInput(publicId, systemId, digSigXSD);
				}
				
				return null;
			}
		});        
        Schema schema = schemaFactory.newSchema(xsdURL);
        
        return schema;
    }
    
    /**
     * Help method maintaining the PKI Message JAXB Context.
     */
    private JAXBContext jaxbContext = null;
    private JAXBContext getJAXBContext() throws JAXBException{
    	if(jaxbContext== null){
    		jaxbContext = JAXBContext.newInstance("org.certificateservices.messages.pkimessages.jaxb");
    	}
    	return jaxbContext;
    }
    

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy