summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEndi Sukma Dewata <edewata@redhat.com>2013-01-23 12:10:52 -0600
committerEndi Sukma Dewata <edewata@redhat.com>2013-01-30 13:36:00 -0500
commit8de6872dd36f79ddaa5ea66381263d4152b0615b (patch)
tree73b4128b3863b44fd98b992a11c537bdb4edefd8
parent9fd77f53bd6238ee94b1ed5fe55dcfbfb475a93d (diff)
downloadpki-ticket-474-2.tar.gz
pki-ticket-474-2.tar.xz
pki-ticket-474-2.zip
Session-based nonces.ticket-474-2
Previously nonces were stored in a global map which might not scale well due to some issues: 1. The map uses the nonces as map keys. There were possible nonce collisions which required special handling. 2. The collision handling code was not thread safe. There were possible race conditions during concurrent modifications. 3. The map was shared and size limited. If there were a lot of users using the system, valid nonces could get pruned. 4. The map maps the nonces to client certificates. This limits the possible authentication methods that can be supported. Now the code has been modified such that each user has a private map in the user's session to store the nonces. Additional locking has been implemented to protect against concurrent modifications. The map now uses the target of the operation as the map key, eliminating possible collisions and allowing the use of other authentication methods. Since this is a private map, it's not affected by the number of users using the system. Ticket #474
-rw-r--r--base/ca/src/CMakeLists.txt10
-rw-r--r--base/ca/src/com/netscape/ca/CertificateAuthority.java41
-rw-r--r--base/common/src/com/netscape/certsrv/base/Nonces.java114
-rw-r--r--base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java6
-rw-r--r--base/common/src/com/netscape/cms/servlet/base/CMSServlet.java9
-rw-r--r--base/common/src/com/netscape/cms/servlet/cert/CertRequestDAO.java25
-rw-r--r--base/common/src/com/netscape/cms/servlet/cert/CertReviewResponseFactory.java6
-rw-r--r--base/common/src/com/netscape/cms/servlet/cert/CertService.java22
-rw-r--r--base/common/src/com/netscape/cms/servlet/cert/DoRevoke.java39
-rw-r--r--base/common/src/com/netscape/cms/servlet/cert/ReasonToRevoke.java32
-rw-r--r--base/common/src/com/netscape/cms/servlet/cert/RequestProcessor.java51
-rw-r--r--base/common/src/com/netscape/cms/servlet/cert/RevocationProcessor.java55
-rw-r--r--base/common/src/com/netscape/cms/servlet/cert/RevocationServlet.java23
-rw-r--r--base/common/src/com/netscape/cms/servlet/processors/Processor.java36
-rw-r--r--base/common/src/com/netscape/cms/servlet/profile/ProfileReviewServlet.java17
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());