/* * Copyright 2003 Federal Chancellery Austria * MOA-SPSS has been developed in a cooperation between BRZ, the Federal * Chancellery Austria - ICT staff unit, and Graz University of Technology. * * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. */ package at.gv.egovernment.moa.spss.server.invoke; import iaik.server.modules.algorithms.HashAlgorithms; import iaik.server.modules.keys.KeyEntryID; import iaik.server.modules.keys.KeyModule; import iaik.server.modules.keys.KeyModuleFactory; import iaik.server.modules.xml.Canonicalization; import iaik.server.modules.xmlsign.SignatureStructureTypes; import iaik.server.modules.xmlsign.XMLSignatureCreationProfile; import iaik.server.modules.xmlsign.XMLSignatureInsertionLocation; import java.math.BigInteger; import java.security.Principal; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import at.gv.egovernment.moa.spss.MOAApplicationException; import at.gv.egovernment.moa.spss.MOASystemException; import at.gv.egovernment.moa.spss.api.common.XMLDataObjectAssociation; import at.gv.egovernment.moa.spss.api.xmlsign.CreateSignatureEnvironmentProfileExplicit; import at.gv.egovernment.moa.spss.api.xmlsign.CreateSignatureInfo; import at.gv.egovernment.moa.spss.api.xmlsign.CreateTransformsInfoProfileExplicit; import at.gv.egovernment.moa.spss.api.xmlsign.CreateXMLSignatureRequest; import at.gv.egovernment.moa.spss.api.xmlsign.DataObjectInfo; import at.gv.egovernment.moa.spss.api.xmlsign.SingleSignatureInfo; import at.gv.egovernment.moa.spss.server.config.ConfigurationProvider; import at.gv.egovernment.moa.spss.server.config.KeyGroup; import at.gv.egovernment.moa.spss.server.config.KeyGroupEntry; import at.gv.egovernment.moa.spss.server.iaik.xml.CanonicalizationImpl; import at.gv.egovernment.moa.spss.server.iaik.xml.ExclusiveCanonicalizationImpl; import at.gv.egovernment.moa.spss.server.iaik.xmlsign.DataObjectTreatmentImpl; import at.gv.egovernment.moa.spss.server.iaik.xmlsign.XMLSignatureCreationProfileImpl; import at.gv.egovernment.moa.spss.server.iaik.xmlsign.XMLSignatureInsertionLocationImpl; import at.gv.egovernment.moa.spss.server.logging.TransactionId; import at.gv.egovernment.moa.spss.server.transaction.TransactionContext; import at.gv.egovernment.moa.spss.server.transaction.TransactionContextManager; import at.gv.egovernment.moa.spss.server.util.IdGenerator; import at.gv.egovernment.moa.spss.util.MessageProvider; import at.gv.egovernment.moaspss.logging.LogMsg; import at.gv.egovernment.moaspss.logging.Logger; import at.gv.egovernment.moaspss.util.Constants; /** * A factory to create XMLSignatureCreationProfiles from a * CreateXMLSignatureRequest, based on the current MOA * configuration. * * @author Patrick Peck * @version $Id$ */ public class XMLSignatureCreationProfileFactory { private static Map HASH_ALGORITHM_MAPPING; static { HASH_ALGORITHM_MAPPING = new HashMap(); HASH_ALGORITHM_MAPPING.put(Constants.SHA1_URI, HashAlgorithms.SHA1); HASH_ALGORITHM_MAPPING.put(Constants.SHA256_URI, HashAlgorithms.SHA256); HASH_ALGORITHM_MAPPING.put(Constants.SHA384_URI, HashAlgorithms.SHA384); HASH_ALGORITHM_MAPPING.put(Constants.SHA512_URI, HashAlgorithms.SHA512); } /** The CreateXMLSignatureRequest for which to create the * profile.*/ private CreateXMLSignatureRequest request; /** How many profiles have been created based on the same request. */ private int createProfileCount; /** The Set of reserved object IDs.*/ private Set reserved; /** * Create a new XMLSignatureCreationProfileFactory. * * @param request The request for which to create profiles. * @param reserved The Set of reserved object IDs. IDs will * be added during signature creation. */ public XMLSignatureCreationProfileFactory( CreateXMLSignatureRequest request, Set reserved) { this.request = request; this.reserved = reserved; createProfileCount = 1; } /** * Create a XMLSignatureCreationProfile for the given * SingleSignatureInfo object.. * * @param singleSignatureInfo The SingleSignatureInfo object * containing information about the creation of a signature. * @param sigInfoReservedIDs The Set of reserved ID attribue values * for the particular singleSignatureInfo. * @return The XMLSignatureCreationProfile containing additional * information for creating an XML signature. * @throws MOASystemException A system error occurred during creation of the * profile. See message for details * @throws MOAApplicationException An application error occurred during * creation of the profile. See message for details. */ public XMLSignatureCreationProfile createProfile(SingleSignatureInfo singleSignatureInfo, Set sigInfoReservedIDs) throws MOASystemException, MOAApplicationException { HashSet allReservedIDs = new HashSet(reserved); allReservedIDs.addAll(sigInfoReservedIDs); TransactionContext context = TransactionContextManager.getInstance().getTransactionContext(); ConfigurationProvider config = context.getConfiguration(); List dataObjectTreatmentList; Set keySet; List transformationSupplements; List createTransformsProfiles; // get the key group id String keyGroupID = request.getKeyIdentifier(); // get digest method on key group level (if configured) KeyGroup keygroup = config.getKeyGroup(keyGroupID); if(null == keygroup) { Logger.error("Could not find key group '" + keyGroupID + "'"); throw new MOAApplicationException("2231", null); } String configDigestMethodKG = keygroup.getDigestMethodAlgorithm(); // get default digest method (if configured) String configDigestMethod = config.getDigestMethodAlgorithmName(); String xadesVersion = config.getXAdESVersion(); String digestMethodXAdES142 = null; boolean isXAdES142 = false; // if XAdES Version 1.4.2 is configured if (xadesVersion != null && xadesVersion.compareTo("1.4.2") == 0) { isXAdES142 = true; Logger.debug("XAdES version '" + xadesVersion + "' used"); } if (isXAdES142) { if (configDigestMethodKG != null) { // if KG specific digest method is configured digestMethodXAdES142 = (String) HASH_ALGORITHM_MAPPING.get(configDigestMethodKG); if (digestMethodXAdES142 == null) { error( "config.17", new Object[] { configDigestMethodKG}); throw new MOASystemException("2900", null); } Logger.debug("Digest algorithm: " + digestMethodXAdES142 + "(configured in KeyGroup)"); } else { // else get default configured digest method digestMethodXAdES142 = (String) HASH_ALGORITHM_MAPPING.get(configDigestMethod); if (digestMethodXAdES142 == null) { error( "config.17", new Object[] { configDigestMethod}); throw new MOASystemException("2900", null); } Logger.debug("Digest algorithm: " + digestMethodXAdES142 + "(default)"); } } XMLSignatureCreationProfileImpl profile = new XMLSignatureCreationProfileImpl(createProfileCount, allReservedIDs, digestMethodXAdES142); // build the transformation supplements createTransformsProfiles = getCreateTransformsInfoProfiles(singleSignatureInfo); transformationSupplements = buildTransformationSupplements(createTransformsProfiles); // build and set the data object treatment list dataObjectTreatmentList = buildDataObjectTreatmentList( singleSignatureInfo, createTransformsProfiles, transformationSupplements, allReservedIDs, digestMethodXAdES142); profile.setDataObjectTreatmentList(dataObjectTreatmentList); // set the key set keySet = buildKeySet(keyGroupID); if (keySet == null) { throw new MOAApplicationException("2231", null); } else if (keySet.size() == 0) { throw new MOAApplicationException("2232", null); } profile.setKeySet(keySet); // set the Security Layer manifest algorithm name profile.setSecurityLayerManifestTypeURI(Constants.SL_MANIFEST_TYPE_URI); // set the structure type if (singleSignatureInfo.getCreateSignatureInfo() != null) { profile.setSignatureStructureType(SignatureStructureTypes.ENVELOPED); } else { profile.setSignatureStructureType(SignatureStructureTypes.DETACHED); } // set insertion location profile.setSignatureInsertionLocation( getSignatureInsertionLocationIndex(singleSignatureInfo)); // set the canonicalization algorithm String canonicalizationURI = config.getCanonicalizationAlgorithmName(); if (Canonicalization.ALL_EXCLUSIVE.contains(canonicalizationURI)) { ExclusiveCanonicalizationImpl canonicalization = new ExclusiveCanonicalizationImpl(config.getCanonicalizationAlgorithmName(), null); profile.setSignedInfoCanonicalization(canonicalization); } else { CanonicalizationImpl canonicalization = new CanonicalizationImpl(config.getCanonicalizationAlgorithmName()); profile.setSignedInfoCanonicalization(canonicalization); } // set the signed properties profile.setSignedProperties(Collections.EMPTY_LIST); // set security layer conformity profile.setSecurityLayerConform( singleSignatureInfo.isSecurityLayerConform()); // update the createProfileCount createProfileCount++; return profile; } /** * Get the List of all CreateTransformsInfoProfiles * contained in all the DataObjectInfos of the given * SingleSignatureInfo. * * @param singleSignatureInfo The SingleSignatureInfo object from * which to extract the CreateTransformsInfoProfiles. * @return All CreateTransformsInfoProfiles of all * DataObjectInfos of singleSignatureInfo. * @throws MOAApplicationException An error occurred creating one of the * profiles. */ List getCreateTransformsInfoProfiles(SingleSignatureInfo singleSignatureInfo) throws MOAApplicationException { TransactionContext context = TransactionContextManager.getInstance().getTransactionContext(); ConfigurationProvider config = context.getConfiguration(); List dataObjInfos = singleSignatureInfo.getDataObjectInfos(); List profiles = new ArrayList(); Iterator dtIter; for (dtIter = dataObjInfos.iterator(); dtIter.hasNext();) { DataObjectInfo dataObjInfo = (DataObjectInfo) dtIter.next(); CreateTransformsInfoProfileExplicit profile = ProfileMapper.mapCreateTransformsInfoProfile( dataObjInfo.getCreateTransformsInfoProfile(), config); profiles.add(profile); } return profiles; } /** * Build the List of transformation supplements contained in a * SingleSignatureInfo object. * * @param createTransformsInfoProfiles The * CreateTransformsInfoProfile object from which to extract the * transformation supplements. * @return A List of DataObjects containing the * transformation supplements. * @throws MOASystemException A system error occurred creating one of the * transformation supplements. * @throws MOAApplicationException An error occurred creating one of the * transformation supplements. */ private List buildTransformationSupplements(List createTransformsInfoProfiles) throws MOASystemException, MOAApplicationException { List transformationSupplements = new ArrayList(); DataObjectFactory factory = DataObjectFactory.getInstance(); Iterator iter; for (iter = createTransformsInfoProfiles.iterator(); iter.hasNext();) { CreateTransformsInfoProfileExplicit profile = (CreateTransformsInfoProfileExplicit) iter.next(); List supplements = profile.getSupplements(); if (supplements != null) { Iterator supplIter; for (supplIter = supplements.iterator(); supplIter.hasNext();) { XMLDataObjectAssociation supplement = (XMLDataObjectAssociation) supplIter.next(); transformationSupplements.add( factory.createFromXmlDataObjectAssociation( supplement, false, true)); } } } return transformationSupplements; } /** * Build the List of DataObjectTreatments for the * given SingleSignatureInfo object.. * * @param singleSignatureInfo The SingleSignatureInfo object * from which to exctract the CreateTransformsInfoProfiles * containing the data for the DataObjectTreatments. * @param createTransformsInfoProfiles The * CreateTransformsInfoProfiles contained in the * singleSignatureInfo. * @param transformationSupplements Additional parameters for * transformations contained in DataObjectTreatments. * @param reservedIDs The Set of reserved object IDs. * @return A List of DataObjectTreatment objects. * @throws MOAApplicationException An error occurred building one of the * DataObjectTreatments. * @throws MOASystemException A system error occurred building one of the * DataObjectTreatments. */ private List buildDataObjectTreatmentList( SingleSignatureInfo singleSignatureInfo, List createTransformsInfoProfiles, List transformationSupplements, Set reservedIDs, String digestMethodXAdES142) throws MOASystemException, MOAApplicationException { TransactionContext context = TransactionContextManager.getInstance().getTransactionContext(); ConfigurationProvider config = context.getConfiguration(); List treatments = new ArrayList(); List dataObjInfos = singleSignatureInfo.getDataObjectInfos(); int dataObjectTreatmentCount = 1; String hashAlgorithmName; Iterator dtIter; Iterator prIter; prIter = createTransformsInfoProfiles.iterator(); for (dtIter = dataObjInfos.iterator(); dtIter.hasNext();) { CreateTransformsInfoProfileExplicit profile = (CreateTransformsInfoProfileExplicit) prIter.next(); DataObjectInfo dataObjInfo = (DataObjectInfo) dtIter.next(); IdGenerator objIdGen = new IdGenerator( ("signed-data-" + createProfileCount) + ("-" + dataObjectTreatmentCount++), reservedIDs); DataObjectTreatmentImpl treatment = new DataObjectTreatmentImpl(objIdGen); treatment.setFinalContentType( profile.getCreateTransformsInfo().getFinalDataMetaInfo().getMimeType()); treatment.setTransformationList(buildTransformationList(profile)); treatment.setReferenceInManifest(dataObjInfo.isChildOfManifest()); // if XAdES version is 1.4.2 if (digestMethodXAdES142 != null) { // use configured digest algorithm hashAlgorithmName = digestMethodXAdES142; } else { // stay as it is hashAlgorithmName = (String) HASH_ALGORITHM_MAPPING.get( config.getDigestMethodAlgorithmName()); if (hashAlgorithmName == null) { error( "config.17", new Object[] { config.getDigestMethodAlgorithmName()}); throw new MOASystemException("2900", null); } } treatment.setHashAlgorithmName(hashAlgorithmName); treatment.setIncludedInSignature( DataObjectInfo.STRUCTURE_ENVELOPING.equals(dataObjInfo.getStructure())); treatment.setTransformationSupplements(transformationSupplements); treatments.add(treatment); } return treatments; } /** * Build the List of transformations contained in a * CreateTransformsInfoProfile object. * * @param profile The CreateTransformsInfoProfile object * from which to extract the Transforms. * @return A List of Transformations contained in * the given CreateTransformsInfoProfile. * @throws MOAApplicationException An error occurred building one of the * Transformations. */ private List buildTransformationList(CreateTransformsInfoProfileExplicit profile) throws MOAApplicationException { TransformationFactory factory = TransformationFactory.getInstance(); List transforms = profile.getCreateTransformsInfo().getTransforms(); return transforms != null ? factory.createTransformationList(transforms) : Collections.EMPTY_LIST; } /** * Build the set of KeyEntryIDs available to the given * keyGroupID. * * @param keyGroupID The keygroup ID for which the available keys should be * returned. * @return The Set of KeyEntryIDs * identifying the available keys. */ private Set buildKeySet(String keyGroupID) { TransactionContext context = TransactionContextManager.getInstance().getTransactionContext(); ConfigurationProvider config = context.getConfiguration(); Set keyGroupEntries; // get the KeyGroup entries from the configuration if (context.getClientCertificate() != null) { X509Certificate cert = context.getClientCertificate()[0]; Principal issuer = cert.getIssuerDN(); BigInteger serialNumber = cert.getSerialNumber(); keyGroupEntries = config.getKeyGroupEntries(issuer, serialNumber, keyGroupID); } else { keyGroupEntries = config.getKeyGroupEntries(null, null, keyGroupID); } // map the KeyGroup entries to a set of KeyEntryIDs if (keyGroupEntries == null) { return null; } else if (keyGroupEntries.size() == 0) { return Collections.EMPTY_SET; } else { KeyModule module = KeyModuleFactory.getInstance( new TransactionId(context.getTransactionID())); Set keyEntryIDs = module.getPrivateKeyEntryIDs(); Set keySet = new HashSet(); Iterator iter; // filter out the keys that do not exist in the IAIK configuration // by walking through the key entries and checking if the exist in the // keyGroupEntries for (iter = keyEntryIDs.iterator(); iter.hasNext();) { KeyEntryID entryID = (KeyEntryID) iter.next(); KeyGroupEntry entry = new KeyGroupEntry( entryID.getModuleID(), entryID.getCertificateIssuer(), entryID.getCertificateSerialNumber()); if (keyGroupEntries.contains(entry)) { keySet.add(entryID); } } return keySet; } } /** * Get the signature location index where the signature will be inserted into * the signature parent element. * * @param singleSignatureInfo The SingleSignatureInfo object * containing the CreateSignatureLocation. * @return The index at which to insert the signature into the signature * environment. * @throws MOAApplicationException An error occurred parsing the * CreateSignatureEnvironmentProfile. */ private XMLSignatureInsertionLocation getSignatureInsertionLocationIndex(SingleSignatureInfo singleSignatureInfo) throws MOAApplicationException { CreateSignatureInfo createInfo = singleSignatureInfo.getCreateSignatureInfo(); if (createInfo != null) { TransactionContext context = TransactionContextManager.getInstance().getTransactionContext(); ConfigurationProvider config = context.getConfiguration(); CreateSignatureEnvironmentProfileExplicit profile = ProfileMapper.mapCreateSignatureEnvironmentProfile( createInfo.getCreateSignatureEnvironmentProfile(), config); int index = profile.getCreateSignatureLocation().getIndex(); return new XMLSignatureInsertionLocationImpl(index); } else { return new XMLSignatureInsertionLocationImpl(0); } } /** * Utility function to issue an error message to the log. * * @param messageId The ID of the message to log. * @param parameters Additional message parameters. */ private static void error(String messageId, Object[] parameters) { MessageProvider msg = MessageProvider.getInstance(); Logger.error(new LogMsg(msg.getMessage(messageId, parameters))); } }