[Pki-devel] [PATCH] random certificate serial numbers

Andrew Wnuk awnuk at redhat.com
Tue Feb 19 01:34:00 UTC 2013


This patch adds support for random certificate serial numbers.

Bug 912554.


-------------- next part --------------
Index: pki/dogtag/console-ui/CMSAdminRS.properties
===================================================================
--- pki/dogtag/console-ui/CMSAdminRS.properties	(revision 2521)
+++ pki/dogtag/console-ui/CMSAdminRS.properties	(working copy)
@@ -378,6 +378,12 @@
 CAGENERAL_COMBOBOX_ALGORITHM_VALUE_3=SHA256 with RSA
 CAGENERAL_COMBOBOX_ALGORITHM_VALUE_4=SHA512 with RSA
 CAGENERAL_COMBOBOX_ALGORITHM_VALUE_5=SHA1 with DSA
+CAGENERAL_BORDER_MANAGEMENT_LABEL=Serial Number Management
+CAGENERAL_CHECKBOX_MANAGEMENT_LABEL=Enable serial number management
+CAGENERAL_CHECKBOXL_MANAGEMENT_TTIP=Allow CA to manage serial numbers automatically
+CAGENERAL_BORDER_RANDOM_LABEL=Random Certificate Serial Numbers 
+CAGENERAL_CHECKBOX_RANDOM_LABEL=Enable random certificate serial numbers
+CAGENERAL_CHECKBOXL_RANDOM_TTIP=Allow CA to generate random certificate serial numbers
 CAGENERAL_BORDER_SERIAL_LABEL=Certificate Serial Number
 CAGENERAL_LABEL_SERIAL_LABEL=Next Serial Number: (0x)
 CAGENERAL_LABEL_SERIAL_TTIP=Specify the next serial number of the certificate that the CA issues
@@ -387,6 +393,9 @@
 CAGENERAL_BORDER_VALIDITY_LABEL=Certificate Validity
 CAGENERAL_CHECKBOX_VALIDITY_LABEL=Override validity nesting requirement
 CAGENERAL_CHECKBOXL_VALIDITY_TTIP=Allow CA to issue certificates with validity beyond that of the CA's signing certificate
+CAGENERAL_BORDER_RANDOM_VALIDITY_LABEL=Randomize Certificate Validity
+CAGENERAL_CHECKBOX_RANDOM_VALIDITY_LABEL=Randomize certificate validity
+CAGENERAL_CHECKBOXL_RANDOM_VALIDITY_TTIP=Allow CA to issue certificates with randomized validity
 CAGENERAL_DIALOG_NUMBERFORMAT_MESSAGE=You must specify a numeric value
 CAGENERAL_DIALOG_NUMBERFORMAT_TITLE=Error
 CAGENERAL_CHECKBOX_RA_LABEL=Enable registration authority interaction
Index: pki/base/common/src/com/netscape/cms/servlet/admin/CAAdminServlet.java
===================================================================
--- pki/base/common/src/com/netscape/cms/servlet/admin/CAAdminServlet.java	(revision 2521)
+++ pki/base/common/src/com/netscape/cms/servlet/admin/CAAdminServlet.java	(working copy)
@@ -1479,6 +1479,10 @@
         getSigningAlgConfig(params);
         getSerialConfig(params);
         getMaxSerialConfig(params);
+        params.add(Constants.PR_SN_MANAGEMENT,
+            Boolean.toString(mCA.getDBSubsystem().getEnableSerialMgmt()));
+        params.add(Constants.PR_RANDOM_SN,
+            Boolean.toString(mCA.getCertificateRepository().getEnableRandomSerialNumbers()));
   
         sendResponse(SUCCESS, null, params, resp);
     }
@@ -1555,6 +1559,11 @@
                 mCA.setStartSerial(value);
             } else if (key.equals(Constants.PR_MAXSERIAL)) {
                 mCA.setMaxSerial(value);
+            } else if (key.equals(Constants.PR_SN_MANAGEMENT)) {
+                mCA.getDBSubsystem().setEnableSerialMgmt(Boolean.valueOf(value));
+                //mCA.getCertificateRepository().setEnableSerialMgmt(Boolean.valueOf(value));
+            } else if (key.equals(Constants.PR_RANDOM_SN)) {
+                mCA.getCertificateRepository().setEnableRandomSerialNumbers(Boolean.valueOf(value), true);
             }
         }
 
Index: pki/base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java
===================================================================
--- pki/base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java	(revision 2521)
+++ pki/base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java	(working copy)
@@ -33,6 +33,7 @@
 import com.netscape.certsrv.policy.*;
 import com.netscape.certsrv.security.*;
 import com.netscape.certsrv.publish.*;
+import com.netscape.certsrv.dbs.*;
 import com.netscape.certsrv.dbs.certdb.*;
 import com.netscape.certsrv.dbs.crldb.*;
 import com.netscape.certsrv.dbs.replicadb.*;
@@ -465,6 +466,13 @@
     public IService getCAService();
 
     /**
+     * Retrieves the DB subsystem managing internal data storage.
+     *
+     * @return DB subsystem object
+     */
+    public IDBSubsystem getDBSubsystem();
+
+    /**
      * Returns the in-memory count of the processed OCSP requests.
      *
      * @return number of processed OCSP requests in memory
Index: pki/base/common/src/com/netscape/certsrv/common/Constants.java
===================================================================
--- pki/base/common/src/com/netscape/certsrv/common/Constants.java	(revision 2521)
+++ pki/base/common/src/com/netscape/certsrv/common/Constants.java	(working copy)
@@ -341,10 +341,14 @@
      * Certificate Authority
      *========================================================*/
     public final static String PR_VALIDITY = "validity";
+    //public final static String PR_RANDOM_VALIDITY = "randomValidity";
+    //public final static String PR_RANDOM_VALIDITY_BITS = "randomValidityBits";
     public final static String PR_DEFAULT_ALGORITHM = "defaultSigningAlgorithm";
     public final static String PR_ALL_ALGORITHMS = "allSigningAlgorithms";
     public final static String PR_SERIAL = "startSerialNumber";
     public final static String PR_MAXSERIAL = "maxSerialNumber";
+    public final static String PR_SN_MANAGEMENT = "serialNumberManagement";
+    public final static String PR_RANDOM_SN = "randomSerialNumbers";
 
     /*========================================================
      * Access Control
Index: pki/base/common/src/com/netscape/certsrv/dbs/repository/IRepositoryRecord.java
===================================================================
--- pki/base/common/src/com/netscape/certsrv/dbs/repository/IRepositoryRecord.java	(revision 2521)
+++ pki/base/common/src/com/netscape/certsrv/dbs/repository/IRepositoryRecord.java	(working copy)
@@ -37,6 +37,7 @@
 
 	public final static String ATTR_SERIALNO = "serialNo";
 	public final static String ATTR_PUB_STATUS = "publishingStatus";
+	public final static String ATTR_DESCRIPTION = "description";
 
 	/**
 	 * Retrieves serial number.
@@ -46,4 +47,6 @@
 	public BigInteger getSerialNumber();
 
 	public String getPublishingStatus();
+
+	public String getDescription();
 }
Index: pki/base/common/src/com/netscape/certsrv/dbs/IDBSubsystem.java
===================================================================
--- pki/base/common/src/com/netscape/certsrv/dbs/IDBSubsystem.java	(revision 2521)
+++ pki/base/common/src/com/netscape/certsrv/dbs/IDBSubsystem.java	(working copy)
@@ -205,6 +205,39 @@
     public void setEnableSerialMgmt(boolean value) throws EBaseException;
 
     /**
+     * Gets replica ID
+     *
+     * @return replica ID
+     */
+    public int getReplicaID();
+
+    /**
+     * Gets internal DB configuration store
+     *
+     * @return internal DB configuration store
+     */
+    public IConfigStore getConfigStore();
+
+    /**
+     * Gets DB subsystem configuration store
+     *
+     * @return DB subsystem configuration store
+     */
+    public IConfigStore getDBConfigStore();
+
+    /**
+     * Gets attribute value for specified entry
+     *
+     * @param dn            entry's distinguished name 
+     * @param attrName      attribute's name 
+     * @param defaultValue  attribute's default value 
+     * @param errorValue    attribute's error value 
+     * @return attribute value
+     */
+    public String getEntryAttribute(String dn, String attrName,
+                                    String defaultValue, String errorValue);
+
+    /**
      * Returns LDAP connection to connection pool.
      *
      * @param conn connection to be returned
Index: pki/base/common/src/com/netscape/certsrv/dbs/certdb/ICertificateRepository.java
===================================================================
--- pki/base/common/src/com/netscape/certsrv/dbs/certdb/ICertificateRepository.java	(revision 2521)
+++ pki/base/common/src/com/netscape/certsrv/dbs/certdb/ICertificateRepository.java	(working copy)
@@ -508,5 +508,22 @@
      */
     public void removeCertRecords(BigInteger beginS, BigInteger endS) throws EBaseException;
 
+    /**
+     * Retrieves serial number management mode.
+     *
+     * @return serial number management mode,
+     * "true" indicates random serial number management,
+     * "false" indicates sequential serial number management.
+     */
+    public boolean getEnableRandomSerialNumbers();
+
+    /**
+     * Sets serial number management mode for certificates..
+     *
+     * @param random "true" sets random serial number management, "false" sequential
+     * @param updateMode "true" updates "description" attribute in certificate repository
+     */
+    public void setEnableRandomSerialNumbers(boolean random, boolean updateMode);
+
     public void shutdown();
 }
Index: pki/base/common/src/com/netscape/cmscore/dbs/DBSubsystem.java
===================================================================
--- pki/base/common/src/com/netscape/cmscore/dbs/DBSubsystem.java	(revision 2521)
+++ pki/base/common/src/com/netscape/cmscore/dbs/DBSubsystem.java	(working copy)
@@ -59,6 +59,7 @@
     private DBRegistry mRegistry = null;
     private String mBaseDN = null;
     private ISubsystem mOwner = null;
+    private int mReplicaID = -1;
 
     private Hashtable[] mRepos = null;
 
@@ -141,8 +142,6 @@
     private static final String PROP_INCREMENT_NAME = "increment_name";
     private static final String PROP_RANGE_DN="rangeDN";
 
-    private static final BigInteger BI_ONE = new BigInteger("1");
-
     private ILogger mLogger = null;
  
     // singleton enforcement
@@ -212,6 +211,10 @@
         mEnableSerialMgmt = v;
     }
 
+    public int getReplicaID() {
+        return mReplicaID;
+    }
+
     public BigInteger getNextSerialConfig() {
         return mNextSerialConfig;
     }
@@ -437,7 +440,7 @@
             conn.modify( dn, mods );
 
             // Add new range object
-            String endRange = nextRangeNo.add(incrementNo).subtract(BI_ONE).toString();
+            String endRange = nextRangeNo.add(incrementNo).subtract(BigInteger.ONE).toString();
             LDAPAttributeSet attrs = new LDAPAttributeSet();
             attrs.add(new LDAPAttribute("objectClass", "top"));
             attrs.add(new LDAPAttribute("objectClass", "pkiRange"));
@@ -449,6 +452,8 @@
             String dn2 = "cn=" + nextRange + "," + rangeDN;
             LDAPEntry rangeEntry = new LDAPEntry(dn2, attrs);
             conn.add(rangeEntry);
+            CMS.debug("DBSubsystem: getNextRange  Next range has been added: " +
+                      nextRange + " - " + endRange);
         } catch (Exception e) {
             CMS.debug("DBSubsystem: getNextRange. Unable to provide next range :" + e);
             e.printStackTrace();
@@ -547,6 +552,7 @@
                 PROP_NEXT_SERIAL_NUMBER, "0"), 16);
 
             mEnableSerialMgmt = mDBConfig.getBoolean(PROP_ENABLE_SERIAL_MGMT, false);
+            CMS.debug("DBSubsystem: init()  mEnableSerialMgmt="+mEnableSerialMgmt);
 
             // populate the certs hash entry
             Hashtable certs = new Hashtable();
@@ -800,14 +806,72 @@
                 reg.registerAttribute(IRepositoryRecord.ATTR_PUB_STATUS,
                     new StringMapper(RepositorySchema.LDAP_ATTR_PUB_STATUS));
             }
+            if (!reg.isAttributeRegistered(IRepositoryRecord.ATTR_DESCRIPTION)) {
+                reg.registerAttribute(IRepositoryRecord.ATTR_DESCRIPTION,
+                    new StringMapper(RepositorySchema.LDAP_ATTR_DESCRIPTION));
+            }
 
         } catch (EBaseException e) {
             if (CMS.isPreOpMode())
                 return;
             throw e;
         }
+
+        if (!CMS.isPreOpMode()) {
+            String dn = null;
+            try {
+                dn = "cn=replica,cn=\""+mBaseDN+"\",cn=mapping tree,cn=config";
+                mReplicaID = Integer.parseInt(getEntryAttribute(dn, "nsDS5ReplicaId", "0", "-1"));
+                CMS.debug("DBSubsystem: init()  mReplicaID="+mReplicaID);
+            } catch (Exception e) {
+                CMS.debug("DBSubsystem: init(). Unable to identify replica ID:" + e.getMessage());
+            }
+        }
     }
 
+    public String getEntryAttribute(String dn, String attrName,
+                                    String defaultValue, String errorValue) {
+        LDAPConnection conn = null;
+        String attrValue = null;
+        //CMS.debug("DBSubsystem: getEntryAttribute:  dn="+dn+"  attrName="+attrName+
+        //          "  defaultValue="+defaultValue+"  errorValue="+errorValue);
+        try {
+            conn = mLdapConnFactory.getConn();
+            String[] attrs = { attrName };
+            LDAPEntry entry = conn.read(dn, attrs);
+            if (entry != null) {
+                LDAPAttribute attr =  entry.getAttribute(attrName);
+                if (attr != null) {
+                    attrValue = (String) attr.getStringValues().nextElement();
+                } else {
+                    attrValue = defaultValue;
+                }
+            } else {
+                attrValue = errorValue;
+            }
+        } catch (LDAPException e) {
+            CMS.debug("DBSubsystem: getEntryAttribute  LDAPException  code="+e.getLDAPResultCode());
+            if (e.getLDAPResultCode() == LDAPException.NO_SUCH_OBJECT) {
+                attrValue = defaultValue;
+            }
+        } catch (Exception e) {
+            CMS.debug("DBSubsystem: getEntryAttribute. Unable to retrieve '"+attrName+"': "+ e);
+            attrValue = errorValue;
+        } finally {
+            try {
+                if ((conn != null) && (mLdapConnFactory != null)) {
+                    CMS.debug("Releasing ldap connection");
+                    mLdapConnFactory.returnConn(conn);
+                }
+            } catch (Exception e) {
+                CMS.debug("Error releasing the ldap connection" + e.toString());
+            }
+        }
+        CMS.debug("DBSubsystem: getEntryAttribute:  dn="+dn+"  attr="+attrName+":"+attrValue+";");
+
+        return attrValue;
+    }
+
     /**
      * Starts up this service.
      */
@@ -815,13 +879,20 @@
     }
 	
     /**
-     * Retrieves configuration store.
+     * Retrieves internal DB configuration store.
      */
     public IConfigStore getConfigStore() {
         return mConfig;
     }
 
     /**
+     * Retrieves DB subsystem configuration store.
+     */
+    public IConfigStore getDBConfigStore() {
+        return mDBConfig;
+    }
+
+    /**
      * Retrieves base DN of backend database.
      */
     public String getBaseDN() {
Index: pki/base/common/src/com/netscape/cmscore/dbs/RepositoryRecord.java
===================================================================
--- pki/base/common/src/com/netscape/cmscore/dbs/RepositoryRecord.java	(revision 2521)
+++ pki/base/common/src/com/netscape/cmscore/dbs/RepositoryRecord.java	(working copy)
@@ -41,11 +41,13 @@
 
     private BigInteger mSerialNo = null;
     private String mPublishingStatus = null;
+    private String mDescription = null;
 
     protected static Vector mNames = new Vector();
     static {
         mNames.addElement(IRepositoryRecord.ATTR_SERIALNO);
         mNames.addElement(IRepositoryRecord.ATTR_PUB_STATUS);
+        mNames.addElement(IRepositoryRecord.ATTR_DESCRIPTION);
     }
 
     /**
@@ -63,6 +65,8 @@
             mSerialNo = (BigInteger) obj;
         } else if (name.equalsIgnoreCase(IRepositoryRecord.ATTR_PUB_STATUS)) {
             mPublishingStatus = (String) obj;
+        } else if (name.equalsIgnoreCase(IRepositoryRecord.ATTR_DESCRIPTION)) {
+            mDescription = (String) obj;
         } else {
             throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name));
         }
@@ -76,6 +80,8 @@
             return mSerialNo;
         } else if (name.equalsIgnoreCase(IRepositoryRecord.ATTR_PUB_STATUS)) {
             return mPublishingStatus;
+        } else if (name.equalsIgnoreCase(IRepositoryRecord.ATTR_DESCRIPTION)) {
+            return mDescription;
         } else {
             throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name));
         }
@@ -109,4 +115,8 @@
     public String getPublishingStatus() {
         return mPublishingStatus;
     }
+
+    public String getDescription() {
+        return mDescription;
+    }
 }
Index: pki/base/common/src/com/netscape/cmscore/dbs/RepositorySchema.java
===================================================================
--- pki/base/common/src/com/netscape/cmscore/dbs/RepositorySchema.java	(revision 2521)
+++ pki/base/common/src/com/netscape/cmscore/dbs/RepositorySchema.java	(working copy)
@@ -41,4 +41,5 @@
     public static final String LDAP_OC_REPOSITORY = "repository";
     public static final String LDAP_ATTR_SERIALNO = "serialno";
     public static final String LDAP_ATTR_PUB_STATUS = "publishingStatus";
+    public final static String LDAP_ATTR_DESCRIPTION = "description";
 }
Index: pki/base/common/src/com/netscape/cmscore/dbs/Repository.java
===================================================================
--- pki/base/common/src/com/netscape/cmscore/dbs/Repository.java	(revision 2521)
+++ pki/base/common/src/com/netscape/cmscore/dbs/Repository.java	(working copy)
@@ -48,9 +48,7 @@
 
 public abstract class Repository implements IRepository {
 
-    private static final BigInteger BI_ONE = new BigInteger("1");
     private BigInteger BI_INCREMENT = null;
-    private static final BigInteger BI_ZERO = new BigInteger("0");
     // (the next serialNo to be issued) - 1
     private BigInteger mSerialNo = null; 
     // the serialNo attribute stored in db
@@ -61,8 +59,10 @@
     private String mNextMaxSerial = null;
     private String mNextMinSerial = null;
 
-    private BigInteger mMinSerialNo = null;
-    private BigInteger mMaxSerialNo = null;
+    protected boolean mEnableRandomSerialNumbers = false;
+    protected BigInteger mCounter = null;
+    protected BigInteger mMinSerialNo = null;
+    protected BigInteger mMaxSerialNo = null;
     private BigInteger mNextMinSerialNo = null;
     private BigInteger mNextMaxSerialNo = null;
 
@@ -152,6 +152,7 @@
         }
 
         BigInteger serial = rec.getSerialNumber();
+        CMS.debug("Repository: getSerialNumber  serial="+serial);
 
         if (!mInit) {
             // cms may crash after issue a cert but before update 
@@ -161,7 +162,7 @@
                         serial + "," + mBaseDN);
 
                 if (obj != null) {
-                    serial = serial.add(BI_ONE);
+                    serial = serial.add(BigInteger.ONE);
                     setSerialNumber(serial);
                 }
             }catch (EBaseException e) {
@@ -249,6 +250,9 @@
        return mMinSerial;
     }
 
+    protected void setLastSerialNo(BigInteger lastSN) {
+        mLastSerialNo = lastSN;
+    }
 
     /**
      * init serial number cache
@@ -323,6 +327,11 @@
 
     }
    
+    protected void initCacheIfNeeded() throws EBaseException {
+        if (mLastSerialNo == null) 
+            initCache();
+    }
+
     /**
      * get the next serial number in cache
      */
@@ -331,7 +340,7 @@
         CMS.debug("Repository:In getTheSerialNumber " );
         if (mLastSerialNo == null) 
             initCache();
-        BigInteger serial = new BigInteger((mLastSerialNo.add(BI_ONE)).toString());
+        BigInteger serial = mLastSerialNo.add(BigInteger.ONE);
 
         if (mMaxSerialNo != null && serial.compareTo(mMaxSerialNo) > 0)
             return null;
@@ -360,7 +369,7 @@
         // < BI_INCREMENT and server restart right afterwards.
         mDB.setNextSerialConfig(num);
 
-        mSerialNo = num.subtract(BI_ONE);
+        mSerialNo = num.subtract(BigInteger.ONE);
         mNext = num.add(BI_INCREMENT);
         setSerialNumber(mNext);
     }
@@ -379,23 +388,43 @@
  
         if (mLastSerialNo == null) {
             initCache();
-
-            mLastSerialNo = mLastSerialNo.add(BI_ONE);
-            
-          
-        } else {
-            mLastSerialNo = mLastSerialNo.add(BI_ONE);
         }
-
-        if( mLastSerialNo == null ) {
+        if (mLastSerialNo == null) {
             CMS.debug( "Repository::getNextSerialNumber() " +
                        "- mLastSerialNo is null!" );
             throw new EBaseException( "mLastSerialNo is null" );
         }
 
+        mLastSerialNo = mLastSerialNo.add(BigInteger.ONE);
+
+        checkRange();
+
+        BigInteger retSerial = new BigInteger(mLastSerialNo.toString());
+
+        CMS.debug("Repository: getNextSerialNumber: returning retSerial " + retSerial);
+        return retSerial; 
+    }
+
+    /**
+     * Checks to see if range needs to be switched.
+     *      
+     * @exception EBaseException thrown when next range is not allocated
+     */
+    protected void checkRange() throws EBaseException 
+    {
         // check if we have reached the end of the range
         // if so, move to next range
-        if (mLastSerialNo.compareTo( mMaxSerialNo ) > 0 ) {
+        BigInteger randomLimit = null;
+        if ((this instanceof ICertificateRepository) &&
+            mDB.getEnableSerialMgmt() && mEnableRandomSerialNumbers) {
+            randomLimit = mMaxSerialNo.subtract(mMinSerialNo).add(BigInteger.ONE);
+            randomLimit = randomLimit.subtract(mLowWaterMarkNo.shiftRight(1));
+            CMS.debug("Repository: checkRange  randomLimit="+randomLimit);
+        }
+        CMS.debug("Repository: checkRange  mLastSerialNo="+mLastSerialNo);
+        if (mLastSerialNo.compareTo( mMaxSerialNo ) > 0 ||
+            (randomLimit != null && mCounter.compareTo(randomLimit) > 0)) {
+
             if (mDB.getEnableSerialMgmt()) {
                 CMS.debug("Reached the end of the range.  Attempting to move to next range");
                 mMinSerialNo = mNextMinSerialNo;
@@ -409,8 +438,8 @@
                 }
 
                 // persist the changes
-                mDB.setMinSerialConfig(mRepo, mMinSerialNo.toString());
-                mDB.setMaxSerialConfig(mRepo, mMaxSerialNo.toString());
+                mDB.setMinSerialConfig(mRepo, mMinSerialNo.toString(mRadix));
+                mDB.setMaxSerialConfig(mRepo, mMaxSerialNo.toString(mRadix));
                 mDB.setNextMinSerialConfig(mRepo, null);
                 mDB.setNextMaxSerialConfig(mRepo, null);
             } else {
@@ -418,11 +447,6 @@
                         mLastSerialNo.toString()));
             }
         }
-
-        BigInteger retSerial = new BigInteger(mLastSerialNo.toString());
-
-        CMS.debug("Repository: getNextSerialNumber: returning retSerial " + retSerial);
-        return retSerial; 
     }
 
     /**
@@ -445,13 +469,19 @@
         if (mLastSerialNo == null)
             initCache();
 
-        BigInteger numsInRange = mMaxSerialNo.subtract(mLastSerialNo);
+        BigInteger numsInRange = null;
+        if ((this instanceof ICertificateRepository) &&
+            mDB.getEnableSerialMgmt() && mEnableRandomSerialNumbers) {
+            numsInRange = (mMaxSerialNo.subtract(mMinSerialNo)).subtract(mCounter);
+        } else {
+            numsInRange = mMaxSerialNo.subtract(mLastSerialNo);
+        }
         BigInteger numsInNextRange = null;
         BigInteger numsAvail = null;
         CMS.debug("Serial numbers left in range: " + numsInRange.toString());
         CMS.debug("Last Serial Number: " + mLastSerialNo.toString());
         if ((mNextMaxSerialNo != null) && (mNextMinSerialNo != null)) {
-            numsInNextRange = mNextMaxSerialNo.subtract(mNextMinSerialNo);
+            numsInNextRange = mNextMaxSerialNo.subtract(mNextMinSerialNo).add(BigInteger.ONE);
             numsAvail = numsInRange.add(numsInNextRange);
             CMS.debug("Serial Numbers in next range: " + numsInNextRange.toString());
             CMS.debug("Serial Numbers available: " + numsAvail.toString());
@@ -467,7 +497,7 @@
                 CMS.debug("Next Range not available");
             } else {
                 CMS.debug("nNextMinSerialNo has been set to " + mNextMinSerialNo.toString(mRadix));
-                mNextMaxSerialNo = mNextMinSerialNo.add(mIncrementNo);
+                mNextMaxSerialNo = mNextMinSerialNo.add(mIncrementNo).subtract(BigInteger.ONE);
                 numsAvail = numsAvail.add(mIncrementNo);
                 mDB.setNextMinSerialConfig(mRepo, mNextMinSerialNo.toString(mRadix));
                 mDB.setNextMaxSerialConfig(mRepo, mNextMaxSerialNo.toString(mRadix));
Index: pki/base/common/src/com/netscape/cmscore/dbs/CertificateRepository.java
===================================================================
--- pki/base/common/src/com/netscape/cmscore/dbs/CertificateRepository.java	(revision 2521)
+++ pki/base/common/src/com/netscape/cmscore/dbs/CertificateRepository.java	(working copy)
@@ -52,7 +52,15 @@
 public class CertificateRepository extends Repository
     implements ICertificateRepository {
 
-    public final String CERT_X509ATTRIBUTE = "x509signedcert";
+    private static final String PROP_ENABLE_RANDOM_SERIAL_NUMBERS = "enableRandomSerialNumbers";
+    private static final String PROP_RANDOM_SERIAL_NUMBER_COUNTER = "randomSerialNumberCounter";
+    private static final String PROP_FORCE_MODE_CHANGE = "forceModeChange";
+    private static final String PROP_RANDOM_MODE = "random";
+    private static final String PROP_SEQUENTIAL_MODE = "sequential";
+    private static final String PROP_COLLISION_RECOVERY_STEPS = "collisionRecoverySteps";
+    private static final String PROP_COLLISION_RECOVERY_REGENERATIONS = "collisionRecoveryRegenerations";
+    private static final BigInteger BI_MINUS_ONE = (BigInteger.ZERO).subtract(BigInteger.ONE);
+    private final int REPLICA_BITS = 16;
 
     private IDBSubsystem mDBService;
     private String mBaseDN;
@@ -66,6 +74,18 @@
     private int mTransitMaxRecords = 1000000;
     private int mTransitRecordPageSize = 200;
 
+    private Random mRandom = null;
+    private int mBitLength = 0;
+    private BigInteger mRangeSize = null;
+    private BigInteger mRandomRangeSize = null;
+    private BigInteger mReplicaID = null;
+    private int mMinRandomBitLength = 4;
+    private int mReplicaBitLength = REPLICA_BITS;
+    private int mMaxCollisionRecoverySteps = 10;
+    private int mMaxCollisionRecoveryRegenerations = 3;
+    private IConfigStore mDBConfig = null;
+    private boolean mForceModeChange = false;
+
     /**
      * Constructs a certificate repository.
      */
@@ -75,17 +95,297 @@
         mBaseDN = certRepoBaseDN;
       
         mDBService = dbService;
-
-        // registers CMS database attributes
-        IDBRegistry reg = dbService.getRegistry();
-
-        IConfigStore cfg = mDBService.getConfigStore();
+        mDBConfig = mDBService.getDBConfigStore();
     }
 
     public ICertRecord createCertRecord(BigInteger id, Certificate cert, MetaInfo meta) {
         return new CertRecord(id, cert, meta);
     }
 
+    public boolean getEnableRandomSerialNumbers() {
+        return mEnableRandomSerialNumbers;
+    }
+
+    public void setEnableRandomSerialNumbers(boolean random, boolean updateMode) {
+        if (mEnableRandomSerialNumbers ^ random) {
+            mEnableRandomSerialNumbers = random;
+            CMS.debug("CertificateRepository:  setEnableRandomSerialNumbers   switching to " +
+                      ((random)?PROP_RANDOM_MODE:PROP_SEQUENTIAL_MODE) + " mode");
+            if (updateMode) {
+                setCertificateRepositoryMode((mEnableRandomSerialNumbers)? PROP_RANDOM_MODE: PROP_SEQUENTIAL_MODE);
+            }
+            mDBConfig.putBoolean(PROP_ENABLE_RANDOM_SERIAL_NUMBERS, mEnableRandomSerialNumbers);
+
+            BigInteger lastSerialNumber = null;
+            try {
+                lastSerialNumber = getLastSerialNumberInRange(mMinSerialNo,mMaxSerialNo);
+            } catch (Exception e) {
+            }
+            if (lastSerialNumber != null) {
+                super.setLastSerialNo(lastSerialNumber);
+                if (mEnableRandomSerialNumbers) {
+                    mCounter = lastSerialNumber.subtract(mMinSerialNo).add(BigInteger.ONE);
+                    CMS.debug("CertificateRepository:  setEnableRandomSerialNumbers  mCounter="+
+                               mCounter+"="+lastSerialNumber+"-"+mMinSerialNo+"+1");
+                    long t = System.currentTimeMillis();
+                    mDBConfig.putString(PROP_RANDOM_SERIAL_NUMBER_COUNTER, mCounter.toString()+","+t);
+                } else {
+                    mCounter = BI_MINUS_ONE;
+                    mDBConfig.putString(PROP_RANDOM_SERIAL_NUMBER_COUNTER, mCounter.toString());
+                }
+            }
+
+            try {
+                CMS.getConfigStore().commit(false);
+            } catch (Exception e) {
+            }
+        }
+    }
+
+    private BigInteger getRandomNumber() throws EBaseException {
+        BigInteger randomNumber = null;
+
+        if (mRandom == null) {
+            mRandom = new Random();
+        }
+        super.initCacheIfNeeded();
+
+        if (mRangeSize == null || mReplicaID == null) {
+            mRangeSize = (mMaxSerialNo.subtract(mMinSerialNo)).add(BigInteger.ONE);
+            mBitLength = mRangeSize.bitLength();
+            int rid = mDBService.getReplicaID();
+            rid = -1;  // shared ranges using replica IDs are postponed
+            if (rid > -1) {
+                mReplicaID = new BigInteger((new Integer(rid)).toString());
+            } else {
+                mReplicaBitLength = 0;
+            }
+            mRandomRangeSize = mRangeSize.shiftRight(mReplicaBitLength);
+        }
+        if (mBitLength - mReplicaBitLength < mMinRandomBitLength) {
+            CMS.debug("CertificateRepository: getRandomNumber:  Range size is too small to support random certificate serial numbers.");
+            throw new EBaseException ("Range size is too small to support random certificate serial numbers.");
+        }
+        randomNumber = new BigInteger((mBitLength-mReplicaBitLength), mRandom);
+        randomNumber = (randomNumber.multiply(mRandomRangeSize)).shiftRight(mBitLength-mReplicaBitLength);
+        CMS.debug("CertificateRepository: getRandomNumber  randomNumber="+randomNumber);
+
+        return randomNumber; 
+    }
+
+    private BigInteger getRandomSerialNumber(BigInteger randomNumber) throws EBaseException {
+        BigInteger nextSerialNumber = null;
+
+        if (mReplicaBitLength > 0) {
+            nextSerialNumber = (randomNumber.shiftLeft(mReplicaBitLength)).add(mReplicaID);
+        } else {
+            nextSerialNumber = randomNumber;
+        }
+        nextSerialNumber = (nextSerialNumber.add(mMinSerialNo)).subtract(BigInteger.ONE);
+        CMS.debug("CertificateRepository: getRandomSerialNumber  nextSerialNumber="+nextSerialNumber);
+
+        return nextSerialNumber; 
+    }
+
+    private BigInteger checkSerialNumbers(BigInteger randomNumber, BigInteger serialNumber) throws EBaseException {
+        BigInteger nextSerialNumber = null;
+        BigInteger initialRandomNumber = randomNumber;
+        BigInteger delta = BigInteger.ZERO;
+        int i = 0;
+        int n = mMaxCollisionRecoverySteps;
+
+        do {
+            CMS.debug("CertificateRepository: checkSerialNumbers  checking("+(i+1)+")="+serialNumber);
+            try {
+                if (readCertificateRecord(serialNumber) != null) {
+                    CMS.debug("CertificateRepository: checkSerialNumbers  collision detected for serialNumber="+serialNumber);
+                }
+            } catch (EDBRecordNotFoundException nfe) {
+                CMS.debug("CertificateRepository: checkSerialNumbers  serial number "+serialNumber+" is available");
+                nextSerialNumber = serialNumber;
+            } catch (Exception e) {
+                CMS.debug("CertificateRepository: checkSerialNumbers  Exception="+e.getMessage());
+            }
+
+            if (nextSerialNumber == null) {
+                if (i%2 == 0) {
+                    delta = delta.add(BigInteger.ONE);
+                    serialNumber = getRandomSerialNumber(initialRandomNumber.add(delta));
+
+                    if (mMaxSerialNo != null && serialNumber.compareTo(mMaxSerialNo) > 0) {
+                        serialNumber = getRandomSerialNumber(initialRandomNumber.subtract(delta));
+                        i++;
+                        n++;
+                    }
+                } else {
+                    serialNumber = getRandomSerialNumber(initialRandomNumber.subtract(delta));
+                    if (mMinSerialNo != null && serialNumber.compareTo(mMinSerialNo) < 0) {
+                        delta = delta.add(BigInteger.ONE);
+                        serialNumber = getRandomSerialNumber(initialRandomNumber.add(delta));
+                        i++;
+                        n++;
+                    }
+                }
+                i++;
+            }
+        } while (nextSerialNumber == null && i < n);
+
+        return nextSerialNumber; 
+    }
+
+    private Object nextSerialNumberMonitor = new Object();
+
+    public BigInteger getNextSerialNumber() throws
+            EBaseException {
+
+        BigInteger nextSerialNumber = null;
+        BigInteger randomNumber = null;
+
+        synchronized (nextSerialNumberMonitor) {
+            CMS.debug("CertificateRepository: getNextSerialNumber  mEnableRandomSerialNumbers="+mEnableRandomSerialNumbers);
+
+            if (mEnableRandomSerialNumbers) {
+                int i = 0;
+                do {
+                    if (i > 0) {
+                        CMS.debug("CertificateRepository: getNextSerialNumber  regenerating serial number");
+                    }
+                    randomNumber = getRandomNumber();
+                    nextSerialNumber = getRandomSerialNumber(randomNumber);
+                    nextSerialNumber = checkSerialNumbers(randomNumber, nextSerialNumber);
+                    i++;
+                } while (nextSerialNumber == null && i < mMaxCollisionRecoveryRegenerations);
+
+                if (nextSerialNumber == null) {
+                    CMS.debug("CertificateRepository: in getNextSerialNumber  nextSerialNumber is null");
+                    throw new EBaseException( "nextSerialNumber is null" );
+                }
+
+                if (mCounter.compareTo(BigInteger.ZERO) >= 0 &&
+                    mMinSerialNo != null && mMaxSerialNo != null &&
+                    nextSerialNumber != null &&
+                    nextSerialNumber.compareTo(mMinSerialNo) >= 0 &&
+                    nextSerialNumber.compareTo(mMaxSerialNo) <= 0) {
+                    mCounter = mCounter.add(BigInteger.ONE);
+                }
+                CMS.debug("CertificateRepository: getNextSerialNumber  nextSerialNumber="+
+                          nextSerialNumber+"  mCounter="+mCounter);
+
+                super.checkRange();
+            } else {
+                nextSerialNumber = super.getNextSerialNumber();
+            }
+        }
+
+        return nextSerialNumber; 
+    }
+
+    private void updateCounter() {
+        CMS.debug("CertificateRepository: updateCounter  mEnableRandomSerialNumbers="+
+                  mEnableRandomSerialNumbers+"  mCounter="+mCounter);
+        try {
+            super.initCacheIfNeeded();
+        } catch (Exception e) {
+            CMS.debug("CertificateRepository: updateCounter  Exception from initCacheIfNeeded: "+e.getMessage());
+        }
+
+        String crMode = mDBService.getEntryAttribute(mBaseDN, IRepositoryRecord.ATTR_DESCRIPTION, "", null);
+
+        boolean modeChange = (mEnableRandomSerialNumbers && crMode != null && crMode.equals(PROP_SEQUENTIAL_MODE)) ||
+                             ((!mEnableRandomSerialNumbers) && crMode != null && crMode.equals(PROP_RANDOM_MODE));
+        CMS.debug("CertificateRepository: updateCounter  modeChange="+modeChange);
+        if (modeChange) {
+            if (mForceModeChange) {
+                setEnableRandomSerialNumbers(mEnableRandomSerialNumbers, true);
+            } else {
+                setEnableRandomSerialNumbers(!mEnableRandomSerialNumbers, false);
+            }
+        } else if (mEnableRandomSerialNumbers && mCounter != null &&
+                   mCounter.compareTo(BigInteger.ZERO) >= 0) {
+            long t = System.currentTimeMillis();
+            mDBConfig.putString(PROP_RANDOM_SERIAL_NUMBER_COUNTER, mCounter.toString()+","+t);
+            try {
+                CMS.getConfigStore().commit(false);
+            } catch (Exception e) {
+                CMS.debug("CertificateRepository: updateCounter  Exception committing ConfigStore="+e.getMessage());
+            }
+        }
+        CMS.debug("CertificateRepository: UpdateCounter  mEnableRandomSerialNumbers="+
+                  mEnableRandomSerialNumbers+"  mCounter="+mCounter);
+    }
+
+    private BigInteger getInRangeCount(String fromTime, BigInteger  minSerialNo, BigInteger maxSerialNo)
+    throws EBaseException {
+        BigInteger count = BigInteger.ZERO;
+        String filter = null;
+
+        if (fromTime != null && fromTime.length() > 0) {
+            filter = "(certCreateTime >= "+fromTime+")";
+        } else {
+            filter = "(&("+ICertRecord.ATTR_ID+">="+minSerialNo+")("+
+                           ICertRecord.ATTR_ID+"<="+maxSerialNo+"))";
+        }
+        CMS.debug("CertificateRepository: getInRangeCount  filter="+filter+
+                  "  minSerialNo="+minSerialNo+"  maxSerialNo="+maxSerialNo);
+
+        Enumeration e = findCertRecs(filter, new String[] {ICertRecord.ATTR_ID, "objectclass"});
+        while (e != null && e.hasMoreElements()) {
+            ICertRecord rec = (ICertRecord) e.nextElement();
+            if (rec != null) {
+                BigInteger sn = rec.getSerialNumber();
+                if (fromTime == null || fromTime.length() == 0 ||
+                    (minSerialNo != null && maxSerialNo != null &&
+                     sn != null && sn.compareTo(minSerialNo) >= 0 &&
+                     sn.compareTo(maxSerialNo) <= 0)) {
+                    count = count.add(BigInteger.ONE);
+                }
+            }
+        }
+        CMS.debug("CertificateRepository: getInRangeCount  count=" + count);
+
+        return count; 
+    }
+
+    private BigInteger getInRangeCounter(BigInteger  minSerialNo, BigInteger maxSerialNo)
+    throws EBaseException {
+        String c = null;
+        String t = null;
+        String s = (mDBConfig.getString(PROP_RANDOM_SERIAL_NUMBER_COUNTER, "-1")).trim();
+        CMS.debug("CertificateRepository: getInRangeCounter:  saved counter string="+s);
+        int i = s.indexOf(',');
+        int n = s.length();
+        if (i > -1) {
+            if (i > 0) {
+                c = s.substring(0, i);
+                if (i < n) {
+                    t = s.substring(i+1);
+                }
+            } else {
+                c = "-1";
+            }
+        } else {
+            c = s;
+        }
+        CMS.debug("CertificateRepository: getInRangeCounter:  c=" + c + ((t != null)?("  t="+t):""));
+
+        BigInteger counter = new BigInteger(c);
+        BigInteger count = BigInteger.ZERO;
+        if (t != null) {
+            count = getInRangeCount(t, minSerialNo, maxSerialNo);
+            if (count.compareTo(BigInteger.ZERO) > 0) {
+                counter = counter.add(count);
+            }
+        } else if (s.equals("-2")) {
+            count = getInRangeCount(t, minSerialNo, maxSerialNo);
+            if (count.compareTo(BigInteger.ZERO) >= 0) {
+                counter = count;
+            }
+        }
+        CMS.debug("CertificateRepository: getInRangeCounter:  counter=" + counter);
+
+        return counter; 
+    }
+
     public BigInteger getLastSerialNumberInRange(BigInteger  serial_low_bound, BigInteger serial_upper_bound)
     throws EBaseException {
 
@@ -97,8 +397,42 @@
 
         }
 
-        String ldapfilter = "(" + "certstatus" + "=*" + ")";
+        mEnableRandomSerialNumbers = mDBConfig.getBoolean(PROP_ENABLE_RANDOM_SERIAL_NUMBERS, false);
+        mForceModeChange = mDBConfig.getBoolean(PROP_FORCE_MODE_CHANGE, false);
+        String crMode = mDBService.getEntryAttribute(mBaseDN, IRepositoryRecord.ATTR_DESCRIPTION, "", null);
+        mMaxCollisionRecoverySteps = mDBConfig.getInteger(PROP_COLLISION_RECOVERY_STEPS, 10);
+        mMaxCollisionRecoveryRegenerations = mDBConfig.getInteger(PROP_COLLISION_RECOVERY_REGENERATIONS, 3);
+        boolean modeChange = (mEnableRandomSerialNumbers && crMode != null && crMode.equals(PROP_SEQUENTIAL_MODE)) ||
+                             ((!mEnableRandomSerialNumbers) && crMode != null && crMode.equals(PROP_RANDOM_MODE));
+        CMS.debug("CertificateRepository: getLastSerialNumberInRange"+
+                  "  mEnableRandomSerialNumbers="+mEnableRandomSerialNumbers+
+                  "  CollisionRecovery="+mMaxCollisionRecoveryRegenerations+","+mMaxCollisionRecoverySteps);
+        CMS.debug("CertificateRepository: getLastSerialNumberInRange  modeChange="+modeChange+
+                  "  mForceModeChange="+mForceModeChange+((crMode != null)?("  mode="+crMode):""));
+        if (modeChange) {
+            if (mForceModeChange) {
+                setCertificateRepositoryMode((mEnableRandomSerialNumbers)? PROP_RANDOM_MODE: PROP_SEQUENTIAL_MODE);
+                mForceModeChange = false;
+                mDBConfig.remove(PROP_FORCE_MODE_CHANGE);
+            } else {
+                mEnableRandomSerialNumbers = !mEnableRandomSerialNumbers;
+                mDBConfig.putBoolean(PROP_ENABLE_RANDOM_SERIAL_NUMBERS, mEnableRandomSerialNumbers);
+            }
+        }  
+        if (mEnableRandomSerialNumbers && mCounter == null) {
+            mCounter = getInRangeCounter(serial_low_bound, serial_upper_bound);
+        } else {
+            mCounter = BI_MINUS_ONE;
+        }
+        mDBConfig.putString(PROP_RANDOM_SERIAL_NUMBER_COUNTER, mCounter.toString());
+        try {
+            CMS.getConfigStore().commit(false);
+        } catch (Exception e) {
+        }
+        CMS.debug("CertificateRepository: getLastSerialNumberInRange  mEnableRandomSerialNumbers="+mEnableRandomSerialNumbers);
 
+        String ldapfilter = "("+ICertRecord.ATTR_CERT_STATUS+"=*"+")";
+
         String[] attrs = null;
 
         ICertRecordList recList = findCertRecordsInList(ldapfilter,attrs,serial_upper_bound.toString(10),"serialno", 5 * -1);
@@ -112,7 +446,7 @@
 
             BigInteger ret = new BigInteger(serial_low_bound.toString(10));
 
-            ret = ret.add(new BigInteger("-1")); 
+            ret = ret.subtract(BigInteger.ONE); 
             CMS.debug("CertificateRepository:getLastCertRecordSerialNo: returning " + ret);
             return ret;
         }
@@ -151,7 +485,7 @@
 
         BigInteger ret = new BigInteger(serial_low_bound.toString(10));
 
-        ret = ret.add(new BigInteger("-1")); 
+        ret = ret.subtract(BigInteger.ONE); 
 
         CMS.debug("CertificateRepository:getLastCertRecordSerialNo: returning " + ret);
         return ret; 
@@ -279,6 +613,7 @@
         transitRevokedExpiredCertificates();
         CMS.getLogger().log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
             CMS.getLogMessage("CMSCORE_DBS_FINISH_REVOKED_EXPIRED_SEARCH"));
+        updateCounter();
     }
 
     /**
@@ -653,6 +988,50 @@
         return rec;
     }
 
+    public boolean checkCertificateRecord(BigInteger serialNo)
+        throws EBaseException {
+        IDBSSession s = mDBService.createSession();
+        CertRecord rec = null;
+        boolean exists = true;
+
+        try {
+            String name = "cn" + "=" +
+                serialNo.toString() + "," + getDN();
+            String attrs[] = { "DN" };
+
+            rec = (CertRecord) s.read(name, attrs);
+            if (rec == null) exists = false;
+        } catch (EDBRecordNotFoundException e) {
+            exists = false;
+        } catch (Exception e) {
+            throw new EBaseException(e.getMessage());
+        } finally {
+            if (s != null) 
+                s.close();
+        }
+        return exists;
+    }
+
+    private void setCertificateRepositoryMode(String mode) {
+        IDBSSession s = null;
+
+        CMS.debug("CertificateRepository: setCertificateRepositoryMode   setting mode: "+mode);
+        try {
+            s = mDBService.createSession();
+            ModificationSet mods = new ModificationSet();
+            String name = getDN();
+            mods.add(IRepositoryRecord.ATTR_DESCRIPTION, Modification.MOD_REPLACE, mode);
+            s.modify(name, mods);
+        } catch (Exception e) {
+            CMS.debug("CertificateRepository: setCertificateRepositoryMode   Exception: "+e.getMessage());
+        }
+        try {
+            if (s != null) s.close();
+        } catch (Exception e) {
+            CMS.debug("CertificateRepository: setCertificateRepositoryMode   Exception: "+e.getMessage());
+        }
+    }
+
     public synchronized void modifyCertificateRecord(BigInteger serialNo,
         ModificationSet mods) throws EBaseException {
         IDBSSession s = mDBService.createSession();
@@ -1191,7 +1570,7 @@
                 String fromVal = "0";
                 try {
                     if (from != null) {
-                      int fv = Integer.parseInt(from);
+                      new BigInteger(from);
                       fromVal = from;
                     }
                 } catch (Exception e1) {
Index: pki/base/console/src/com/netscape/admin/certsrv/config/CMSCAGeneralPanel.java
===================================================================
--- pki/base/console/src/com/netscape/admin/certsrv/config/CMSCAGeneralPanel.java	(revision 2521)
+++ pki/base/console/src/com/netscape/admin/certsrv/config/CMSCAGeneralPanel.java	(working copy)
@@ -47,6 +47,10 @@
     private JTextField mSerialNumber;
     private JTextField mMaxSerialNumber;
     private JCheckBox mValidity;
+    private JCheckBox mRandomValidity;
+    private JTextField mRandomBits;
+    private JCheckBox mEnableSerialNumberManagement;
+    private JCheckBox mEnableRandomSerialNumbers;
     private Vector mGroupData;
     private static final String HELPINDEX =
       "configuration-ca-general-help";
@@ -139,11 +143,11 @@
         gb1.setConstraints(mOCSPEnable, gbc);
         adminPanel.add(mOCSPEnable);
 
-		// add validity block
+        // add validity block
         CMSAdminUtil.resetGBC(gbc);
         mValidity = makeJCheckBox("VALIDITY");
         gbc.anchor = gbc.CENTER;
-        //gbc.gridwidth = gbc.REMAINDER;
+        //gbc.gridwidth = gbc.REMAINDER;  remove this comment when adding random validity
         //gbc.gridheight = gbc.REMAINDER;
         //gbc.weightx = 1.0;
         gbc.weighty = 1.0;
@@ -151,6 +155,20 @@
         validityPanel.add(mValidity);
 
         CMSAdminUtil.resetGBC(gbc);
+        mRandomValidity = makeJCheckBox("RANDOM_VALIDITY");
+        gbc.anchor = gbc.CENTER;
+        gbc.weighty = 1.0;
+        gb4.setConstraints(mRandomValidity, gbc);
+        //validityPanel.add(mRandomValidity);
+
+        CMSAdminUtil.resetGBC(gbc);
+        mRandomBits = makeJTextField(10);
+        gbc.anchor = gbc.CENTER;
+        gbc.weighty = 1.0;
+        gb4.setConstraints(mRandomBits, gbc);
+        //validityPanel.add(mRandomBits);
+
+        CMSAdminUtil.resetGBC(gbc);
         JLabel dummy4 = new JLabel(" ");
         gbc.anchor = gbc.NORTHWEST;
         gbc.gridwidth = gbc.REMAINDER;
@@ -189,49 +207,86 @@
         gb2.setConstraints(dummy1, gbc);
         signingPanel.add(dummy1);
 
+        // add serial number management
+        CMSAdminUtil.resetGBC(gbc);
+        mEnableSerialNumberManagement = makeJCheckBox("MANAGEMENT");
+        //mEnableSerialNumberManagement.setEnabled(false);
+        gbc.anchor = gbc.CENTER;
+        gbc.gridwidth = gbc.REMAINDER;
+        gbc.gridheight = 1;
+        gbc.weightx = 1.0;
+        gbc.weighty = 1.0;
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gb3.setConstraints(mEnableSerialNumberManagement, gbc);
+        serialPanel.add(mEnableSerialNumberManagement);
+
+        // add random serial numbers
+        CMSAdminUtil.resetGBC(gbc);
+        mEnableRandomSerialNumbers = makeJCheckBox("RANDOM");
+        gbc.anchor = gbc.CENTER;
+        gbc.gridwidth = gbc.REMAINDER;
+        gbc.gridheight = gbc.REMAINDER; //1;
+        gbc.weightx = 1.0;
+        gbc.weighty = 1.0;
+        gbc.gridx = 0;
+        gbc.gridy = 1;
+        gb3.setConstraints(mEnableRandomSerialNumbers, gbc);
+        serialPanel.add(mEnableRandomSerialNumbers);
+
         // add serial number block
         CMSAdminUtil.resetGBC(gbc);
         JLabel serialLabel = makeJLabel("SERIAL");
+        serialLabel.setEnabled(false);
         gbc.anchor = gbc.CENTER;
         gb3.setConstraints(serialLabel, gbc);
+        gbc.gridwidth = 1;
+        gbc.gridheight = 1;
+        gbc.weightx = 0.0;
         gbc.weighty = 1.0;
-        //gbc.insets = new Insets(COMPONENT_SPACE,0,COMPONENT_SPACE,0);
-        serialPanel.add(serialLabel);
+        gbc.gridx = 0;
+        gbc.gridy = 2;
+        //serialPanel.add(serialLabel);
 
         CMSAdminUtil.resetGBC(gbc);
         mSerialNumber = makeJTextField(17);
         mSerialNumber.setEnabled(false);
         gbc.anchor = gbc.NORTHWEST;
-        //gbc.gridwidth = gbc.REMAINDER;
-        //gbc.gridheight = gbc.REMAINDER;
-        //gbc.weightx = 1.0;
+        gbc.gridwidth = 1;
+        gbc.gridheight = 1;
+        gbc.weightx = 0.0;
         gbc.weighty = 1.0;
+        gbc.gridx = 1;
+        gbc.gridy = 2;
         gb3.setConstraints(mSerialNumber, gbc);
-        serialPanel.add(mSerialNumber);
+        //serialPanel.add(mSerialNumber);
 
         // add end serial number block
         CMSAdminUtil.resetGBC(gbc);
         JLabel maxSerialLabel = makeJLabel("MAXSERIAL");
-        gbc.anchor = gbc.EAST;
-        //gbc.insets = new Insets(COMPONENT_SPACE,DIFFERENT_COMPONENT_SPACE,0,0);
+        maxSerialLabel.setEnabled(false);
+        gbc.anchor = gbc.CENTER;
+        gbc.gridwidth = 1;
+        gbc.gridheight = 1;
         gbc.weightx = 0.0;
-        gbc.gridwidth = 1;
+        gbc.weighty = 1.0;
         gbc.gridx = 0;
+        gbc.gridy = 3;
         gb3.setConstraints(maxSerialLabel, gbc);
-        //gbc.weighty = 1.0;
-        serialPanel.add(maxSerialLabel);
+        //serialPanel.add(maxSerialLabel);
 
         CMSAdminUtil.resetGBC(gbc);
         mMaxSerialNumber = makeJTextField(17);
         mMaxSerialNumber.setEnabled(false);
-        gbc.anchor = gbc.NORTHWEST;
-        gbc.gridy = 1;
-        //gbc.gridwidth = gbc.REMAINDER;
-        //gbc.gridheight = gbc.REMAINDER;
-        //gbc.weightx = 1.0;
+        gbc.anchor = gbc.CENTER;
+        gbc.gridwidth = 1;
+        gbc.gridheight = 1;
+        gbc.weightx = 0.0;
         gbc.weighty = 1.0;
+        gbc.gridx = 1;
+        gbc.gridy = 3;
         gb3.setConstraints(mMaxSerialNumber, gbc);
-        serialPanel.add(mMaxSerialNumber);
+        //serialPanel.add(mMaxSerialNumber);
 
         CMSAdminUtil.resetGBC(gbc);
         JLabel dummy2 = new JLabel(" ");
@@ -249,13 +304,17 @@
     public void refresh() {
         mModel.progressStart();
         NameValuePairs nvps = new NameValuePairs();
-        nvps.add(Constants.PR_EE_ENABLED, "");
+        //nvps.add(Constants.PR_EE_ENABLED, "");
         //nvps.add(Constants.PR_RA_ENABLED, "");
         nvps.add(Constants.PR_DEFAULT_ALGORITHM, "");
         nvps.add(Constants.PR_ALL_ALGORITHMS, "");
         nvps.add(Constants.PR_SERIAL, "");
         nvps.add(Constants.PR_MAXSERIAL, "");
         nvps.add(Constants.PR_VALIDITY, "");
+        //nvps.add(Constants.PR_RANDOM_VALIDITY, "");
+        //nvps.add(Constants.PR_RANDOM_VALIDITY_BITS, "");
+        nvps.add(Constants.PR_SN_MANAGEMENT, "");
+        nvps.add(Constants.PR_RANDOM_SN, "");
 
         try {
             NameValuePairs val = mAdmin.read(DestDef.DEST_CA_ADMIN,
@@ -268,6 +327,7 @@
         }
         mModel.progressStop();
         clearDirtyFlag();
+        enableFields();
     }
 
     protected void populate(NameValuePairs nvps) {
@@ -275,16 +335,21 @@
         for (int i=0; i<nvps.size(); i++) {
             NameValuePair nvp = nvps.elementAt(i);
             String name = nvp.getName();
+/*
             if (name.equals(Constants.PR_EE_ENABLED)) {
                 mEEEnable.setSelected(getBoolean(nvp.getValue()));
             } else if (name.equals(Constants.PR_OCSP_ENABLED)) {
                 mOCSPEnable.setSelected(getBoolean(nvp.getValue()));
-/*
             } else if (name.equals(Constants.PR_RA_ENABLED)) {
                 mRAEnable.setSelected(getBoolean(nvp.getValue()));
+            } else
 */
-            } else if (name.equals(Constants.PR_VALIDITY)) {
+            if (name.equals(Constants.PR_VALIDITY)) {
                 mValidity.setSelected(getBoolean(nvp.getValue()));
+            } else if (name.equals(Constants.PR_SN_MANAGEMENT)) {
+                mEnableSerialNumberManagement.setSelected(getBoolean(nvp.getValue()));
+            } else if (name.equals(Constants.PR_RANDOM_SN)) {
+                mEnableRandomSerialNumbers.setSelected(getBoolean(nvp.getValue()));
             } else if (name.equals(Constants.PR_DEFAULT_ALGORITHM)) {
                 defaultAlgorithm = nvp.getValue();
             } else if (name.equals(Constants.PR_ALL_ALGORITHMS)) {
@@ -322,9 +387,19 @@
     }
 
     public void actionPerformed(ActionEvent e) {
+        if (e.getSource().equals(mEnableSerialNumberManagement)) {
+            enableFields();
+        }
         super.actionPerformed(e);
     }
 
+    private void enableFields() {
+        boolean enable = mEnableSerialNumberManagement.isSelected();
+        mEnableRandomSerialNumbers.setEnabled(enable);
+        if (!enable) mEnableRandomSerialNumbers.setSelected(enable);
+        CMSAdminUtil.repaintComp(mEnableRandomSerialNumbers);
+    }
+
     private String hexToDecimal(String hex)
     {
         //String newHex = hex.substring(2);
@@ -339,6 +414,7 @@
     public boolean applyCallback() {
         NameValuePairs nvps = new NameValuePairs();
 
+/*
         if (mEEEnable.isSelected())
             nvps.add(Constants.PR_EE_ENABLED, Constants.TRUE);
         else
@@ -349,7 +425,6 @@
         else
             nvps.add(Constants.PR_OCSP_ENABLED, Constants.FALSE);
 
-/*
         if (mRAEnable.isSelected())
             nvps.add(Constants.PR_RA_ENABLED, Constants.TRUE);
         else
@@ -361,6 +436,17 @@
         else
             nvps.add(Constants.PR_VALIDITY, Constants.FALSE);
 
+        if (mEnableSerialNumberManagement.isSelected())
+            nvps.add(Constants.PR_SN_MANAGEMENT, Constants.TRUE);
+        else
+            nvps.add(Constants.PR_SN_MANAGEMENT, Constants.FALSE);
+
+        if (mEnableSerialNumberManagement.isSelected() &&
+            mEnableRandomSerialNumbers.isSelected())
+            nvps.add(Constants.PR_RANDOM_SN, Constants.TRUE);
+        else
+            nvps.add(Constants.PR_RANDOM_SN, Constants.FALSE);
+
         nvps.add(Constants.PR_DEFAULT_ALGORITHM, 
           (String)mAlgorithms.getSelectedItem());
 
Index: pki/base/console/src/com/netscape/certsrv/common/Constants.java
===================================================================
--- pki/base/console/src/com/netscape/certsrv/common/Constants.java	(revision 2521)
+++ pki/base/console/src/com/netscape/certsrv/common/Constants.java	(working copy)
@@ -343,10 +343,14 @@
      * Certificate Authority
      *========================================================*/
     public final static String PR_VALIDITY = "validity";
+    //public final static String PR_RANDOM_VALIDITY = "randomValidity";
+    //public final static String PR_RANDOM_VALIDITY_BITS = "randomValidityBits";
     public final static String PR_DEFAULT_ALGORITHM = "defaultSigningAlgorithm";
     public final static String PR_ALL_ALGORITHMS = "allSigningAlgorithms";
     public final static String PR_SERIAL = "startSerialNumber";
     public final static String PR_MAXSERIAL = "maxSerialNumber";
+    public final static String PR_SN_MANAGEMENT = "serialNumberManagement";
+    public final static String PR_RANDOM_SN = "randomSerialNumbers";
 
     /*========================================================
      * Access Control


More information about the Pki-devel mailing list