/* * 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.config; import iaik.asn1.structures.Name; //import iaik.ixsil.exceptions.URIException; //import iaik.ixsil.util.URI; import iaik.pki.pathvalidation.ChainingModes; import iaik.pki.revocation.RevocationSourceTypes; import iaik.server.modules.xml.BlackListEntry; import iaik.server.modules.xml.ExternalReferenceChecker; import iaik.server.modules.xml.WhiteListEntry; import iaik.utils.RFC2253NameParser; import iaik.utils.RFC2253NameParserException; import iaik.xml.crypto.utils.URI; import iaik.xml.crypto.utils.URIException; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.security.Principal; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; 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 javax.xml.bind.DatatypeConverter; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.traversal.NodeIterator; import org.xml.sax.SAXException; import at.gv.egovernment.moa.spss.api.common.TSLConfiguration; import at.gv.egovernment.moa.spss.api.impl.TSLConfigurationImpl; 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; import at.gv.egovernment.moaspss.util.DOMUtils; import at.gv.egovernment.moaspss.util.FileUtils; import at.gv.egovernment.moaspss.util.MiscUtil; import at.gv.egovernment.moaspss.util.StringUtils; import at.gv.egovernment.moaspss.util.XPathUtils; /** * A class that builds configuration data from a DOM based representation. * * @author Patrick Peck * @version $Id$ */ public class ConfigurationPartsBuilder { // // XPath namespace prefix shortcuts // private static final String CONF = Constants.MOA_CONFIG_PREFIX + ":"; private static final String DSIG = Constants.DSIG_PREFIX + ":"; // // chaining mode constants appearing in the configuration file // private static final String CM_CHAINING = "chaining"; private static final String CM_PKIX = "pkix"; // // XPath expressions to select certain parts of the configuration // private static final String ROOT = "/" + CONF + "MOAConfiguration/"; private static final String PDFAS_CONFIGURATION_XPATH = ROOT + CONF + "Common/" + CONF + "PDFASConfig"; private static final String FORMRESULT_CONFIGURATION_XPATH = ROOT + CONF + "Common/" + CONF + "AdESFormResult"; private static final String DIGEST_METHOD_XPATH = ROOT + CONF + "SignatureCreation/" + CONF + "XMLDSig/" + CONF + "DigestMethodAlgorithm"; private static final String XADES_VERSION_XPATH = ROOT + CONF + "SignatureCreation/" + CONF + "XAdES/" + CONF + "Version"; private static final String C14N_ALGORITHM_XPATH = ROOT + CONF + "SignatureCreation/" + CONF + "XMLDSig/" + CONF + "CanonicalizationAlgorithm"; private static final String HARDWARE_CRYPTO_MODULE_XPATH = ROOT + CONF + "Common/" + CONF + "HardwareCryptoModule"; private static final String PERMIT_EXTERNAL_URIS_XPATH = ROOT + CONF + "Common/" + CONF + "PermitExternalUris"; private static final String BLACK_LIST_URIS_XPATH = ROOT + CONF + "Common/" + CONF + "PermitExternalUris/" + CONF + "BlackListUri"; private static final String FORBID_EXTERNAL_URIS_XPATH = ROOT + CONF + "Common/" + CONF + "ForbidExternalUris"; private static final String WHITE_LIST_URIS_XPATH = ROOT + CONF + "Common/" + CONF + "ForbidExternalUris/" + CONF + "WhiteListUri"; private static final String HARDWARE_KEY_XPATH = ROOT + CONF + "SignatureCreation/" + CONF + "KeyModules/" + CONF + "HardwareKeyModule"; private static final String SOFTWARE_KEY_XPATH = ROOT + CONF + "SignatureCreation/" + CONF + "KeyModules/" + CONF + "SoftwareKeyModule"; private static final String KEYGROUP_XPATH = ROOT + CONF + "SignatureCreation/" + CONF + "KeyGroup"; private static final String KEYGROUP_MAPPING_XPATH = ROOT + CONF + "SignatureCreation/" + CONF + "KeyGroupMapping"; private static final String ISSUER_XPATH = DSIG + "X509IssuerName"; private static final String SERIAL_XPATH = DSIG + "X509SerialNumber"; private static final String CERTSTORE_LOCATION_XPATH = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "PathConstruction/" + CONF + "CertificateStore/" + CONF + "DirectoryStore/" + CONF + "Location"; private static final String AUTO_ADD_CERTIFICATES_XPATH_ = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "PathConstruction/" + CONF + "AutoAddCertificates"; private static final String AUTO_ADD_EE_CERTIFICATES_XPATH_ = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "PathConstruction/" + CONF + "AutoAddEECertificates"; private static final String USE_AUTHORITY_INFO_ACCESS_XPATH_ = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "PathConstruction/" + CONF + "UseAuthorityInformationAccess"; private static final String CHAINING_MODES_XPATH = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "PathValidation/" + CONF + "ChainingMode"; private static final String CHAINING_MODES_DEFAULT_XPATH = CHAINING_MODES_XPATH + "/" + CONF + "DefaultMode"; private static final String TRUST_ANCHOR_XPATH = CHAINING_MODES_XPATH + "/" + CONF + "TrustAnchor"; private static final String TRUST_PROFILE_XPATH = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "PathValidation/" + CONF + "TrustProfile"; private static final String DISTRIBUTION_POINTS_XPATH = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "RevocationChecking/" + CONF + "DistributionPoint"; private static final String CRL_RETENTION_INTERVALS_CA_XPATH = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "RevocationChecking/" + CONF + "CrlRetentionIntervals/" + CONF + "CA"; private static final String ENABLE_REVOCATION_CHECKING_XPATH_ = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "RevocationChecking/" + CONF + "EnableChecking"; private static final String MAX_REVOCATION_AGE_XPATH_ = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "RevocationChecking/" + CONF + "MaxRevocationAge"; private static final String REVOCATION_SERVICEORDER_XPATH_ = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "RevocationChecking/" + CONF + "ServiceOrder/" + CONF + "Service"; private static final String ENABLE_ARCHIVING_XPATH = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "RevocationChecking/" + CONF + "Archiving/" + CONF + "EnableArchiving"; private static final String CRL_ARCHIVE_DURATION_XPATH = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "RevocationChecking/" + CONF + "Archiving/" + CONF + "ArchiveDuration"; private static final String ACHIVE_JDBC_URL_ = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "RevocationChecking/" + CONF + "Archiving/" + CONF + "Archive/" + CONF + "DatabaseArchive/" + CONF + "JDBCURL"; private static final String ACHIVE_JDBC_DRIVER_CLASS_ = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "RevocationChecking/" + CONF + "Archiving/" + CONF + "Archive/" + CONF + "DatabaseArchive/" + CONF + "JDBCDriverClassName"; private static final String CREATE_TRANSFORMS_INFO_PROFILE_XPATH = ROOT + CONF + "SignatureCreation/" + CONF + "CreateTransformsInfoProfile"; private static final String CREATE_SIGNATURE_ENVIRONMENT_PROFILE_XPATH = ROOT + CONF + "SignatureCreation/" + CONF + "CreateSignatureEnvironmentProfile"; private static final String VERIFY_TRANSFORMS_INFO_PROFILE_XPATH = ROOT + CONF + "SignatureVerification/" + CONF + "VerifyTransformsInfoProfile"; private static final String SUPPLEMENT_PROFILE_XPATH = ROOT + CONF + "SignatureVerification/" + CONF + "SupplementProfile"; private static final String PERMIT_FILE_URIS_XPATH = ROOT + CONF + "SignatureVerification/" + CONF + "PermitFileURIs"; private static final String CONNECTION_TIMEOUT_XPATH_ = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "ConnectionTimeout"; private static final String READ_TIMEOUT_XPATH_ = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "ReadTimeout"; private static final String TSL_CONFIGURATION_XPATH = ROOT + CONF + "SignatureVerification/" + CONF + "CertificateValidation/" + CONF + "TSLConfiguration/"; // // default values for configuration parameters // /** The accepted canonicalization algorithm URIs, as an array */ private static final String[] ACCEPTED_C14N_ALGORITHMS_ARRAY = { Constants.C14N_URI, Constants.C14N_WITH_COMMENTS_URI, Constants.EXC_C14N_URI, Constants.EXC_C14N_WITH_COMMENTS_URI }; /** The accepted canonicalization algorithm URIs, as a Set */ private static final Set ACCEPTED_C14N_ALGORITHMS = new HashSet(Arrays.asList(ACCEPTED_C14N_ALGORITHMS_ARRAY)); /** Default canonicalization algorithm, if none/illegal has been configured */ private static final String C14N_ALGORITHM_DEFAULT = Constants.C14N_URI; /** The accepted digest method algorithm URIs, as an array */ private static final String[] ACCEPTED_DIGEST_ALGORITHMS_ARRAY = { Constants.SHA1_URI, Constants.SHA256_URI, Constants.SHA384_URI, Constants.SHA512_URI}; /** The accepted digest method algorithm URIs, as a Set */ private static final Set ACCEPTED_DIGEST_ALGORITHMS = new HashSet(Arrays.asList(ACCEPTED_DIGEST_ALGORITHMS_ARRAY)); /** Default digest algorithm URI, if none/illegal has been configured (for XAdES 1.1.1) */ private static final String DIGEST_ALGORITHM_DEFAULT_XADES_1_1_1 = Constants.SHA1_URI; /** Default digest algorithm URI, if none/illegal has been configured (for XAdES 1.4.2) */ private static final String DIGEST_ALGORITHM_DEFAULT_XADES_1_4_2 = Constants.SHA256_URI; /** The root element of the MOA configuration */ private Element configElem; /** * The directory containing the underlying configuration file. */ private File configRoot_; /** Whether any warnings were encountered building the configuration. */ private List warnings = new ArrayList(); /** * Create a new ConfigurationPartsBuilder. * * @param configElem The root element of the MOA configuration. * * @param configRoot The directory containing the underlying configuration file. */ public ConfigurationPartsBuilder(Element configElem, File configRoot) { this.configElem = configElem; configRoot_ = configRoot; } /** * Returns the root element of the MOA configuration. * * @return The root element of the MOA configuration. */ public Element getConfigElem() { return configElem; } /** * Returns the directory containing the underlying configuration file. * * @return the directory containing the underlying configuration file. */ public File getConfigRoot() { return configRoot_; } /** * Returns the warnings encountered during building the configuration. * * @return A List of Strings, containing the * warning messages. */ public List getWarnings() { return warnings; } /** * Returns the digest method algorithm name. * * @return The digest method algorithm name from the configuration. */ public String getDigestMethodAlgorithmName() { String digestMethod = getElementValue(getConfigElem(), DIGEST_METHOD_XPATH, null); if (digestMethod == null || !ACCEPTED_DIGEST_ALGORITHMS.contains(digestMethod)) { String xadesVersion = this.getXAdESVersion(); if (xadesVersion == null) { info( "config.23", new Object[] { "DigestMethodAlgorithm", DIGEST_ALGORITHM_DEFAULT_XADES_1_1_1 }); digestMethod = DIGEST_ALGORITHM_DEFAULT_XADES_1_1_1; } else { info( "config.23", new Object[] { "DigestMethodAlgorithm", DIGEST_ALGORITHM_DEFAULT_XADES_1_4_2 }); digestMethod = DIGEST_ALGORITHM_DEFAULT_XADES_1_4_2; } } return digestMethod; } /** * Returns the digest method algorithm name. * * @return The digest method algorithm name from the configuration. */ public String getXAdESVersion() { String xadesVersion = getElementValue(getConfigElem(), XADES_VERSION_XPATH, null); return xadesVersion; } /** * Returns the digest method algorithm name. * * @return The digest method algorithm name from the configuration. */ public String getPDFASConfiguration() { String pdfasConfiguration = getElementValue(getConfigElem(), PDFAS_CONFIGURATION_XPATH, null); return pdfasConfiguration; } /** * Returns the digest method algorithm name. * * @return The digest method algorithm name from the configuration. */ public int getConnectionTimeout() { String connectionTimeout = getElementValue(getConfigElem(), CONNECTION_TIMEOUT_XPATH_, "30"); int defaultConnectionTimeout = 30; if(connectionTimeout != null) { try { defaultConnectionTimeout = Integer.parseInt(connectionTimeout); } catch(NumberFormatException e) { Logger.warn("Configuration value " + CONNECTION_TIMEOUT_XPATH_ + " should be a number defaulting to 30"); } } if(defaultConnectionTimeout < 0) { defaultConnectionTimeout = 30; } return defaultConnectionTimeout * 1000; } public int getReadTimeout() { String connectionTimeout = getElementValue(getConfigElem(), READ_TIMEOUT_XPATH_, "30"); int defaultConnectionTimeout = 30; if(connectionTimeout != null) { try { defaultConnectionTimeout = Integer.parseInt(connectionTimeout); } catch(NumberFormatException e) { Logger.warn("Configuration value " + READ_TIMEOUT_XPATH_ + " should be a number defaulting to 30"); } } if(defaultConnectionTimeout < 0) { defaultConnectionTimeout = 30; } return defaultConnectionTimeout * 1000; } public boolean getAdesFormResult() { String enableArchiving = getElementValue(getConfigElem(), FORMRESULT_CONFIGURATION_XPATH, null); return Boolean.valueOf(enableArchiving).booleanValue(); } /** * Returns the canonicalization algorithm name. * * @return The canonicalization algorithm name from the configuration. */ public String getCanonicalizationAlgorithmName() { String c14nAlgorithm = getElementValue(getConfigElem(), C14N_ALGORITHM_XPATH, null); if (c14nAlgorithm == null || !ACCEPTED_C14N_ALGORITHMS.contains(c14nAlgorithm)) { info( "config.23", new Object[] { "CanonicalizationAlgorithm", C14N_ALGORITHM_DEFAULT }); c14nAlgorithm = C14N_ALGORITHM_DEFAULT; } return c14nAlgorithm; } /** * Build the configured hardware crypto modules. * * @return The hardware crypto modules from the configuration. */ public List buildHardwareCryptoModules() { List modules = new ArrayList(); NodeIterator modIter = XPathUtils.selectNodeIterator( getConfigElem(), HARDWARE_CRYPTO_MODULE_XPATH); Element modElem; while ((modElem = (Element) modIter.nextNode()) != null) { String name = getElementValue(modElem, CONF + "Name", null); String slotId = getElementValue(modElem, CONF + "SlotId", null); String userPIN = getElementValue(modElem, CONF + "UserPIN", null); HardwareCryptoModule module = new HardwareCryptoModule(name, slotId, userPIN); modules.add(module); } return modules; } /** * * @return */ public boolean allowExternalUris() { Element permitExtUris = (Element)XPathUtils.selectSingleNode(getConfigElem(), PERMIT_EXTERNAL_URIS_XPATH); // if PermitExternalUris element does not exist - don't allow external uris if (permitExtUris == null) { // set permitExtUris for iaik-moa ExternalReferenceChecker.setPermitExternalURLs(false); return false; } else { // set permitExtUris for iaik-moa ExternalReferenceChecker.setPermitExternalURLs(true); return true; } } /** * * @return */ public List buildPermitExternalUris() { info("config.33", null); List blacklist = new ArrayList(); List blackListIaikMoa = new ArrayList(); NodeIterator permitExtIter = XPathUtils.selectNodeIterator( getConfigElem(), BLACK_LIST_URIS_XPATH); Element permitExtElem = null; while ((permitExtElem = (Element) permitExtIter.nextNode()) != null) { String host = getElementValue(permitExtElem, CONF + "IP", null); String port = getElementValue(permitExtElem, CONF + "Port", null); BlackListEntry entry =null; if (port == null) { entry = new BlackListEntry(host, -1); info("config.34", new Object[]{host}); } else { entry = new BlackListEntry(host, new Integer(port).intValue()); info("config.34", new Object[]{host + ":" + port}); } // add entry to iaik-moa blacklist blackListIaikMoa.add(entry); String array[] = new String[2]; array[0] = host; array[1] = port; blacklist.add(array); } // set blacklist for iaik-moa ExternalReferenceChecker.setBlacklist(blackListIaikMoa); if(blacklist.isEmpty()) // no blacklisted uris given info("config.36", null); return blacklist; } /** * * @return */ public List buildForbidExternalUris() { //info("config.47", null); List whitelist = new ArrayList(); List whiteListIaikMoa = new ArrayList(); NodeIterator forbidExtIter = XPathUtils.selectNodeIterator( getConfigElem(), WHITE_LIST_URIS_XPATH); Element permitExtElem = null; while ((permitExtElem = (Element) forbidExtIter.nextNode()) != null) { String host = getElementValue(permitExtElem, CONF + "IP", null); String port = getElementValue(permitExtElem, CONF + "Port", null); // WhiteListeEntry WhiteListEntry entry =null; if (port == null) { entry = new WhiteListEntry(host, -1); info("config.49", new Object[]{host}); } else { entry = new WhiteListEntry(host, new Integer(port).intValue()); info("config.49", new Object[]{host + ":" + port}); } // add entry to iaik-moa whitelist whiteListIaikMoa.add(entry); String array[] = new String[2]; array[0] = host; array[1] = port; whitelist.add(array); } // set whitelist for iaik-moa ExternalReferenceChecker.setWhitelist(whiteListIaikMoa); if(whitelist.isEmpty()) // no whitelisted uris given info("config.48", null); return whitelist; } /** * Build the configured hardware keys. * * @param keyModules The keyModules that the configuration already knows about. To * prevent multiple key modules with the same ID. * @return The hardware keys contained in the configuration. */ public List buildHardwareKeyModules(List keyModules) { Set existingIds = toIdSet(keyModules); List hardwareKeys = new ArrayList(); NodeIterator hkIter = XPathUtils.selectNodeIterator(getConfigElem(), HARDWARE_KEY_XPATH); Element keyElem; while ((keyElem = (Element) hkIter.nextNode()) != null) { String id = getElementValue(keyElem, CONF + "Id", null); String name = getElementValue(keyElem, CONF + "Name", null); String slotId = getElementValue(keyElem, CONF + "SlotId", null); String userPIN = getElementValue(keyElem, CONF + "UserPIN", null); if (existingIds.contains(id)) { warn( "config.04", new Object[] { "Hardware- oder SoftwareKeyModule", id }); } else { KeyModule key = new HardwareKeyModule(id, name, slotId, userPIN); hardwareKeys.add(key); existingIds.add(id); } } return hardwareKeys; } /** * Build the configured software keys. * * @param keyModules The keyModules that the configuration already knows about. To * prevent multiple key modules with the same ID. * * @return The software keys contained in the configuration. */ public List buildSoftwareKeyModules(List keyModules) { Set existingIds = toIdSet(keyModules); List softwareKeys = new ArrayList(); NodeIterator skIter = XPathUtils.selectNodeIterator(getConfigElem(), SOFTWARE_KEY_XPATH); Element keyElem; while ((keyElem = (Element) skIter.nextNode()) != null) { String id = getElementValue(keyElem, CONF + "Id", null); String fileName = getElementValue(keyElem, CONF + "FileName", null); String passWord = getElementValue(keyElem, CONF + "Password", null); if (existingIds.contains(id)) { warn( "config.04", new Object[] { "Hardware- oder SoftwareKeyModule", id }); } else { File keyFile; KeyModule key; // make keyFile absolute keyFile = new File(fileName); if (!keyFile.isAbsolute()) { keyFile = new File(configRoot_, fileName); } // check for existence if (!keyFile.exists() || keyFile.isDirectory()) { warn("config.25", new Object[] { id, keyFile.getAbsolutePath()}); } else { // create a new key module key = new SoftwareKeyModule(id, keyFile.getAbsolutePath(), passWord); softwareKeys.add(key); existingIds.add(id); } } } return softwareKeys; } /** * Build the key group configuration. * * @param keyModules The KeyModules that the configuration * knows about. Used to check for errors in the configuration. * @return The mapping between key group IDs and key groups. */ public Map buildKeyGroups(List keyModules) { Set keyModuleIds = toIdSet(keyModules); Map keyGroups = new HashMap(); NodeIterator kgIter; Element keyGroupElem; // select all KeyGroup elements and build the KeyGroup objects from them kgIter = XPathUtils.selectNodeIterator(getConfigElem(), KEYGROUP_XPATH); while ((keyGroupElem = (Element) kgIter.nextNode()) != null) { String keyGroupId = getElementValue(keyGroupElem, CONF + "Id", null); //switch all keyGroupIds to lower case, only if (MiscUtil.isNotEmpty(keyGroupId)) keyGroupId = keyGroupId.trim().toLowerCase(); String keyGroupDigestMethodAlgorithm = getElementValue(keyGroupElem, CONF + "DigestMethodAlgorithm", null); Set keyGroupEntries = buildKeyGroupEntries(keyGroupId, keyModuleIds, keyGroupElem); KeyGroup keyGroup = new KeyGroup(keyGroupId, keyGroupEntries, keyGroupDigestMethodAlgorithm); if (keyGroups.containsKey(keyGroupId)) { warn("config.04", new Object[] { "KeyGroup", keyGroupId }); } else { keyGroups.put(keyGroup.getId(), keyGroup); } } return keyGroups; } /** * Return the set of IDs contained in the given KeyModules. * * @param keyModules The KeyModules from which to extract the * IDs. * @return The IDs from the given KeyModules. */ private Set toIdSet(List keyModules) { Set ids = new HashSet(); Iterator iter; for (iter = keyModules.iterator(); iter.hasNext();) { KeyModule keyModule = (KeyModule) iter.next(); ids.add(keyModule.getId()); } return ids; } /** * Build the key entries belonging to a key group. * * @param keyGroupId The ID of the key group we are building here. Passed * for logging purposes. * @param keyModuleIds The IDs of the HardwareKeyModules and * SoftwareKeyModules that exist in the configuration. * @param keyGroupElem The KeyGroup DOM element to parse. * @return A Set of KeyGroupEntry objects. */ private Set buildKeyGroupEntries( String keyGroupId, Set keyModuleIds, Element keyGroupElem) { Set entries = new HashSet(); NodeIterator keyEntryIter; Element keyEntryElem; // select all Key elements and put them into the Map keyEntryIter = XPathUtils.selectNodeIterator(keyGroupElem, CONF + "Key"); while ((keyEntryElem = (Element) keyEntryIter.nextNode()) != null) { String keyModuleId = getElementValue(keyEntryElem, CONF + "KeyModuleId", ""); Element keyCertElem = (Element) XPathUtils.selectSingleNode(keyEntryElem, CONF + "KeyCertIssuerSerial"); IssuerAndSerial issuerSerial = buildIssuerAndSerial(keyCertElem); if (!keyModuleIds.contains(keyModuleId)) { warn("config.26", new Object[] { keyGroupId, keyModuleId }); } else if (issuerSerial != null) { KeyGroupEntry entry = new KeyGroupEntry(keyModuleId, issuerSerial); entries.add(entry); } } return entries; } /** * Build the key group mapping. * * @param keyGroups The available key groups. * @param anonymous The IssuerAndSerial to be used for key group * mappings not protected by a certificate. * @return The key group mapping. */ public Map buildKeyGroupMappings(Map keyGroups, IssuerAndSerial anonymous) { Map mappings = new HashMap(); NodeIterator mappingIter; Element mappingElem; // select all KeyGroupMapping elements mappingIter = XPathUtils.selectNodeIterator(getConfigElem(), KEYGROUP_MAPPING_XPATH); // build the mapping for each KeyGroupMapping element while ((mappingElem = (Element) mappingIter.nextNode()) != null) { Element issuerSerialElem = (Element) XPathUtils.selectSingleNode(mappingElem, CONF + "CustomerId"); // build the IssuerAndSerial who has access to the key groups IssuerAndSerial issuerAndSerial; if (issuerSerialElem != null) { issuerAndSerial = buildIssuerAndSerial(issuerSerialElem); } else { // IssuerSerial element: the keygroup is generally available issuerAndSerial = anonymous; } // add the key groups to the mappings if (issuerAndSerial != null) { Map groups = (Map) mappings.get(issuerAndSerial); NodeIterator keyGroupIter; Element keyGroupElem; if (groups == null) { // no mapping exist -> build one groups = new HashMap(); mappings.put(issuerAndSerial, groups); } // select the available key groups and add them to the mapping keyGroupIter = XPathUtils.selectNodeIterator(mappingElem, CONF + "KeyGroupId"); while ((keyGroupElem = (Element) keyGroupIter.nextNode()) != null) { String keyGroupId = getElementValue(keyGroupElem, ".", null); KeyGroup keyGroup = (KeyGroup) keyGroups.get(keyGroupId.trim().toLowerCase()); if (keyGroup != null) { groups.put(keyGroupId, keyGroup); } else { warn("config.00", new Object[] { keyGroupId }); } } } } return mappings; } /** * Returns the default chaining mode from the configuration. * * @return The default chaining mode. */ public String getDefaultChainingMode() { String defaultChaining = getElementValue( getConfigElem(), CHAINING_MODES_DEFAULT_XPATH, CM_PKIX); return translateChainingMode(defaultChaining); } /** * Build the chaining modes for all configured trust anchors. * * @return The mapping from trust anchors to chaining modes. */ public Map buildChainingModes() { Map chainingModes = new HashMap(); NodeIterator trustIter = XPathUtils.selectNodeIterator(getConfigElem(), TRUST_ANCHOR_XPATH); Element trustAnchorElem; while ((trustAnchorElem = (Element) trustIter.nextNode()) != null) { IssuerAndSerial issuerAndSerial = buildIssuerAndSerial( (Element)XPathUtils.selectSingleNode(trustAnchorElem, CONF + "Identification")); String mode = getElementValue(trustAnchorElem, CONF + "Mode", null); if (issuerAndSerial != null) { chainingModes.put(issuerAndSerial, translateChainingMode(mode)); } } return chainingModes; } /** * Build an IssuerAndSerial from the DOM representation. * * @param root The root element (being of type dsig: * X509IssuerSerialType. * @return The issuer and serial number contained in the root * element or null if could not be built for any reason. */ private IssuerAndSerial buildIssuerAndSerial(Element root) { String issuer = getElementValue(root, ISSUER_XPATH, null); String serial = getElementValue(root, SERIAL_XPATH, null); if (issuer != null && serial != null) { try { RFC2253NameParser nameParser = new RFC2253NameParser(issuer); Principal issuerDN = nameParser.parse(); return new IssuerAndSerial(issuerDN, new BigInteger(serial)); } catch (RFC2253NameParserException e) { warn("config.16", new Object[] { issuer, serial }, e); return null; } catch (NumberFormatException e) { warn("config.16", new Object[] { issuer, serial }, e); return null; } } return null; } /** * Translate the chaining mode from the configuration file to one used in the * IAIK MOA API. * * @param chainingMode The chaining mode from the configuration. * @return The chaining mode as provided by the ChainingModes * interface. * @see iaik.pki.pathvalidation.ChainingModes */ private String translateChainingMode(String chainingMode) { if (chainingMode.equals(CM_CHAINING)) { return ChainingModes.CHAIN_MODE; } else if (chainingMode.equals(CM_PKIX)) { return ChainingModes.PKIX_MODE; } else { return ChainingModes.PKIX_MODE; } } /** * Build the distribution points mapping. * * @return The mapping from certificate authorities to distribution points. */ public Map buildDistributionPoints() { Map dPs = new HashMap(); NodeIterator dPIter; Element dPElem; // select all DistributionPoint elements dPIter = XPathUtils.selectNodeIterator(getConfigElem(), DISTRIBUTION_POINTS_XPATH); // build the mapping of CA name to distribution points while ((dPElem = (Element) dPIter.nextNode()) != null) { String caIssuerDNText = getElementValue(dPElem, CONF + "CAIssuerDN", ""); RFC2253NameParser nameParser = new RFC2253NameParser(caIssuerDNText); NodeIterator cRLDPIter = XPathUtils.selectNodeIterator(dPElem, CONF + "CRLDP"); NodeIterator oCSPDPPIter = XPathUtils.selectNodeIterator(dPElem, CONF + "OCSPDP"); try { String caIssuerDN = nameParser.parse().getName(); // check, if a mapping exists or make a new mapping Set dPsForCA = (Set) dPs.get(caIssuerDN); if (dPsForCA == null) { dPsForCA = new HashSet(); dPs.put(caIssuerDN, dPsForCA); } // add the CRL distribution points of this CA to the set Element cRLDPElem; while ((cRLDPElem = (Element) cRLDPIter.nextNode()) != null) { CRLDistributionPoint cRLDP = (CRLDistributionPoint) buildDistributionPoint(cRLDPElem, caIssuerDN); dPsForCA.add(cRLDP); } // add the OCSP distribution points of this CA to the set Element oCSPPElem; while ((oCSPPElem = (Element) oCSPDPPIter.nextNode()) != null) { OCSPDistributionPoint oCSPDP = (OCSPDistributionPoint) buildDistributionPoint(oCSPPElem, null); dPsForCA.add(oCSPDP); } } catch (RFC2253NameParserException e) { warn("config.13", new Object[] { caIssuerDNText }, e); } } return dPs; } /** * Build a distribution point from the DOM representation. * * @param dpElem The root element of the distribution point. * * @param issuerName The name of the CA issuing the CRL referred to by this DP, or null * if this DP refers to an OCSP responder. * * @return The distribution point. */ private DistributionPoint buildDistributionPoint(Element dpElem, String issuerName) { String uri = getElementValue(dpElem, CONF + "Location", null); if ("CRLDP".equals(dpElem.getLocalName())) { NodeIterator reasonCodesIter = XPathUtils.selectNodeIterator(dpElem, CONF + "ReasonCode"); Element reasonCodeElem; StringBuffer reasonCodesSB = new StringBuffer(); while ((reasonCodeElem = (Element)reasonCodesIter.nextNode()) != null) { if (reasonCodesSB.length() > 0) reasonCodesSB.append(" "); reasonCodesSB.append(getElementValue(reasonCodeElem, ".", "").trim()); } return new CRLDistributionPoint(issuerName, uri, reasonCodesSB.toString()); } else { return new OCSPDistributionPoint(uri); } } /** * Return the CRL archive duration. * * @return The value of the CRL archive duration setting from the configuration, or 0 if * no value is set in the configuration. */ public int getRevocationArchiveDuration() { String archiveDuration = getElementValue(getConfigElem(), CRL_ARCHIVE_DURATION_XPATH, null); try { return Integer.parseInt(archiveDuration); } catch (NumberFormatException e) { warn("config.01", null); return 365; } } /** * Build the CreateTransformsInfoProfiles. * * @return The mapping from profile ID to profile. */ public Map buildCreateTransformsInfoProfiles() { return loadProfiles(CREATE_TRANSFORMS_INFO_PROFILE_XPATH, "CreateTransformsInfoProfile"); } /** * Build the CreateSignatureEnvironmentProfiles. * * @return The mapping from profile ID to profile. */ public Map buildCreateSignatureEnvironmentProfiles() { return loadProfiles(CREATE_SIGNATURE_ENVIRONMENT_PROFILE_XPATH, "CreateSignatureEnvironmentProfile"); } /** * Build the VerifyTransformsInfoProfiles. * * @return The mapping from profile ID to profile. */ public Map buildVerifyTransformsInfoProfiles() { return loadProfiles(VERIFY_TRANSFORMS_INFO_PROFILE_XPATH, "VerifyTransformsInfoProfile"); } /** * Build the SupplementProfiles. * * @return The mapping from profile ID to profile. */ public Map buildSupplementProfiles() { return loadProfiles(SUPPLEMENT_PROFILE_XPATH, "SupplementProfile"); } /** * Load a profile mapping. * * @param xpath The XPath to select the profiles from the configuration. * * @param profileRoot The name of the profile root element. * * @return Map The profile ID to profile mapping. */ private Map loadProfiles(String xpath, String profileRoot) { Map profiles = new HashMap(); NodeIterator profileIter = XPathUtils.selectNodeIterator(getConfigElem(), xpath); Element profileElem; while ((profileElem = (Element) profileIter.nextNode()) != null) { String id = getElementValue(profileElem, CONF + "Id", null); String fileName = getElementValue(profileElem, CONF + "Location", null); if (profiles.containsKey(id)) { warn("config.04", new Object[] { profileRoot, id }); } else { try { File profileFile = new File(fileName); // make profileFile absolute if (!profileFile.isAbsolute()) profileFile = new File(configRoot_, fileName); // load the profile info("config.22", new Object[] { profileRoot, id, profileFile.getAbsoluteFile()}); Element profile = loadProfile(profileFile); if (Constants.MOA_NS_URI.equals(profile.getNamespaceURI()) && profile.getLocalName().equals(profileRoot)) { profiles.put(id, profile); } else { warn("config.02", new Object[] { profileRoot, id, fileName }); } } catch (ConfigurationException e) { warn("config.03", new Object[] { profileRoot, id }); } } } return profiles; } /** * Load a profile from a file. * * @param root The absolute directory path of the main configuration file. * @param profileFile The file containing the profile. * @return The profile in its DOM representation. * @throws ConfigurationException An error occurred loading the profile. */ private Element loadProfile(File profileFile) throws ConfigurationException { Element profile; try { profile = parseXml(new FileInputStream(profileFile)); } catch (Exception e) { throw new ConfigurationException("config.12", null, e); } return profile; } /** * Build the trust profile mapping. * * @return The profile ID to profile mapping. */ public Map buildTrustProfiles() { Map trustProfiles = new HashMap(); NodeIterator profileIter = XPathUtils.selectNodeIterator(getConfigElem(), TRUST_PROFILE_XPATH); Element profileElem; while ((profileElem = (Element) profileIter.nextNode()) != null) { //load basic TrustProfile information //check TrustProfileId String id = getElementValue(profileElem, CONF + "Id", null); if (MiscUtil.isEmpty(id)) { warn("config.52", new Object[]{"Id des TrustProfiles ist leer."}); continue; } //cast profileId to lowercase (changed in 3.0.1) id = id.trim().toLowerCase(); if (trustProfiles.containsKey(id)) { warn("config.04", new Object[] { "TrustProfile", id }); continue; } //check location of TrustAnchor directory String trustAnchorsLocStr = getElementValue(profileElem, CONF + "TrustAnchorsLocation", null); URI trustAnchorsLocURI = null; try { trustAnchorsLocURI = new URI(trustAnchorsLocStr); if (!trustAnchorsLocURI.isAbsolute()) { // make it absolute to the config file trustAnchorsLocURI = new URI(configRoot_.toURL() + trustAnchorsLocStr); } } catch (URIException e) { warn("config.14", new Object[] { "uri", id, trustAnchorsLocStr }, e); continue; } catch (MalformedURLException e) { warn("config.15", new Object[] {id}, e); continue; } File profileDir = new File(trustAnchorsLocURI.getPath()); if (!profileDir.exists() || !profileDir.isDirectory()) { warn("config.27", new Object[] { "uri", id }); continue; } //check signerCertsLocation URL String signerCertsLocStr = getElementValue(profileElem, CONF + "SignerCertsLocation", null); URI signerCertsLocURI = null; if (signerCertsLocStr != null && !"".equals(signerCertsLocStr)) { try { signerCertsLocURI = new URI(signerCertsLocStr); if (!signerCertsLocURI.isAbsolute()) signerCertsLocURI = new URI(configRoot_.toURL() + signerCertsLocStr); File signerCertsDir = new File(signerCertsLocURI.getPath()); if (!signerCertsDir.exists() || !signerCertsDir.isDirectory()) { warn("config.27", new Object[] { "signerCertsUri", id }); continue; } } catch (URIException e) { warn("config.14", new Object[] { "signerCertsUri", id, trustAnchorsLocStr }, e); continue; } catch (MalformedURLException e) { warn("config.15", new Object[] {id}, e); continue; } } signerCertsLocStr = (signerCertsLocURI != null) ? signerCertsLocURI.toString() : null; //check if TSL support is enabled Element eutslElem = (Element) XPathUtils.selectSingleNode(profileElem, CONF + "EUTSL"); boolean tslEnabled = false; if (eutslElem != null) //EUTSL element found --> TSL enabled tslEnabled = true; //load TSL configuration String countries = getElementValue(profileElem, CONF + "EUTSL" + "/" + CONF + "CountrySelection", null); String allowedTspStatus = getElementValue(profileElem, CONF + "EUTSL" + "/" + CONF + "AllowedTSPStatus", null); String allowedTspServiceTypes = getElementValue(profileElem, CONF + "EUTSL" + "/" + CONF + "AllowedTSPServiceTypes", null); //create profile configuration TrustProfile profile = new TrustProfile(id, trustAnchorsLocURI.toString(), signerCertsLocStr, tslEnabled, countries, allowedTspStatus, allowedTspServiceTypes); trustProfiles.put(id, profile); } return trustProfiles; } /** * Returns the location of the certificate store. * * @return the location of the certificate store. */ public String getCertStoreLocation() { String certStoreLocStr = getElementValue(getConfigElem(), CERTSTORE_LOCATION_XPATH, null); File certStoreLocFile; // No value specified in configuration file: Set it to a reasonable (absolute) default if (certStoreLocStr == null) return new File(configRoot_, "certstore").getAbsolutePath(); // Make cert store location an absolute value certStoreLocFile = new File(certStoreLocStr); if (!certStoreLocFile.isAbsolute()) { certStoreLocFile = new File(configRoot_, certStoreLocStr); } // Check if cert store location exists, eventually try to create it if (!certStoreLocFile.isDirectory()) { boolean created = false; try { created = certStoreLocFile.mkdirs(); } finally { if (!created) { warn("config.32", new Object[] { certStoreLocFile.getAbsolutePath() }); } } } return certStoreLocFile.getAbsolutePath(); } // // various utility methods // /** * Parse a configuration XML file. * * @param inputStream The stream from which to read the XML data. * @return The DOM representation of the XML data. * @throws ParserConfigurationException XML parser not configured properly. * @throws SAXException An error parsing the XML file. * @throws IOException An error reading the stream. */ private static Element parseXml(InputStream inputStream) throws ParserConfigurationException, SAXException, IOException { return DOMUtils .parseDocument(inputStream, true, Constants.ALL_SCHEMA_LOCATIONS, null) .getDocumentElement(); } /** * Return the value of an element located by an XPath. * * @param root The root element from which to evaluate the xpath. * @param xpath The XPath pointing to the element. * @param def The default value, if no element can be found with the given * xpath. * @return The element value or def, if the element cannot be * found. */ private String getElementValue(Element root, String xpath, String def) { Element elem = (Element) XPathUtils.selectSingleNode(root, xpath); return elem != null ? DOMUtils.getText(elem) : def; } /** * Return the value of an attribute located by an XPath. * * @param root The root element from which to evaluate the xpath. * @param xpath The XPath pointing to the attribute. * @param def The default value, if no attribute can be found with the given * xpath. * @return The element value or def, if the attribute cannot be * found. */ private String getAttributeValue(Element root, String xpath, String def) { Attr attr = (Attr) XPathUtils.selectSingleNode(root, xpath); return attr != null ? attr.getValue() : def; } /** * Log an info message. * * @param messageId The message ID. * @param parameters Additional parameters for the message. * @see at.gv.egovernment.moa.spss.server.util.MessageProvider */ private static void info(String messageId, Object[] parameters) { MessageProvider msg = MessageProvider.getInstance(); Logger.info(new LogMsg(msg.getMessage(messageId, parameters))); } /** * Log a warning. * * @param messageId The message ID. * @param args Additional parameters for the message. * @see at.gv.egovernment.moa.spss.server.util.MessageProvider */ private void warn(String messageId, Object[] args) { MessageProvider msg = MessageProvider.getInstance(); String txt = msg.getMessage(messageId, args); Logger.warn(new LogMsg(txt)); warnings.add(txt); } /** * Log a warning. * * @param messageId The message ID. * @param args Additional parameters for the message. * @see at.gv.egovernment.moa.spss.server.util.MessageProvider */ private void debug(String messageId, Object[] args) { MessageProvider msg = MessageProvider.getInstance(); String txt = msg.getMessage(messageId, args); Logger.debug(new LogMsg(txt)); } /** * Log a debug message. * * @param messageId The message ID. * @param args Additional parameters for the message. * @see at.gv.egovernment.moa.spss.server.util.MessageProvider */ private void debug(String message) { Logger.debug(new LogMsg(message)); } /** * Log a warning. * * @param messageId The message ID. * @param args Additional parameters for the message. * @param t An exception being the cause of the warning. * @see at.gv.egovernment.moa.spss.server.util.MessageProvider */ private void warn(String messageId, Object[] args, Throwable t) { MessageProvider msg = MessageProvider.getInstance(); String txt = msg.getMessage(messageId, args); Logger.warn(new LogMsg(txt), t); warnings.add(txt); } /** * Log an error. * * @param messageId The message ID. * @param args Additional parameters for the message. * @see at.gv.egovernment.moa.spss.server.util.MessageProvider */ private void error(String messageId, Object[] args) { MessageProvider msg = MessageProvider.getInstance(); String txt = msg.getMessage(messageId, args); Logger.error(new LogMsg(txt)); warnings.add(txt); } /** * Log an error. * * @param messageId The message ID. * @param args Additional parameters for the message. * @param t An exception being the cause of the warning. * @see at.gv.egovernment.moa.spss.server.util.MessageProvider */ private void error(String messageId, Object[] args, Throwable t) { MessageProvider msg = MessageProvider.getInstance(); String txt = msg.getMessage(messageId, args); Logger.error(new LogMsg(txt), t); warnings.add(txt); } /** * Returns whether revocation information should be archived. * * @return whether revocation information should be archived. */ public boolean getEnableRevocationArchiving() { String enableArchiving = getElementValue(getConfigElem(), ENABLE_ARCHIVING_XPATH, null); return Boolean.valueOf(enableArchiving).booleanValue(); } /** * Returns the JDBC URL for the revocation archive database. * * @return the JDBC URL for the revocation archive database, or nullnull