package at.gv.egovernment.moa.spss.server.service; import iaik.server.modules.keys.KeyEntryID; import iaik.server.modules.keys.KeyModule; import iaik.server.modules.keys.KeyModuleFactory; import java.io.IOException; import java.math.BigInteger; import java.security.Principal; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import at.gv.egovernment.moa.spss.server.config.ConfigurationException; import at.gv.egovernment.moa.spss.server.config.ConfigurationProvider; import at.gv.egovernment.moa.spss.server.config.KeyGroupEntry; import at.gv.egovernment.moa.spss.server.logging.TransactionId; import at.gv.egovernment.moa.spss.server.transaction.TransactionIDGenerator; import at.gv.egovernment.moaspss.logging.Logger; /** * * @author Andreas Fitzek * @version $Id$ */ public class CertificateProviderServlet extends HttpServlet { /** * */ private static final long serialVersionUID = -6907582473072190122L; /** The property name for accessing the X509 client certificate chain. */ private static final String X509_CERTIFICATE_PROPERTY = "javax.servlet.request.X509Certificate"; public static final String PARAM_KEYID = "id"; /** * 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. * @throws ConfigurationException */ @SuppressWarnings({ "rawtypes", "unchecked" }) private Set buildKeySet(String keyGroupID, X509Certificate cert, KeyModule module) throws ConfigurationException { ConfigurationProvider config = ConfigurationProvider.getInstance(); Set keyGroupEntries; // get the KeyGroup entries from the configuration if (cert != null) { 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 { 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; } } private X509Certificate getClientCertificate(HttpServletRequest request) { X509Certificate[] clientCert = (X509Certificate[]) request .getAttribute(X509_CERTIFICATE_PROPERTY); if(clientCert != null) { return clientCert[0]; } return null; } @SuppressWarnings("rawtypes") public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { X509Certificate cert = getClientCertificate(request); String keyId = request.getParameter(PARAM_KEYID); if(keyId == null) { Logger.warn(PARAM_KEYID + " not provided in Request. Returning: " + HttpServletResponse.SC_BAD_REQUEST); response.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } String transactionId = TransactionIDGenerator.nextID(); KeyModule module = KeyModuleFactory.getInstance(new TransactionId( transactionId)); Set keySet = buildKeySet(keyId, cert, module); if(keySet == null || keySet.isEmpty()) { Logger.warn("No keys available for Key Identifier " + keyId + " and given authentication."); response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } if(keySet.size() != 1) { Logger.warn("Too many keys available for Key Identifier " + keyId + " and given authentication."); response.sendError(HttpServletResponse.SC_CONFLICT); return; } 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 = keySet.iterator(); iter.hasNext();) { KeyEntryID entryID = (KeyEntryID) iter.next(); List certChain = module.getPrivateKeyEntry(entryID).getCertificateChain(); if(certChain != null && !certChain.isEmpty()) { Logger.trace("Returning Certificate!"); Certificate keyCert = ((Certificate)certChain.get(0)); byte[] certData = keyCert.getEncoded(); response.setStatus(HttpServletResponse.SC_OK); response.setContentType("application/pkix-cert"); response.setHeader("Content-disposition","attachment; filename=\"" + keyId + ".cer\""); response.getOutputStream().write(certData); response.getOutputStream().close(); return; } break; } // No Certificate could be found! Logger.warn("Failed to find keys available for Key Identifier " + keyId + " and given authentication."); response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } catch(Throwable e) { Logger.error("Unhandled Exception when providing certificate", e); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } }