diff options
15 files changed, 248 insertions, 238 deletions
diff --git a/base/ca/src/CMakeLists.txt b/base/ca/src/CMakeLists.txt index e5ef9e530..74533814a 100644 --- a/base/ca/src/CMakeLists.txt +++ b/base/ca/src/CMakeLists.txt @@ -31,6 +31,14 @@ find_file(JAXRS_API_JAR ${RESTEASY_LIB} ) +find_file(SERVLET_JAR + NAMES + servlet.jar + PATHS + ${JAVA_LIB_INSTALL_DIR} + /usr/share/java +) + # build pki-ca javac(pki-ca-classes SOURCES @@ -39,7 +47,7 @@ javac(pki-ca-classes ${PKI_CERTSRV_JAR} ${PKI_CMS_JAR} ${PKI_CMSCORE_JAR} ${PKI_CMSUTIL_JAR} ${PKI_NSUTIL_JAR} ${LDAPJDK_JAR} ${JAXRS_API_JAR} - ${JSS_JAR} ${COMMONS_CODEC_JAR} ${SYMKEY_JAR} + ${JSS_JAR} ${COMMONS_CODEC_JAR} ${SYMKEY_JAR} ${SERVLET_JAR} OUTPUT_DIR ${CMAKE_BINARY_DIR}/classes DEPENDS diff --git a/base/ca/src/com/netscape/ca/CertificateAuthority.java b/base/ca/src/com/netscape/ca/CertificateAuthority.java index f8f3d7a9b..50ef503b6 100644 --- a/base/ca/src/com/netscape/ca/CertificateAuthority.java +++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java @@ -29,11 +29,16 @@ import java.security.PublicKey; import java.security.cert.CRLException; import java.security.cert.CertificateException; import java.security.cert.CertificateParsingException; +import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; +import java.util.Map; import java.util.Vector; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + import netscape.security.util.DerOutputStream; import netscape.security.util.DerValue; import netscape.security.x509.AlgorithmId; @@ -65,6 +70,7 @@ import com.netscape.certsrv.base.EPropertyNotFound; import com.netscape.certsrv.base.IConfigStore; import com.netscape.certsrv.base.ISubsystem; import com.netscape.certsrv.base.Nonces; +import com.netscape.certsrv.base.PKIException; import com.netscape.certsrv.ca.ECAException; import com.netscape.certsrv.ca.ICRLIssuingPoint; import com.netscape.certsrv.ca.ICertificateAuthority; @@ -219,7 +225,6 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori private boolean mUseNonces = true; private int mMaxNonces = 100; - private Nonces mNonces = null; /** * Constructs a CA subsystem. @@ -279,8 +284,34 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori return mUseNonces; } - public Nonces getNonces() { - return mNonces; + public Map<Object, Long> getNonces(HttpServletRequest request, String name) { + + // Create a new session or use an existing one. + HttpSession session = request.getSession(true); + if (session == null) { + throw new PKIException("Unable to create session."); + } + + // Lock the session to prevent concurrent access. + // http://yet-another-dev.blogspot.com/2009/08/synchronizing-httpsession.html + + Object lock = request.getSession().getId().intern(); + synchronized (lock) { + + // Find the existing storage in the session. + @SuppressWarnings("unchecked") + Map<Object, Long> nonces = (Map<Object, Long>)session.getAttribute("nonces-"+name); + + if (nonces == null) { + // If not present, create a new storage. + nonces = Collections.synchronizedMap(new Nonces(mMaxNonces)); + + // Put the storage in the session. + session.setAttribute("nonces-"+name, nonces); + } + + return nonces; + } } /** @@ -319,10 +350,6 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori mUseNonces = mConfig.getBoolean("enableNonces", true); mMaxNonces = mConfig.getInteger("maxNumberOfNonces", 100); - if (mUseNonces) { - mNonces = new Nonces(mMaxNonces); - CMS.debug("CertificateAuthority init: Nonces enabled. (" + mNonces.size() + ")"); - } // init request queue and related modules. CMS.debug("CertificateAuthority init: initRequestQueue"); diff --git a/base/common/src/com/netscape/certsrv/base/Nonces.java b/base/common/src/com/netscape/certsrv/base/Nonces.java index c28a74fae..57ff30d35 100644 --- a/base/common/src/com/netscape/certsrv/base/Nonces.java +++ b/base/common/src/com/netscape/certsrv/base/Nonces.java @@ -17,107 +17,59 @@ // --- END COPYRIGHT BLOCK --- package com.netscape.certsrv.base; -import java.security.cert.X509Certificate; -import java.util.Hashtable; -import java.util.Vector; +import java.util.LinkedHashMap; +import java.util.Map; /** - * This class manages nonces sometimes used to control request state flow. - * <P> + * This class provides a limited storage for nonces. Usually + * nonces are added and removed immediately. In case some of + * the nonces are abandoned, the oldest nonce will be removed + * if the storage size grows exceeding the limit. * * @version $Revision$, $Date$ */ -public class Nonces { +public class Nonces extends LinkedHashMap<Object,Long> { - private Hashtable<Long, X509Certificate> mNonces = new Hashtable<Long, X509Certificate>(); - private Vector<Long> mNonceList = new Vector<Long>(); - private int mNonceLimit; + private static final long serialVersionUID = 7953840029228765259L; + + private int limit; - /** - * Constructs nonces. - */ public Nonces() { this(100); } public Nonces(int limit) { - mNonceLimit = limit; + this.limit = limit; } - public long addNonce(long nonce, X509Certificate cert) { - long i; - long k = 0; - long n = nonce; - long m = (mNonceLimit / 2) + 1; - - for (i = 0; i < m; i++) { - k = n + i; - // avoid collisions - if (!mNonceList.contains(k)) { - break; - } - k = n - i; - // avoid collisions - if (!mNonceList.contains(k)) { - break; - } - } - if (i < m) { - mNonceList.add(k); - mNonces.put(k, cert); - if (mNonceList.size() > mNonceLimit) { - n = mNonceList.firstElement().longValue(); - mNonceList.remove(0); - mNonces.remove(n); - } - } else { - // failed to resolved collision - k = -nonce; - } - return k; + /** + * Override removeEldestEntry() to remove eldest entry + * if the size exceeds the limit. + */ + protected boolean removeEldestEntry(Map.Entry<Object,Long> eldest) { + return size() > limit; } - public X509Certificate getCertificate(long nonce) { - X509Certificate cert = mNonces.get(nonce); - return cert; - } + public static void main(String[] args) { + Nonces nonces = new Nonces(3); - public X509Certificate getCertificate(int index) { - X509Certificate cert = null; - if (index >= 0 && index < mNonceList.size()) { - long nonce = mNonceList.elementAt(index).longValue(); - cert = mNonces.get(nonce); - } - return cert; - } + System.out.println("Adding 3 entries."); + nonces.put("a", 1l); + nonces.put("b", 2l); + nonces.put("c", 3l); - public long getNonce(int index) { - long nonce = 0; - if (index >= 0 && index < mNonceList.size()) { - nonce = mNonceList.elementAt(index).longValue(); + System.out.println("Nonces:"); + for (Object id : nonces.keySet()) { + System.out.println(" - "+id+": "+nonces.get(id)); } - return nonce; - } - - public void removeNonce(long nonce) { - mNonceList.remove(nonce); - mNonces.remove(nonce); - } - - public int size() { - return mNonceList.size(); - } - public int maxSize() { - return mNonceLimit; - } + System.out.println("Adding 2 more entries."); + nonces.put("d", 4l); + nonces.put("e", 5l); - public void clear() { - mNonceList.clear(); - mNonces.clear(); - } - - public boolean isInSync() { - return (mNonceList.size() == mNonces.size()); + System.out.println("Nonces:"); + for (Object id : nonces.keySet()) { + System.out.println(" - "+id+": "+nonces.get(id)); + } } } diff --git a/base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java b/base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java index ee7d60c38..21859a0f2 100644 --- a/base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java +++ b/base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java @@ -18,6 +18,9 @@ package com.netscape.certsrv.ca; import java.util.Enumeration; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; import netscape.security.x509.CertificateChain; import netscape.security.x509.CertificateVersion; @@ -31,7 +34,6 @@ import org.mozilla.jss.crypto.SignatureAlgorithm; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.IConfigStore; import com.netscape.certsrv.base.ISubsystem; -import com.netscape.certsrv.base.Nonces; import com.netscape.certsrv.dbs.certdb.ICertificateRepository; import com.netscape.certsrv.dbs.crldb.ICRLRepository; import com.netscape.certsrv.dbs.replicadb.IReplicaIDRepository; @@ -132,7 +134,7 @@ public interface ICertificateAuthority extends ISubsystem { public boolean noncesEnabled(); - public Nonces getNonces(); + public Map<Object, Long> getNonces(HttpServletRequest request, String name); /** * Retrieves the publishing processor of this certificate authority. diff --git a/base/common/src/com/netscape/cms/servlet/base/CMSServlet.java b/base/common/src/com/netscape/cms/servlet/base/CMSServlet.java index 72ced2c53..744a000e3 100644 --- a/base/common/src/com/netscape/cms/servlet/base/CMSServlet.java +++ b/base/common/src/com/netscape/cms/servlet/base/CMSServlet.java @@ -226,6 +226,7 @@ public abstract class CMSServlet extends HttpServlet { // the authority, RA, CA, KRA this servlet is serving. protected IAuthority mAuthority = null; + protected ICertificateAuthority certAuthority; protected IRequestQueue mRequestQueue = null; // system logger. @@ -301,9 +302,11 @@ public abstract class CMSServlet extends HttpServlet { authority = sc.getInitParameter(PROP_AUTHORITYID); } - if (authority != null) - mAuthority = (IAuthority) - CMS.getSubsystem(authority); + if (authority != null) { + mAuthority = (IAuthority) CMS.getSubsystem(authority); + if (mAuthority instanceof ICertificateAuthority) + certAuthority = (ICertificateAuthority) mAuthority; + } if (mAuthority != null) mRequestQueue = mAuthority.getRequestQueue(); diff --git a/base/common/src/com/netscape/cms/servlet/cert/CertRequestDAO.java b/base/common/src/com/netscape/cms/servlet/cert/CertRequestDAO.java index 4d0fc38b2..d4785e957 100644 --- a/base/common/src/com/netscape/cms/servlet/cert/CertRequestDAO.java +++ b/base/common/src/com/netscape/cms/servlet/cert/CertRequestDAO.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Random; import javax.servlet.ServletException; @@ -29,7 +30,6 @@ import javax.ws.rs.core.UriInfo; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; -import com.netscape.certsrv.base.Nonces; import com.netscape.certsrv.ca.ICertificateAuthority; import com.netscape.certsrv.cert.CertEnrollmentRequest; import com.netscape.certsrv.cert.CertRequestInfo; @@ -54,7 +54,6 @@ public class CertRequestDAO extends CMSRequestDAO { private IRequestQueue queue; private ICertificateAuthority ca; IProfileSubsystem ps; - private Nonces nonces = null; private Random random = null; public static final String ATTR_SERIALNO = "serialNumber"; @@ -65,7 +64,6 @@ public class CertRequestDAO extends CMSRequestDAO { queue = ca.getRequestQueue(); if (ca.noncesEnabled()) { random = new Random(); - nonces = ca.getNonces(); } ps = (IProfileSubsystem) CMS.getSubsystem(IProfileSubsystem.ID); } @@ -141,20 +139,19 @@ public class CertRequestDAO extends CMSRequestDAO { String profileId = request.getExtDataInString("profileId"); IProfile profile = ps.getProfile(profileId); CertReviewResponse info = CertReviewResponseFactory.create(request, profile, uriInfo, locale); - if (ca.noncesEnabled()) { - addNonce(info, servletRequest); - } - return info; - } - private void addNonce(CertReviewResponse info, HttpServletRequest servletRequest) throws EBaseException { - if (nonces != null) { + if (ca.noncesEnabled()) { + // generate nonce long n = random.nextLong(); - long m = nonces.addNonce(n, Processor.getSSLClientCertificate(servletRequest)); - if ((n + m) != 0) { - info.setNonce(Long.toString(m)); - } + + // store nonce in session + Map<Object, Long> nonces = ca.getNonces(servletRequest, "cert-request"); + nonces.put(info.getRequestId().toBigInteger(), n); + + // return nonce to client + info.setNonce(Long.toString(n)); } + return info; } /** diff --git a/base/common/src/com/netscape/cms/servlet/cert/CertReviewResponseFactory.java b/base/common/src/com/netscape/cms/servlet/cert/CertReviewResponseFactory.java index 97611eb94..a7d76a469 100644 --- a/base/common/src/com/netscape/cms/servlet/cert/CertReviewResponseFactory.java +++ b/base/common/src/com/netscape/cms/servlet/cert/CertReviewResponseFactory.java @@ -26,7 +26,6 @@ import javax.ws.rs.core.UriInfo; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.IArgBlock; -import com.netscape.certsrv.base.Nonces; import com.netscape.certsrv.cert.CertReviewResponse; import com.netscape.certsrv.profile.EProfileException; import com.netscape.certsrv.profile.IPolicyDefault; @@ -128,7 +127,8 @@ public class CertReviewResponseFactory { return ret; } - public static CertReviewResponse create(CMSRequest cmsReq, IProfile profile, Nonces nonces, Locale locale) + public static CertReviewResponse create( + CMSRequest cmsReq, IProfile profile, boolean noncesEnabled, Locale locale) throws EPropertyException, EProfileException { HttpServletRequest req = cmsReq.getHttpReq(); IRequest ireq = cmsReq.getIRequest(); @@ -139,7 +139,7 @@ public class CertReviewResponseFactory { ret.setRequestNotes(req.getParameter("requestNotes")); ret.setRequestId(ireq.getRequestId()); - if (nonces != null) { + if (noncesEnabled) { ret.setNonce(req.getParameter(Processor.ARG_REQUEST_NONCE)); } diff --git a/base/common/src/com/netscape/cms/servlet/cert/CertService.java b/base/common/src/com/netscape/cms/servlet/cert/CertService.java index e049710cb..69856751d 100644 --- a/base/common/src/com/netscape/cms/servlet/cert/CertService.java +++ b/base/common/src/com/netscape/cms/servlet/cert/CertService.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; import java.util.List; +import java.util.Map; import java.util.Random; import netscape.security.pkcs.ContentInfo; @@ -44,7 +45,6 @@ import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.BadRequestException; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.ICertPrettyPrint; -import com.netscape.certsrv.base.Nonces; import com.netscape.certsrv.base.PKIException; import com.netscape.certsrv.base.UnauthorizedException; import com.netscape.certsrv.ca.ICertificateAuthority; @@ -80,7 +80,6 @@ public class CertService extends PKIService implements CertResource { ICertificateAuthority authority; ICertificateRepository repo; Random random; - Nonces nonces; public final static int DEFAULT_SIZE = 20; @@ -88,7 +87,6 @@ public class CertService extends PKIService implements CertResource { authority = (ICertificateAuthority) CMS.getSubsystem("ca"); if (authority.noncesEnabled()) { random = new Random(); - nonces = authority.getNonces(); } repo = authority.getCertificateRepository(); } @@ -195,7 +193,11 @@ public class CertService extends PKIService implements CertResource { } } - processor.validateNonce(clientCert, request.getNonce()); + if (authority.noncesEnabled() && + !processor.isMemberOfSubsystemGroup(clientCert)) { + processor.validateNonce(servletRequest, "cert-revoke", id.toBigInteger(), request.getNonce()); + + } // Find target cert record if different from client cert. ICertRecord targetRecord = id.equals(clientSerialNumber) ? clientRecord : processor.getCertificateRecord(id); @@ -470,12 +472,14 @@ public class CertService extends PKIService implements CertResource { certData.setStatus(record.getStatus()); - if (generateNonce && nonces != null) { + if (authority.noncesEnabled() && generateNonce) { + // generate nonce long n = random.nextLong(); - long m = nonces.addNonce(n, Processor.getSSLClientCertificate(servletRequest)); - if (n + m != 0) { - certData.setNonce(m); - } + // store nonce in session + Map<Object, Long> nonces = authority.getNonces(servletRequest, "cert-revoke"); + nonces.put(certId.toBigInteger(), n); + // return nonce to client + certData.setNonce(n); } URI uri = uriInfo.getBaseUriBuilder().path(CertResource.class).path("{id}").build(certId.toHexString()); diff --git a/base/common/src/com/netscape/cms/servlet/cert/DoRevoke.java b/base/common/src/com/netscape/cms/servlet/cert/DoRevoke.java index 5d33bf2bc..272034fc2 100644 --- a/base/common/src/com/netscape/cms/servlet/cert/DoRevoke.java +++ b/base/common/src/com/netscape/cms/servlet/cert/DoRevoke.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.Enumeration; +import java.util.Hashtable; import java.util.Locale; import java.util.Vector; @@ -49,7 +50,6 @@ import com.netscape.certsrv.authorization.EAuthzAccessDenied; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.ForbiddenException; import com.netscape.certsrv.base.IArgBlock; -import com.netscape.certsrv.base.Nonces; import com.netscape.certsrv.base.PKIException; import com.netscape.certsrv.ca.ICRLIssuingPoint; import com.netscape.certsrv.ca.ICertificateAuthority; @@ -87,7 +87,6 @@ public class DoRevoke extends CMSServlet { private ICertificateRepository mCertDB = null; private String mFormPath = null; private IPublisherProcessor mPublisherProcessor = null; - private Nonces mNonces = null; private int mTimeLimits = 30; /* in seconds */ private IUGSubsystem mUG = null; private ICertUserLocator mUL = null; @@ -111,9 +110,6 @@ public class DoRevoke extends CMSServlet { if (mAuthority instanceof ICertificateAuthority) { mCertDB = ((ICertificateAuthority) mAuthority).getCertificateRepository(); - if (((ICertificateAuthority) mAuthority).noncesEnabled()) { - mNonces = ((ICertificateAuthority) mAuthority).getNonces(); - } } if (mAuthority instanceof ICertAuthority) { mPublisherProcessor = ((ICertAuthority) mAuthority).getPublisherProcessor(); @@ -401,14 +397,27 @@ public class DoRevoke extends CMSServlet { processor.setInvalidityDate(invalidityDate); processor.setComments(comments); + Hashtable<BigInteger, Long> nonceMap = new Hashtable<BigInteger, Long>(); + X509Certificate clientCert = getSSLClientCertificate(req); + if (mAuthority instanceof ICertificateAuthority) { - processor.setAuthority((ICertificateAuthority)mAuthority); - } + processor.setAuthority(certAuthority); - X509Certificate clientCert = getSSLClientCertificate(req); - String requestedNonce = req.getParameter("nonce"); - Long nonce = requestedNonce == null ? null : new Long(requestedNonce.trim()); - processor.validateNonce(clientCert, nonce); + if (certAuthority.noncesEnabled()) { + String nonces = req.getParameter("nonce"); + if (nonces == null) { + throw new ForbiddenException("Missing nonce."); + } + + // parse serial numbers and nonces + for (String s : nonces.split(",")) { + String[] elements = s.split(":"); + BigInteger serialNumber = new BigInteger(elements[0].trim()); + Long nonce = new Long(elements[1].trim()); + nonceMap.put(serialNumber, nonce); + } + } + } try { processor.createCRLExtension(); @@ -437,6 +446,14 @@ public class DoRevoke extends CMSServlet { rarg.addStringValue("serialNumber", targetCert.getSerialNumber().toString(16)); try { + if (mAuthority instanceof ICertificateAuthority && + certAuthority.noncesEnabled() && + !processor.isMemberOfSubsystemGroup(clientCert)) { + // validate nonce for each certificate + Long nonce = nonceMap.get(targetRecord.getSerialNumber()); + processor.validateNonce(req, "cert-revoke", targetRecord.getSerialNumber(), nonce); + } + processor.validateCertificateToRevoke(eeSubjectDN, targetRecord, false); processor.addCertificateToRevoke(targetCert); rarg.addStringValue("error", null); diff --git a/base/common/src/com/netscape/cms/servlet/cert/ReasonToRevoke.java b/base/common/src/com/netscape/cms/servlet/cert/ReasonToRevoke.java index 5b9cd7741..75e732676 100644 --- a/base/common/src/com/netscape/cms/servlet/cert/ReasonToRevoke.java +++ b/base/common/src/com/netscape/cms/servlet/cert/ReasonToRevoke.java @@ -18,8 +18,10 @@ package com.netscape.cms.servlet.cert; import java.io.IOException; +import java.util.ArrayList; import java.util.Enumeration; import java.util.Locale; +import java.util.Map; import java.util.Random; import javax.servlet.ServletConfig; @@ -30,13 +32,14 @@ import javax.servlet.http.HttpServletResponse; import netscape.security.x509.X509CertImpl; +import org.apache.commons.lang.StringUtils; + import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.authentication.IAuthToken; import com.netscape.certsrv.authorization.AuthzToken; import com.netscape.certsrv.authorization.EAuthzAccessDenied; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.IArgBlock; -import com.netscape.certsrv.base.Nonces; import com.netscape.certsrv.ca.ICertificateAuthority; import com.netscape.certsrv.dbs.certdb.ICertRecord; import com.netscape.certsrv.dbs.certdb.ICertificateRepository; @@ -65,7 +68,6 @@ public class ReasonToRevoke extends CMSServlet { private String mFormPath = null; private ICertificateAuthority mCA = null; private Random mRandom = null; - private Nonces mNonces = null; private int mTimeLimits = 30; /* in seconds */ public ReasonToRevoke() { @@ -88,7 +90,6 @@ public class ReasonToRevoke extends CMSServlet { if (mCA != null && mCA.noncesEnabled()) { mRandom = new Random(); - mNonces = mCA.getNonces(); } mTemplates.remove(CMSRequest.SUCCESS); @@ -222,14 +223,6 @@ public class ReasonToRevoke extends CMSServlet { header.addStringValue("revokeAll", revokeAll); header.addIntegerValue("totalRecordCount", totalRecordCount); - if (mNonces != null) { - long n = mRandom.nextLong(); - long m = mNonces.addNonce(n, getSSLClientCertificate(req)); - if ((n + m) != 0) { - header.addStringValue("nonce", Long.toString(m)); - } - } - try { if (mCA != null) { X509CertImpl caCert = mCA.getSigningUnit().getCertImpl(); @@ -248,6 +241,7 @@ public class ReasonToRevoke extends CMSServlet { Enumeration<ICertRecord> e = mCertDB.searchCertificates(revokeAll, totalRecordCount, mTimeLimits); + ArrayList<String> noncesList = new ArrayList<String>(); int count = 0; while (e != null && e.hasMoreElements()) { @@ -258,6 +252,17 @@ public class ReasonToRevoke extends CMSServlet { X509CertImpl xcert = rec.getCertificate(); if (xcert != null) + + if (mCA != null && mCA.noncesEnabled()) { + // generate nonce + long n = mRandom.nextLong(); + // store nonce in session + Map<Object, Long> nonces = mCA.getNonces(req, "cert-revoke"); + nonces.put(xcert.getSerialNumber(), n); + // store serial number and nonce + noncesList.add(xcert.getSerialNumber()+":"+n); + } + if (!(rec.getStatus().equals(ICertRecord.STATUS_REVOKED))) { count++; IArgBlock rarg = CMS.createArgBlock(); @@ -278,6 +283,11 @@ public class ReasonToRevoke extends CMSServlet { header.addIntegerValue("verifiedRecordCount", count); + if (mCA != null && mCA.noncesEnabled()) { + // return serial numbers and nonces to client + header.addStringValue("nonce", StringUtils.join(noncesList.toArray(), ",")); + } + } catch (EBaseException e) { log(ILogger.LL_FAILURE, "Error " + e); throw e; diff --git a/base/common/src/com/netscape/cms/servlet/cert/RequestProcessor.java b/base/common/src/com/netscape/cms/servlet/cert/RequestProcessor.java index 508cd72c1..b5063c243 100644 --- a/base/common/src/com/netscape/cms/servlet/cert/RequestProcessor.java +++ b/base/common/src/com/netscape/cms/servlet/cert/RequestProcessor.java @@ -17,7 +17,6 @@ // --- END COPYRIGHT BLOCK --- package com.netscape.cms.servlet.cert; -import java.security.cert.X509Certificate; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; @@ -33,6 +32,7 @@ import com.netscape.certsrv.authentication.IAuthToken; import com.netscape.certsrv.authorization.AuthzToken; import com.netscape.certsrv.authorization.EAuthzException; import com.netscape.certsrv.base.BadRequestDataException; +import com.netscape.certsrv.base.BadRequestException; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.EPropertyNotFound; import com.netscape.certsrv.base.IConfigStore; @@ -71,7 +71,8 @@ public class RequestProcessor extends CertProcessor { String profileId = ireq.getExtDataInString("profileId"); IProfile profile = ps.getProfile(profileId); - CertReviewResponse data = CertReviewResponseFactory.create(cmsReq, profile, nonces, locale); + CertReviewResponse data = CertReviewResponseFactory.create( + cmsReq, profile, authority.noncesEnabled(), locale); processRequest(req, data, request, op); return data; @@ -99,41 +100,27 @@ public class RequestProcessor extends CertProcessor { throw new EAuthzException(CMS.getUserMessage(locale, "CMS_AUTHORIZATION_ERROR")); } - if (nonces != null) { + if (authority.noncesEnabled()) { + Object id = data.getRequestId().toBigInteger(); + String requestNonce = data.getNonce(); - boolean nonceVerified = false; - if (requestNonce != null) { - long nonce = 0L; - try { - nonce = Long.parseLong(requestNonce.trim()); - } catch (NumberFormatException e) { - } - X509Certificate cert1 = nonces.getCertificate(nonce); - X509Certificate cert2 = getSSLClientCertificate(request); - if (cert1 == null) { - CMS.debug("CertRequestExecutor: Unknown nonce"); - } else if (cert1 != null && cert2 != null && cert1.equals(cert2)) { - nonceVerified = true; - nonces.removeNonce(nonce); - } - } else { - CMS.debug("CertRequestExecutor: Missing nonce"); - } - CMS.debug("CertRequestExecutor: nonceVerified=" + nonceVerified); - if (!nonceVerified) { - CMS.debug("nonce not verified"); - throw new EAuthzException(CMS.getUserMessage(locale, "CMS_AUTHORIZATION_ERROR")); + if (requestNonce == null) { + CMS.debug("RequestProcessor: Missing nonce"); + throw new BadRequestException("Missing nonce."); } + + Long nonce = new Long(requestNonce.trim()); + validateNonce(request, "cert-request", id, nonce); } - CMS.debug("CertRequestExecutor: processRequest: start serving"); + CMS.debug("RequestProcessor: processRequest: start serving"); RequestId requestId = data.getRequestId(); if (requestId == null || requestId.equals("")) { CMS.debug(CMS.getUserMessage(locale, "CMS_REQUEST_ID_NOT_FOUND")); throw new BadRequestDataException(CMS.getUserMessage(locale, "CMS_REQUEST_ID_NOT_FOUND")); } - CMS.debug("CertRequestExecutor: requestId=" + requestId); + CMS.debug("RequestProcessor: requestId=" + requestId); // check if the request is in one of the terminal states if (!req.getRequestStatus().equals(RequestStatus.PENDING)) { @@ -147,10 +134,10 @@ public class RequestProcessor extends CertProcessor { String profileId = req.getExtDataInString("profileId"); if (profileId == null || profileId.equals("")) { - CMS.debug("CertRequestExecutor: Profile Id not found in request"); + CMS.debug("RequestProcessor: Profile Id not found in request"); throw new EBaseException(CMS.getUserMessage(locale, "CMS_PROFILE_ID_NOT_FOUND")); } - CMS.debug("CertRequestExecutor: profileId=" + profileId); + CMS.debug("RequestProcessor: profileId=" + profileId); IProfile profile = ps.getProfile(profileId); if (profile == null) { @@ -158,7 +145,7 @@ public class RequestProcessor extends CertProcessor { throw new BadRequestDataException(CMS.getUserMessage(locale, "CMS_PROFILE_NOT_FOUND", profileId)); } if (!ps.isProfileEnable(profileId)) { - CMS.debug("CertRequestExecutor: Profile " + profileId + " not enabled"); + CMS.debug("RequestProcessor: Profile " + profileId + " not enabled"); throw new BadRequestDataException("Profile " + profileId + " not enabled"); } @@ -168,7 +155,7 @@ public class RequestProcessor extends CertProcessor { // assigned owner if (owner != null && owner.length() > 0) { if (!grantPermission(req, authToken)) { - CMS.debug("CertRequestExecutor: Permission not granted to assign request."); + CMS.debug("RequestProcessor: Permission not granted to assign request."); throw new EAuthzException(CMS.getUserMessage(locale, "CMS_PROFILE_DENY_OPERATION")); } } @@ -197,7 +184,7 @@ public class RequestProcessor extends CertProcessor { req.setRequestOwner(""); } } else { - CMS.debug("CertRequestExecutor: Permission not granted to approve/reject/cancel/update/validate/unassign request."); + CMS.debug("RequestProcessor: Permission not granted to approve/reject/cancel/update/validate/unassign request."); throw new EAuthzException(CMS.getUserMessage(locale, "CMS_PROFILE_DENY_OPERATION")); } } diff --git a/base/common/src/com/netscape/cms/servlet/cert/RevocationProcessor.java b/base/common/src/com/netscape/cms/servlet/cert/RevocationProcessor.java index 341314887..e555d1ac6 100644 --- a/base/common/src/com/netscape/cms/servlet/cert/RevocationProcessor.java +++ b/base/common/src/com/netscape/cms/servlet/cert/RevocationProcessor.java @@ -26,7 +26,12 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.Locale; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import com.netscape.certsrv.authorization.EAuthzException; import netscape.security.x509.CRLExtensions; import netscape.security.x509.CRLReasonExtension; import netscape.security.x509.InvalidityDateExtension; @@ -39,6 +44,7 @@ import com.netscape.certsrv.base.BadRequestException; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.EPropertyNotFound; import com.netscape.certsrv.base.ForbiddenException; +import com.netscape.certsrv.base.PKIException; import com.netscape.certsrv.base.UnauthorizedException; import com.netscape.certsrv.ca.ICertificateAuthority; import com.netscape.certsrv.dbs.certdb.CertId; @@ -188,47 +194,24 @@ public class RevocationProcessor extends CertProcessor { return request; } - public void validateNonce(X509Certificate clientCert, Long nonce) { + public boolean isMemberOfSubsystemGroup(X509Certificate clientCert) { - if (nonces != null) { - boolean nonceVerified = false; - boolean skipNonceVerification = false; + if (clientCert == null) { + return false; + } - if (clientCert != null) { - X509Certificate certChain[] = new X509Certificate[1]; - certChain[0] = clientCert; - IUser user = null; - try { - user = ul.locateUser(new Certificates(certChain)); - } catch (Exception e) { - CMS.debug("RevocationProcessor: Failed to map certificate '" + - clientCert.getSubjectDN().getName() + "' to user."); - } - if (ug.isMemberOf(user, "Subsystem Group")) { - skipNonceVerification = true; - } - } + try { + X509Certificate certChain[] = new X509Certificate[1]; + certChain[0] = clientCert; - if (nonce != null) { - X509Certificate storedCert = nonces.getCertificate(nonce); - if (storedCert == null) { - CMS.debug("RevocationProcessor: Unknown nonce"); + IUser user = ul.locateUser(new Certificates(certChain)); + return ug.isMemberOf(user, "Subsystem Group"); - } else if (clientCert != null && storedCert.equals(clientCert)) { - nonceVerified = true; - nonces.removeNonce(nonce); - } - } else { - CMS.debug("RevocationProcessor: Missing nonce"); - } - - CMS.debug("RevocationProcessor: nonceVerified=" + nonceVerified); - CMS.debug("RevocationProcessor: skipNonceVerification=" + skipNonceVerification); - if ((!nonceVerified) && (!skipNonceVerification)) { - throw new ForbiddenException("Invalid nonce."); - } + } catch (Exception e) { + CMS.debug("RevocationProcessor: Failed to map certificate '" + + clientCert.getSubjectDN().getName() + "' to user."); + return false; } - } public void validateCertificateToRevoke(String subjectDN, ICertRecord targetRecord, boolean revokingCACert) { diff --git a/base/common/src/com/netscape/cms/servlet/cert/RevocationServlet.java b/base/common/src/com/netscape/cms/servlet/cert/RevocationServlet.java index 4c4f7e9e0..d136c5ff9 100644 --- a/base/common/src/com/netscape/cms/servlet/cert/RevocationServlet.java +++ b/base/common/src/com/netscape/cms/servlet/cert/RevocationServlet.java @@ -23,6 +23,7 @@ import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.Enumeration; import java.util.Locale; +import java.util.Map; import java.util.Random; import javax.servlet.ServletConfig; @@ -42,7 +43,6 @@ import com.netscape.certsrv.authorization.AuthzToken; import com.netscape.certsrv.authorization.EAuthzAccessDenied; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.IArgBlock; -import com.netscape.certsrv.base.Nonces; import com.netscape.certsrv.ca.ICertificateAuthority; import com.netscape.certsrv.dbs.certdb.ICertRecord; import com.netscape.certsrv.dbs.certdb.ICertificateRepository; @@ -82,7 +82,6 @@ public class RevocationServlet extends CMSServlet { private boolean mRevokeByDN = true; private Random mRandom = null; - private Nonces mNonces = null; public RevocationServlet() { super(); @@ -109,7 +108,6 @@ public class RevocationServlet extends CMSServlet { if (mAuthority instanceof ICertificateAuthority) { if (((ICertificateAuthority) mAuthority).noncesEnabled()) { - mNonces = ((ICertificateAuthority) mAuthority).getNonces(); mRandom = new Random(); } } @@ -207,18 +205,21 @@ public class RevocationServlet extends CMSServlet { // header.addLongValue("validNotBefore", old_cert.getNotBefore().getTime()/1000); // header.addLongValue("validNotAfter", old_cert.getNotAfter().getTime()/1000); - if (mNonces != null) { - long n = mRandom.nextLong(); - long m = mNonces.addNonce(n, old_cert); - if ((n + m) != 0) { - header.addStringValue("nonce", Long.toString(m)); - } - } - boolean noInfo = false; X509CertImpl[] certsToRevoke = null; if (mAuthority instanceof ICertificateAuthority) { + + if (certAuthority.noncesEnabled()) { + // generate nonce + long n = mRandom.nextLong(); + // store nonce in session + Map<Object, Long> nonces = certAuthority.getNonces(cmsReq.getHttpReq(), "cert-revoke"); + nonces.put(old_serial_no, n); + // return serial number and nonce to client + header.addStringValue("nonce", old_serial_no+":"+n); + } + certsToRevoke = ((ICertificateAuthority) mAuthority).getCertificateRepository().getX509Certificates( old_cert.getSubjectDN().toString(), ICertificateRepository.ALL_UNREVOKED_CERTS); diff --git a/base/common/src/com/netscape/cms/servlet/processors/Processor.java b/base/common/src/com/netscape/cms/servlet/processors/Processor.java index 423d1bed5..42e1bca75 100644 --- a/base/common/src/com/netscape/cms/servlet/processors/Processor.java +++ b/base/common/src/com/netscape/cms/servlet/processors/Processor.java @@ -28,6 +28,7 @@ import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Locale; +import java.util.Map; import java.util.Map.Entry; import java.util.StringTokenizer; @@ -39,13 +40,14 @@ import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.authentication.AuthToken; import com.netscape.certsrv.authentication.IAuthToken; import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.authorization.EAuthzException; import com.netscape.certsrv.authorization.IAuthzSubsystem; +import com.netscape.certsrv.base.BadRequestException; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.EPropertyNotFound; import com.netscape.certsrv.base.IArgBlock; import com.netscape.certsrv.base.IConfigStore; import com.netscape.certsrv.base.MetaInfo; -import com.netscape.certsrv.base.Nonces; import com.netscape.certsrv.base.SessionContext; import com.netscape.certsrv.ca.ICertificateAuthority; import com.netscape.certsrv.dbs.certdb.ICertRecord; @@ -138,7 +140,6 @@ public class Processor { protected String authzResourceName; protected String authMgr; protected String getClientCert = "false"; - protected Nonces nonces; protected Locale locale; // subsystems @@ -179,10 +180,6 @@ public class Processor { throw new EBaseException("CertProcessor: authority is null"); } - if (authority.noncesEnabled()) { - nonces = authority.getNonces(); - } - queue = authority.getRequestQueue(); if (queue == null) { throw new EBaseException("CertProcessor: cannot get request queue"); @@ -1237,4 +1234,31 @@ public class Processor { return ILogger.SIGNED_AUDIT_EMPTY_VALUE; } } + + public void validateNonce( + HttpServletRequest servletRequest, + String name, + Object id, + Long nonce) throws EBaseException { + + if (nonce == null) { + throw new BadRequestException("Missing nonce."); + } + + Map<Object, Long> nonces = authority.getNonces(servletRequest, name); + + Long storedNonce = nonces.get(id); + if (storedNonce == null) { + throw new BadRequestException("Nonce for "+name+" "+id+" does not exist."); + } + + if (!nonce.equals(storedNonce)) { + CMS.debug("Processor: Invalid nonce"); + throw new EAuthzException(CMS.getUserMessage(locale, "CMS_AUTHORIZATION_ERROR")); + } + + nonces.remove(id); + + CMS.debug("Processor: Nonce verified"); + } } diff --git a/base/common/src/com/netscape/cms/servlet/profile/ProfileReviewServlet.java b/base/common/src/com/netscape/cms/servlet/profile/ProfileReviewServlet.java index 61a04a630..2b3ef83bb 100644 --- a/base/common/src/com/netscape/cms/servlet/profile/ProfileReviewServlet.java +++ b/base/common/src/com/netscape/cms/servlet/profile/ProfileReviewServlet.java @@ -19,6 +19,7 @@ package com.netscape.cms.servlet.profile; import java.util.Enumeration; import java.util.Locale; +import java.util.Map; import java.util.Random; import javax.servlet.ServletConfig; @@ -29,11 +30,9 @@ import javax.servlet.http.HttpServletResponse; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.authentication.IAuthToken; -import com.netscape.certsrv.authority.IAuthority; import com.netscape.certsrv.authorization.AuthzToken; import com.netscape.certsrv.authorization.EAuthzAccessDenied; import com.netscape.certsrv.base.EBaseException; -import com.netscape.certsrv.base.Nonces; import com.netscape.certsrv.ca.ICertificateAuthority; import com.netscape.certsrv.logging.ILogger; import com.netscape.certsrv.profile.EProfileException; @@ -68,8 +67,8 @@ public class ProfileReviewServlet extends ProfileServlet { private static final String PROP_AUTHORITY_ID = "authorityId"; private String mAuthorityId = null; + ICertificateAuthority authority = null; private Random mRandom = null; - private Nonces mNonces = null; public ProfileReviewServlet() { } @@ -84,12 +83,10 @@ public class ProfileReviewServlet extends ProfileServlet { super.init(sc); mAuthorityId = sc.getInitParameter(PROP_AUTHORITY_ID); - ICertificateAuthority authority = null; if (mAuthorityId != null) authority = (ICertificateAuthority) CMS.getSubsystem(mAuthorityId); if (authority != null && authority.noncesEnabled()) { - mNonces = authority.getNonces(); mRandom = new Random(); } } @@ -168,7 +165,6 @@ public class ProfileReviewServlet extends ProfileServlet { } // retrieve request - IAuthority authority = (IAuthority) CMS.getSubsystem(mAuthorityId); if (authority == null) { CMS.debug("ProfileReviewServlet: Authority " + mAuthorityId + @@ -253,12 +249,11 @@ public class ProfileReviewServlet extends ProfileServlet { } } - if (mNonces != null) { + if (authority != null && authority.noncesEnabled()) { long n = mRandom.nextLong(); - long m = mNonces.addNonce(n, getSSLClientCertificate(request)); - if ((n + m) != 0) { - args.set(ARG_REQUEST_NONCE, Long.toString(m)); - } + Map<Object, Long> nonces = authority.getNonces(request, "cert-request"); + nonces.put(req.getRequestId().toBigInteger(), n); + args.set(ARG_REQUEST_NONCE, Long.toString(n)); } args.set(ARG_REQUEST_ID, req.getRequestId().toString()); |