package at.gv.egovernment.moa.spss.server.service; 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; import iaik.server.modules.keys.KeyEntryID; import iaik.server.modules.keys.KeyModule; import iaik.server.modules.keys.KeyModuleFactory; /** * * @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 { final ConfigurationProvider config = ConfigurationProvider.getInstance(); Set keyGroupEntries; // get the KeyGroup entries from the configuration if (cert != null) { final Principal issuer = cert.getIssuerDN(); final 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 { final Set keyEntryIDs = module.getPrivateKeyEntryIDs(); final 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();) { final KeyEntryID entryID = (KeyEntryID) iter.next(); final KeyGroupEntry entry = new KeyGroupEntry(entryID.getModuleID(), entryID.getCertificateIssuer(), entryID.getCertificateSerialNumber()); if (keyGroupEntries.contains(entry)) { keySet.add(entryID); } } return keySet; } } private X509Certificate getClientCertificate(HttpServletRequest request) { final X509Certificate[] clientCert = (X509Certificate[]) request .getAttribute(X509_CERTIFICATE_PROPERTY); if (clientCert != null) { return clientCert[0]; } return null; } @Override @SuppressWarnings("rawtypes") public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { final X509Certificate cert = getClientCertificate(request); final 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; } final String transactionId = TransactionIDGenerator.nextID(); final KeyModule module = KeyModuleFactory.getInstance(new TransactionId( transactionId)); final 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();) { final KeyEntryID entryID = (KeyEntryID) iter.next(); final List certChain = module.getPrivateKeyEntry(entryID).getCertificateChain(); if (certChain != null && !certChain.isEmpty()) { Logger.trace("Returning Certificate!"); final Certificate keyCert = (Certificate) certChain.get(0); final 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 (final Throwable e) { Logger.error("Unhandled Exception when providing certificate", e); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } }