diff options
Diffstat (limited to 'base/server/cmscore/src/com/netscape/cmscore/dbs/KeyRepository.java')
-rw-r--r-- | base/server/cmscore/src/com/netscape/cmscore/dbs/KeyRepository.java | 607 |
1 files changed, 607 insertions, 0 deletions
diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/KeyRepository.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/KeyRepository.java new file mode 100644 index 000000000..556cab9f5 --- /dev/null +++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/KeyRepository.java @@ -0,0 +1,607 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.math.BigInteger; +import java.security.PublicKey; +import java.util.Date; +import java.util.Enumeration; +import java.util.Vector; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +import netscape.security.x509.X500Name; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.IDBRegistry; +import com.netscape.certsrv.dbs.IDBSSession; +import com.netscape.certsrv.dbs.IDBSearchResults; +import com.netscape.certsrv.dbs.IDBSubsystem; +import com.netscape.certsrv.dbs.Modification; +import com.netscape.certsrv.dbs.ModificationSet; +import com.netscape.certsrv.dbs.keydb.IKeyRecord; +import com.netscape.certsrv.dbs.keydb.IKeyRecordList; +import com.netscape.certsrv.dbs.keydb.IKeyRepository; +import com.netscape.certsrv.dbs.repository.IRepository; + +/** + * A class represents a Key repository. This is the container of + * archived keys. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class KeyRepository extends Repository implements IKeyRepository { + + public KeyStatusUpdateTask mKeyStatusUpdateTask; + protected IDBSubsystem mDBService; + + IRepository requestRepository; + + /** + * Internal constants + */ + private String mBaseDN = null; + + /** + * Constructs a key repository. It checks if the key repository + * does exist. If not, it creates the repository. + * <P> + * + * @param service db service + * @exception EBaseException failed to setup key repository + */ + public KeyRepository(IDBSubsystem service, int increment, String baseDN) + throws EDBException { + super(service, increment, baseDN); + mBaseDN = baseDN; + mDBService = service; + + // register key record schema + IDBRegistry reg = service.getRegistry(); + String keyRecordOC[] = new String[2]; + + keyRecordOC[0] = KeyDBSchema.LDAP_OC_TOP; + keyRecordOC[1] = KeyDBSchema.LDAP_OC_KEYRECORD; + + if (!reg.isObjectClassRegistered(KeyRecord.class.getName())) { + reg.registerObjectClass(KeyRecord.class.getName(), + keyRecordOC); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_ID)) { + reg.registerAttribute(KeyRecord.ATTR_ID, new + BigIntegerMapper(KeyDBSchema.LDAP_ATTR_SERIALNO)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_ALGORITHM)) { + reg.registerAttribute(KeyRecord.ATTR_ALGORITHM, new + StringMapper(KeyDBSchema.LDAP_ATTR_ALGORITHM)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_STATE)) { + reg.registerAttribute(KeyRecord.ATTR_STATE, new + KeyStateMapper(KeyDBSchema.LDAP_ATTR_STATE)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_KEY_SIZE)) { + reg.registerAttribute(KeyRecord.ATTR_KEY_SIZE, new + IntegerMapper(KeyDBSchema.LDAP_ATTR_KEY_SIZE)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_OWNER_NAME)) { + reg.registerAttribute(KeyRecord.ATTR_OWNER_NAME, new + StringMapper(KeyDBSchema.LDAP_ATTR_OWNER_NAME)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_PRIVATE_KEY_DATA)) { + reg.registerAttribute(KeyRecord.ATTR_PRIVATE_KEY_DATA, new + ByteArrayMapper(KeyDBSchema.LDAP_ATTR_PRIVATE_KEY_DATA)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_PUBLIC_KEY_DATA)) { + reg.registerAttribute(KeyRecord.ATTR_PUBLIC_KEY_DATA, new + PublicKeyMapper(KeyDBSchema.LDAP_ATTR_PUBLIC_KEY_DATA)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_DATE_OF_RECOVERY)) { + reg.registerAttribute(KeyRecord.ATTR_DATE_OF_RECOVERY, new + DateArrayMapper(KeyDBSchema.LDAP_ATTR_DATE_OF_RECOVERY)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_CREATE_TIME)) { + reg.registerAttribute(KeyRecord.ATTR_CREATE_TIME, new + DateMapper(KeyDBSchema.LDAP_ATTR_CREATE_TIME)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_MODIFY_TIME)) { + reg.registerAttribute(KeyRecord.ATTR_MODIFY_TIME, new + DateMapper(KeyDBSchema.LDAP_ATTR_MODIFY_TIME)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_META_INFO)) { + reg.registerAttribute(KeyRecord.ATTR_META_INFO, new + MetaInfoMapper(KeyDBSchema.LDAP_ATTR_META_INFO)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_ARCHIVED_BY)) { + reg.registerAttribute(KeyRecord.ATTR_ARCHIVED_BY, new + StringMapper(KeyDBSchema.LDAP_ATTR_ARCHIVED_BY)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_CLIENT_ID)) { + reg.registerAttribute(KeyRecord.ATTR_CLIENT_ID, new + StringMapper(KeyDBSchema.LDAP_ATTR_CLIENT_ID)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_STATUS)) { + reg.registerAttribute(KeyRecord.ATTR_STATUS, new + StringMapper(KeyDBSchema.LDAP_ATTR_STATUS)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_DATA_TYPE)) { + reg.registerAttribute(KeyRecord.ATTR_DATA_TYPE, new + StringMapper(KeyDBSchema.LDAP_ATTR_DATA_TYPE)); + } + + } + + public void setKeyStatusUpdateInterval(IRepository requestRepo, int interval) { + + CMS.debug("In setKeyStatusUpdateInterval " + interval); + synchronized (this) { + this.requestRepository = requestRepo; + } + + // stop running task + if (mKeyStatusUpdateTask != null) { + mKeyStatusUpdateTask.stop(); + } + + // don't run the thread if serial management is disabled. + if (interval == 0 || !mDBService.getEnableSerialMgmt()) { + CMS.debug("In setKeyStatusUpdateInterval interval = 0"); + return; + } + + CMS.debug("In setKeyStatusUpdateInterval scheduling key status update every " + interval + " seconds."); + mKeyStatusUpdateTask = new KeyStatusUpdateTask(this, interval); + mKeyStatusUpdateTask.start(); + } + + /** + * This method blocks when another thread is running + */ + public synchronized void updateKeyStatus() { + try { + CMS.debug("About to start checkRanges"); + + CMS.debug("Starting key checkRanges"); + checkRanges(); + CMS.debug("key checkRanges done"); + + CMS.debug("Starting request checkRanges"); + requestRepository.checkRanges(); + CMS.debug("request checkRanges done"); + + } catch (Exception e) { + CMS.debug("key checkRanges done: " + e.toString()); + } + } + + public IDBSubsystem getDBSubsystem() { + return mDBService; + } + + /** + * Retrieves the DN of this repository. + */ + public String getDN() { + return mBaseDN; + } + + /** + * Removes all objects with this repository. + */ + public void removeAllObjects() throws EBaseException { + String filter = "(" + KeyRecord.ATTR_OWNER_NAME + "=*" + ")"; + IKeyRecordList list = findKeyRecordsInList(filter, + null, "serialno", 10); + int size = list.getSize(); + Enumeration<IKeyRecord> e = list.getKeyRecords(0, size - 1); + while (e.hasMoreElements()) { + IKeyRecord rec = e.nextElement(); + deleteKeyRecord(rec.getSerialNumber()); + } + } + + /** + * Archives a key to the repository. + * <P> + * + * @param record key record + * @exception EBaseException failed to archive key + */ + public void addKeyRecord(IKeyRecord record) throws EBaseException { + IDBSSession s = mDBService.createSession(); + + try { + String name = "cn" + "=" + + ((KeyRecord) record).getSerialNumber().toString() + "," + getDN(); + + if (s != null) + s.add(name, (KeyRecord) record); + } finally { + if (s != null) + s.close(); + } + } + + /** + * Recovers an archived key by serial number. + * <P> + * + * @param serialNo serial number + * @return key record + * @exception EBaseException failed to recover key + */ + public IKeyRecord readKeyRecord(BigInteger serialNo) + throws EBaseException { + if (serialNo == null) { + throw new EBaseException("Invalid Serial Number."); + } + IDBSSession s = mDBService.createSession(); + KeyRecord rec = null; + + try { + String name = "cn" + "=" + + serialNo.toString() + "," + getDN(); + + if (s != null) + rec = (KeyRecord) s.read(name); + } finally { + if (s != null) + s.close(); + } + if (rec == null) { + throw new EBaseException("Failed to recover Key for Serial Number " + serialNo); + } + return rec; + } + + /** + * Recovers an archived key by owner name. + * <P> + * + * @param ownerName owner name + * @return key record + * @exception EBaseException failed to recover key + */ + public IKeyRecord readKeyRecord(X500Name ownerName) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + KeyRecord keyRec = null; + + try { + if (ownerName != null) { + String filter = "(" + KeyRecord.ATTR_OWNER_NAME + "=" + + ownerName.toString() + ")"; + IDBSearchResults res = s.search(getDN(), filter); + + keyRec = (KeyRecord) res.nextElement(); + } + } finally { + if (s != null) + s.close(); + } + return keyRec; + } + + /** + * Recovers archived key using public key. + */ + public IKeyRecord readKeyRecord(PublicKey publicKey) + throws EBaseException { + // XXX - setup binary search attributes + byte data[] = publicKey.getEncoded(); + + if (data == null) + throw new EBaseException("null data"); + IDBSSession s = mDBService.createSession(); + KeyRecord rec = null; + + try { + String filter = "(" + KeyRecord.ATTR_PUBLIC_KEY_DATA + "=" + + escapeBinaryData(data) + ")"; + if (s != null) { + IDBSearchResults res = s.search(getDN(), filter); + + rec = (KeyRecord) res.nextElement(); + } + } finally { + if (s != null) + s.close(); + } + return rec; + } + + /** + * Recovers archived key using b64 encoded cert + */ + public IKeyRecord readKeyRecord(String cert) + throws EBaseException { + + IDBSSession s = mDBService.createSession(); + KeyRecord rec = null; + + try { + String filter = "(publicKey=x509cert#\"" + cert + "\")"; + CMS.debug("filter= " + filter); + + if (s != null) { + IDBSearchResults res = s.search(getDN(), filter); + + rec = (KeyRecord) res.nextElement(); + } + } finally { + if (s != null) + s.close(); + } + return rec; + } + + /** + * Modifies key record. + */ + public void modifyKeyRecord(BigInteger serialNo, ModificationSet mods) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + + try { + String name = "cn" + "=" + + serialNo.toString() + "," + getDN(); + + mods.add(KeyRecord.ATTR_MODIFY_TIME, Modification.MOD_REPLACE, + new Date()); + if (s != null) + s.modify(name, mods); + } finally { + if (s != null) + s.close(); + } + } + + public void deleteKeyRecord(BigInteger serialNo) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + + try { + String name = "cn" + "=" + + serialNo.toString() + "," + getDN(); + + if (s != null) + s.delete(name); + } finally { + if (s != null) + s.close(); + } + } + + /** + * Read RFC-2254 + */ + public static String escapeBinaryData(byte data[]) { + StringBuffer result = new StringBuffer(); + + for (int i = 0; i < data.length; i++) { + result.append("\\" + Integer.toHexString(data[i])); + } + return result.toString(); + } + + public Enumeration<IKeyRecord> searchKeys(String filter, int maxSize) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Vector<IKeyRecord> v = new Vector<IKeyRecord>(); + + try { + IDBSearchResults sr = s.search(getDN(), filter, maxSize); + while (sr.hasMoreElements()) { + v.add((IKeyRecord) sr.nextElement()); + } + } finally { + if (s != null) + s.close(); + } + return v.elements(); + } + + public Enumeration<IKeyRecord> searchKeys(String filter, int maxSize, int timeLimit) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Vector<IKeyRecord> v = new Vector<IKeyRecord>(); + + try { + IDBSearchResults sr = s.search(getDN(), filter, maxSize, timeLimit); + while (sr.hasMoreElements()) { + v.add((IKeyRecord) sr.nextElement()); + } + } finally { + if (s != null) + s.close(); + } + return v.elements(); + } + + /** + * Retrieves key record list. + */ + public IKeyRecordList findKeyRecordsInList(String filter, + String attrs[], int pageSize) throws EBaseException { + return findKeyRecordsInList(filter, attrs, IKeyRecord.ATTR_ID, + pageSize); + } + + public IKeyRecordList findKeyRecordsInList(String filter, + String attrs[], String sortKey, int pageSize) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + IKeyRecordList list = null; + + try { + if (s != null) { + list = new KeyRecordList( + s.<IKeyRecord>createVirtualList(getDN(), "(&(objectclass=" + + KeyRecord.class.getName() + ")" + filter + ")", + attrs, sortKey, pageSize)); + } + } finally { + if (s != null) + s.close(); + } + return list; + } + + public IKeyRecordList findKeyRecordsInList(String filter, + String attrs[], String jumpTo, String sortKey, int pageSize) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + IKeyRecordList list = null; + + int len = jumpTo.length(); + + String jumpToVal = null; + + if (len > 9) { + jumpToVal = Integer.toString(len) + jumpTo; + } else { + jumpToVal = "0" + Integer.toString(len) + jumpTo; + } + + try { + if (s != null) { + list = new KeyRecordList( + s.<IKeyRecord>createVirtualList(getDN(), "(&(objectclass=" + + KeyRecord.class.getName() + ")" + filter + ")", + attrs, jumpToVal, sortKey, pageSize)); + } + } finally { + if (s != null) + s.close(); + } + return list; + } + + public BigInteger getLastSerialNumberInRange(BigInteger serial_low_bound, BigInteger serial_upper_bound) throws + EBaseException { + + CMS.debug("KeyRepository: in getLastSerialNumberInRange: low " + + serial_low_bound + " high " + serial_upper_bound); + + if (serial_low_bound == null + || serial_upper_bound == null || serial_low_bound.compareTo(serial_upper_bound) >= 0) { + return null; + } + + String ldapfilter = "(" + "serialno" + "=*" + ")"; + String[] attrs = null; + + KeyRecordList recList = + (KeyRecordList) findKeyRecordsInList(ldapfilter, attrs, serial_upper_bound.toString(10), "serialno", + 5 * -1); + + int size = -1; + if (recList != null) { + size = recList.getSize(); + } + + CMS.debug("KeyRepository: getLastSerialNumberInRange: recList size " + size); + + if (size <= 0) { + CMS.debug("KeyRepository: getLastSerialNumberInRange: index may be empty"); + + BigInteger ret = new BigInteger(serial_low_bound.toString(10)); + + ret = ret.add(new BigInteger("-1")); + + CMS.debug("KeyRepository: getLastSerialNumberInRange returning: " + ret); + return ret; + } + int ltSize = recList.getSizeBeforeJumpTo(); + + CMS.debug("KeyRepository:getLastSerialNumberInRange: ltSize " + ltSize); + + int i; + KeyRecord curRec = null; + + for (i = 0; i < 5; i++) { + curRec = (KeyRecord) recList.getKeyRecord(i); + + if (curRec != null) { + + BigInteger serial = curRec.getSerialNumber(); + + CMS.debug("KeyRepository: getLastCertRecordSerialNo: serialno " + serial); + + if (((serial.compareTo(serial_low_bound) == 0) || (serial.compareTo(serial_low_bound) == 1)) && + ((serial.compareTo(serial_upper_bound) == 0) || (serial.compareTo(serial_upper_bound) == -1))) { + CMS.debug("KeyRepository: getLastSerialNumberInRange returning: " + serial); + return serial; + } + } else { + CMS.debug("KeyRepository: getLastSerialNumberInRange:found null from getCertRecord"); + } + } + + BigInteger ret = new BigInteger(serial_low_bound.toString(10)); + + ret = ret.add(new BigInteger("-1")); + + CMS.debug("KeyRepository: getLastSerialNumberInRange returning: " + ret); + return ret; + + } + + public void shutdown() { + if (mKeyStatusUpdateTask != null) { + mKeyStatusUpdateTask.stop(); + } + } + +} + +class KeyStatusUpdateTask implements Runnable { + KeyRepository repository; + int interval; + + ScheduledExecutorService executorService; + + public KeyStatusUpdateTask(KeyRepository repository, int interval) { + this.repository = repository; + this.interval = interval; + } + + public void start() { + // schedule task to run immediately and repeat after specified interval + executorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { + public Thread newThread(Runnable r) { + return new Thread(r, "KeyStatusUpdateTask"); + } + }); + executorService.scheduleWithFixedDelay(this, 0, interval, TimeUnit.SECONDS); + } + + public void run() { + repository.updateKeyStatus(); + } + + public void stop() { + // shutdown executorService without interrupting running task + if (executorService != null) executorService.shutdown(); + } +} |