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.logging.Logger;
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;
/**
*
* @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 KeyEntryID
s available to the given
* keyGroupID
.
*
* @param keyGroupID
* The keygroup ID for which the available keys should be
* returned.
* @return The Set
of KeyEntryID
s 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);
}
}
}