[Pki-devel] [PATCH] 0026 Add lightweight sub-CA support
Fraser Tweedale
ftweedal at redhat.com
Fri Mar 6 08:16:29 UTC 2015
G'day,
The first major patch for lightweight sub-CAs is attached for
review. Some important features are not yet implemented in this
patch:
- Sub-CA creation
- Caching of sub-CA instances
- Signing key replication for clones
- CRLs (the OCSP servlet works for sub-CAs, however)
- Sub-CA support is possibly missing from some web servlets /
templates. Let me know if you hit any.
Because sub-CA creation is not implemented, if you want to test this
patch you will need to:
1. Use the top-level CA to sign a sub-CA certificate and manually
install it in the NSSDB with the nickname:
"${TOPLEVEL_CA_NICKNAME} ${SUB_CA_HANDLE}"
2. Create the sub-CA certificate repository OU:
"ou=${SUB_CA_HANDLE},ou=certificateRepository,ou=ca,o=pki-tomcat-CA"
3. When submitting requests or other queries via HTTP, edit the
initial link target or form action to include the query parameter:
"?caRef=${SUB_CA_HANDLE}"
(Subsequent pages should not require this intervention.)
I have also updated the design proposal with some refinements and
details of the implementation so far:
http://pki.fedoraproject.org/wiki/Lightweight_sub-CAs
Looking forward to your feedback / bug reports!
Fraser
-------------- next part --------------
>From 711a0601073068ce89e76ce7093d3665a5022ccc Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <frase at frase.id.au>
Date: Wed, 28 Jan 2015 02:41:10 -0500
Subject: [PATCH] Add lightweight sub-CA support
---
.../shared/webapps/ca/agent/ca/queryCert.template | 9 ++-
.../webapps/ca/agent/ca/reasonToRevoke.template | 2 +
.../shared/webapps/ca/agent/ca/srchCert.template | 2 +
base/ca/shared/webapps/ca/ee/ca/queryCert.template | 6 +-
.../webapps/ca/ee/ca/reasonToRevoke.template | 2 +
.../src/com/netscape/ca/CertificateAuthority.java | 90 ++++++++++++++++++++--
base/ca/src/com/netscape/ca/SigningUnit.java | 10 ++-
.../netscape/certsrv/ca/ICertificateAuthority.java | 17 ++++
.../netscape/certsrv/profile/IEnrollProfile.java | 5 ++
.../cms/profile/common/CAEnrollProfile.java | 7 +-
.../netscape/cms/profile/common/EnrollProfile.java | 3 +
.../cms/profile/def/AuthInfoAccessExtDefault.java | 8 +-
.../def/AuthorityKeyIdentifierExtDefault.java | 17 +++-
.../netscape/cms/profile/def/CAEnrollDefault.java | 4 +-
.../netscape/cms/servlet/cert/DisplayBySerial.java | 31 ++++----
.../com/netscape/cms/servlet/cert/DoRevoke.java | 15 ++--
.../cms/servlet/cert/EnrollmentProcessor.java | 7 ++
.../com/netscape/cms/servlet/cert/ListCerts.java | 23 +++---
.../netscape/cms/servlet/cert/ReasonToRevoke.java | 13 ++--
.../com/netscape/cms/servlet/cert/SrchCerts.java | 24 +++---
.../com/netscape/cms/servlet/ocsp/OCSPServlet.java | 5 +-
21 files changed, 227 insertions(+), 73 deletions(-)
diff --git a/base/ca/shared/webapps/ca/agent/ca/queryCert.template b/base/ca/shared/webapps/ca/agent/ca/queryCert.template
index 40ee64b0c0b62a0ff409f2617b956647b8779b59..39f933bcd9cd777a22e1baf4fdc4d8e33e5295bc 100644
--- a/base/ca/shared/webapps/ca/agent/ca/queryCert.template
+++ b/base/ca/shared/webapps/ca/agent/ca/queryCert.template
@@ -321,8 +321,10 @@ function displayCertificateRecord(i, cert)
"<td style='overflow: hidden; white-space: nowrap;'>"+
" <font face='PrimaSans BT, Verdana, sans-serif' size='-1'>\n"+
" <div style='overflow: hidden; white-space: nowrap;'>"+
- " <a index='"+i+"' href='displayBySerial?op=displayBySerial&serialNumber=0x"+
- cert.serialNumber+"' onmouseover='mouseover(this,event);' "+
+ " <a index='"+i+"' href='displayBySerial?op=displayBySerial"
+ + "&serialNumber=0x" + cert.serialNumber
+ + (result.header.caRef ? "&caRef=" + result.header.caRef : "")
+ + "' onmouseover='mouseover(this,event);' "+
"onmouseout='mouseout(this);'>"+
cert.subject+"</a></div></font>"+
"</td>"+
@@ -419,6 +421,7 @@ function doNext(element)
var form = element.form;
// form.action = "/"+result.header.op;
form.action = "/ca/agent/ca/listCerts";
+ form.caRef.value = result.header.caRef || "";
form.op.value = result.header.op;
form.queryCertFilter.value = result.header.queryCertFilter;
form.direction.value= "down";
@@ -472,6 +475,8 @@ document.write(
"<button "+disabledUp+" NAME=up onClick='doNext(this)' VALUE='<' width='72'><</button>\n"+
"<INPUT TYPE=hidden NAME=totalRecordCount VALUE='"+
result.header.totalRecordCount+ "'>\n"+
+"<INPUT TYPE=hidden NAME=caRef VALUE='"+
+(result.header.caRef || "") + "'>\n"+
"<INPUT TYPE=hidden NAME=queryCertFilter VALUE='"+
result.header.queryCertFilter+ "'>\n"+
"<INPUT TYPE=hidden NAME=querySentinelDown VALUE='"+
diff --git a/base/ca/shared/webapps/ca/agent/ca/reasonToRevoke.template b/base/ca/shared/webapps/ca/agent/ca/reasonToRevoke.template
index ffb648beb117a304a5b6382c129dade20fbb3a09..560bd11d310ad8cc03b441f3edba41174277f02b 100644
--- a/base/ca/shared/webapps/ca/agent/ca/reasonToRevoke.template
+++ b/base/ca/shared/webapps/ca/agent/ca/reasonToRevoke.template
@@ -461,6 +461,8 @@ function revokeCert(serialNumber)
result.recordSet[i].serialNumber +"\">");
}
}
+ document.writeln("<INPUT TYPE=hidden name=caRef value=\"" +
+ (result.header.caRef || "") + "\">");
document.writeln("<INPUT TYPE=hidden name=revokeAll value=\"" +
result.header.revokeAll +"\">");
document.writeln("<INPUT TYPE=hidden name=totalRecordCount value=\"" +
diff --git a/base/ca/shared/webapps/ca/agent/ca/srchCert.template b/base/ca/shared/webapps/ca/agent/ca/srchCert.template
index 001b0e3b5bde043997b6bdb4e1e12f3e10e87526..ebd59822806953ba6500a02b94a1219eba2fe534 100644
--- a/base/ca/shared/webapps/ca/agent/ca/srchCert.template
+++ b/base/ca/shared/webapps/ca/agent/ca/srchCert.template
@@ -106,6 +106,7 @@ function renderDetailsButton(serialNumber)
return "<FORM METHOD=post "+
"ACTION=\""+ "displayBySerial" +"\">\n"+
"<INPUT TYPE=hidden NAME=\"op\" VALUE=\""+ "displayBySerial" +"\">\n"+
+"<INPUT TYPE=hidden NAME=\"caRef\" VALUE=\"" + (result.header.caRef || "") + "\">\n" +
"<INPUT TYPE=hidden NAME=\"serialNumber\" VALUE=\""+ "0x"+serialNumber +"\">\n"+
"<INPUT TYPE=submit VALUE=\"Details\" width=\"72\"></FORM>\n";
}
@@ -118,6 +119,7 @@ function renderRevokeButton(serialNumberDecimal)
//"onSubmit=\"return revokeCert("+serialNumberDecimal+");\" "+
"ACTION=\""+ "reasonToRevoke" +"\">\n"+
"<INPUT TYPE=hidden NAME=\"op\" VALUE=\""+ "reasonToRevoke" +"\">\n"+
+"<INPUT TYPE=hidden NAME=\"caRef\" VALUE=\"" + (result.header.caRef || "") + "\">\n" +
"<INPUT TYPE=hidden NAME=\"serialNumber\" VALUE=\""+ serialNumberDecimal +"\">\n"+
"<INPUT TYPE=hidden NAME=\"revokeAll\" VALUE=\"(&(certRecordId="+serialNumberDecimal+"))\">\n"+
"<INPUT TYPE=hidden NAME=\"totalRecordCount\" VALUE=\"1\">\n"+
diff --git a/base/ca/shared/webapps/ca/ee/ca/queryCert.template b/base/ca/shared/webapps/ca/ee/ca/queryCert.template
index 1165cb309431cf4e7f83eed6759925b86d11d23e..e8f7541ba26563feec07d15b764aea63ff9789e6 100644
--- a/base/ca/shared/webapps/ca/ee/ca/queryCert.template
+++ b/base/ca/shared/webapps/ca/ee/ca/queryCert.template
@@ -301,8 +301,10 @@ function displayCertificateRecord(i, cert)
"<td style='overflow: hidden; white-space: nowrap;'>"+
" <font face='PrimaSans BT, Verdana, sans-serif' size='-1'>\n"+
" <div style='overflow: hidden; white-space: nowrap;'>"+
- " <a index='"+i+"' href='/ca/ee/ca/displayBySerial?op=displayBySerial&serialNumber=0x"+
- cert.serialNumber+"' onmouseover='mouseover(this,event);' "+
+ " <a index='"+i+"' href='/ca/ee/ca/displayBySerial?op=displayBySerial"
+ + "&serialNumber=0x" + cert.serialNumber
+ + (result.header.caRef ? "&caRef=" + result.header.caRef : "")
+ + "' onmouseover='mouseover(this,event);' " +
"onmouseout='mouseout(this);'>"+
addEscapes(cert.subject)+"</a></div></font>"+
"</td>"+
diff --git a/base/ca/shared/webapps/ca/ee/ca/reasonToRevoke.template b/base/ca/shared/webapps/ca/ee/ca/reasonToRevoke.template
index 2a608438b1f46b7695a8692ed857ce7de6e07d42..4a6abb830cde161223164e49039b68a4b2b891d3 100644
--- a/base/ca/shared/webapps/ca/ee/ca/reasonToRevoke.template
+++ b/base/ca/shared/webapps/ca/ee/ca/reasonToRevoke.template
@@ -448,6 +448,8 @@ function revokeCert(serialNumber)
<input type="reset" value="Reset" name="reset" width="72">
<SCRIPT LANGUAGE="JavaScript">
//<!--
+ document.writeln("<INPUT TYPE=hidden name=caRef value=\"" +
+ (result.header.caRef || "") + "\">");
document.writeln("<INPUT TYPE=hidden name=serialNumber value=\"" +
result.header.serialNumber +"\">");
document.writeln("<INPUT TYPE=hidden name=revokeAll value=\"" +
diff --git a/base/ca/src/com/netscape/ca/CertificateAuthority.java b/base/ca/src/com/netscape/ca/CertificateAuthority.java
index 65296113e1df07f82070d639ee68588f8e0dbaf7..28dde0b23bb71ebc69c7437851534073392ad13c 100644
--- a/base/ca/src/com/netscape/ca/CertificateAuthority.java
+++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java
@@ -33,6 +33,7 @@ import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
+import java.util.List;
import java.util.Map;
import java.util.Vector;
@@ -123,6 +124,9 @@ import com.netscape.cmsutil.ocsp.SingleResponse;
import com.netscape.cmsutil.ocsp.TBSRequest;
import com.netscape.cmsutil.ocsp.UnknownInfo;
+import org.apache.commons.lang.StringUtils;
+
+
/**
* A class represents a Certificate Authority that is
* responsible for certificate specific operations.
@@ -136,6 +140,9 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori
public final static OBJECT_IDENTIFIER OCSP_NONCE = new OBJECT_IDENTIFIER("1.3.6.1.5.5.7.48.1.2");
+ protected List<String> subCAHier;
+ protected String subCAOUs;
+
protected ISubsystem mOwner = null;
protected IConfigStore mConfig = null;
protected ILogger mLogger = CMS.getLogger();
@@ -234,6 +241,27 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori
* Constructs a CA subsystem.
*/
public CertificateAuthority() {
+ subCAHier = new Vector(0);
+ subCAOUs = joinSubCAOUs(subCAHier);
+ }
+
+ /**
+ * Construct a CA subsystem with given owner subsystem, config and
+ * path in CA hierarchy.
+ *
+ * The primary CA has an empty path. For Sub-CAs, the
+ * certification path runs left-to-right, i.e., CA at index
+ * N is signed by CA at index (N - 1).
+ */
+ public CertificateAuthority(
+ String subsystemId,
+ ISubsystem owner,
+ IConfigStore config,
+ List<String> path) throws EBaseException {
+ subCAHier = path;
+ subCAOUs = joinSubCAOUs(subCAHier);
+ setId(subsystemId);
+ init(owner, config);
}
/**
@@ -1226,13 +1254,17 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori
mIssuerObj = new CertificateIssuerName((X500Name)mSubjectObj.get(CertificateIssuerName.DN_NAME));
}
- mSigningUnit.init(this, caSigningCfg);
+ String handle = null;
+ if (subCAHier != null && subCAHier.size() > 0)
+ handle = StringUtils.join(subCAHier, ",");
+ mSigningUnit.init(this, caSigningCfg, handle);
CMS.debug("CA signing unit inited");
// for identrus
IConfigStore CrlStore = mConfig.getSubStore(PROP_CRL_SIGNING_SUBSTORE);
- if (CrlStore != null && CrlStore.size() > 0) {
+ if (CrlStore != null && CrlStore.size() > 0
+ && (subCAHier == null || subCAHier.size() == 0)) {
mCRLSigningUnit = new SigningUnit();
mCRLSigningUnit.init(this, mConfig.getSubStore(PROP_CRL_SIGNING_SUBSTORE));
} else {
@@ -1302,7 +1334,8 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori
IConfigStore OCSPStore = mConfig.getSubStore(PROP_OCSP_SIGNING_SUBSTORE);
- if (OCSPStore != null && OCSPStore.size() > 0) {
+ if (OCSPStore != null && OCSPStore.size() > 0
+ && (subCAHier == null || subCAHier.size() == 0)) {
mOCSPSigningUnit = new SigningUnit();
mOCSPSigningUnit.init(this, mConfig.getSubStore(PROP_OCSP_SIGNING_SUBSTORE));
CMS.debug("Separate OCSP signing unit inited");
@@ -1448,13 +1481,13 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori
String certReposDN = mConfig.getString(PROP_CERT_REPOS_DN, null);
if (certReposDN == null) {
- certReposDN = "ou=certificateRepository, ou=" + getId() +
+ certReposDN = subCAOUs + "ou=certificateRepository, ou=" + getId() +
", " + getDBSubsystem().getBaseDN();
}
String reposDN = mConfig.getString(PROP_REPOS_DN, null);
if (reposDN == null) {
- reposDN = "ou=certificateRepository, ou=" + getId() +
+ reposDN = subCAOUs + "ou=certificateRepository, ou=" + getId() +
", " + getDBSubsystem().getBaseDN();
}
@@ -2089,4 +2122,51 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori
return new SingleResponse(cid, certStatus, thisUpdate, nextUpdate);
}
+
+ /**
+ * Get the sub-CA specified by a slash-delimited string.
+ *
+ * Leading and trailing slashes are stripped and multiple
+ * slashes appearing together in the interior are treated
+ * as a single delimiter.
+ */
+ public ICertificateAuthority getSubCA(String pathRaw)
+ throws EBaseException {
+ if (pathRaw == null)
+ return this;
+ pathRaw = StringUtils.strip(pathRaw, "/");
+ String[] pathComponents = StringUtils.split(pathRaw, "/");
+ Vector<String> path = new Vector(pathComponents.length);
+ for (String s : pathComponents)
+ path.add(s);
+ return getSubCA(path);
+ }
+
+ /**
+ * Get the sub-CA specified by the relative hierarchy.
+ */
+ public ICertificateAuthority getSubCA(List<String> relHier)
+ throws EBaseException {
+ if (relHier == null || relHier.size() < 1)
+ return this;
+
+ List<String> newHier = new Vector();
+ if (subCAHier != null)
+ newHier.addAll(0, subCAHier);
+ newHier.add(relHier.get(0));
+
+ CertificateAuthority subCA = new CertificateAuthority(
+ getId(), mOwner, mConfig, newHier);
+ return subCA.getSubCA(relHier.subList(1, relHier.size()));
+ }
+
+ private static String joinSubCAOUs(List<String> handles) {
+ String s = "";
+ if (handles != null) {
+ for (String handle : handles) {
+ s = "ou=" + handle + "," + s;
+ }
+ }
+ return s;
+ }
}
diff --git a/base/ca/src/com/netscape/ca/SigningUnit.java b/base/ca/src/com/netscape/ca/SigningUnit.java
index 2466fb652a46a3b5faede616cb397d18e592f5a0..e8917017b051ba5277194381cb2eb341909df9ae 100644
--- a/base/ca/src/com/netscape/ca/SigningUnit.java
+++ b/base/ca/src/com/netscape/ca/SigningUnit.java
@@ -133,6 +133,11 @@ public final class SigningUnit implements ISigningUnit {
public void init(ISubsystem owner, IConfigStore config)
throws EBaseException {
+ init(owner, config, null);
+ }
+
+ public void init(ISubsystem owner, IConfigStore config, String caHandle)
+ throws EBaseException {
mOwner = owner;
mConfig = config;
@@ -140,7 +145,10 @@ public final class SigningUnit implements ISigningUnit {
try {
mManager = CryptoManager.getInstance();
- mNickname = getNickName();
+ if (caHandle == null)
+ mNickname = getNickName();
+ else
+ mNickname = getNickName() + " " + caHandle;
tokenname = config.getString(PROP_TOKEN_NAME);
if (tokenname.equalsIgnoreCase(Constants.PR_INTERNAL_TOKEN) ||
diff --git a/base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java b/base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java
index f87f15420b3ea6e02e5ce47b5c350e86f67ccc9f..7abd79ac8e2ee223318b14ef8dc6331931b273c8 100644
--- a/base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java
+++ b/base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java
@@ -18,6 +18,7 @@
package com.netscape.certsrv.ca;
import java.util.Enumeration;
+import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
@@ -515,4 +516,20 @@ public interface ICertificateAuthority extends ISubsystem {
public CertificateIssuerName getIssuerObj();
public CertificateSubjectName getSubjectObj();
+
+ /**
+ * Get the sub-CA specified by a slash-delimited string.
+ *
+ * Leading and trailing slashes are stripped and multiple
+ * slashes appearing together in the interior are treated
+ * as a single delimiter.
+ */
+ public ICertificateAuthority getSubCA(String pathRaw)
+ throws EBaseException;
+
+ /**
+ * Get the sub-CA specified by the relative heirarchy.
+ */
+ public ICertificateAuthority getSubCA(List<String> relHier)
+ throws EBaseException;
}
diff --git a/base/common/src/com/netscape/certsrv/profile/IEnrollProfile.java b/base/common/src/com/netscape/certsrv/profile/IEnrollProfile.java
index 69a39d7e23232a1a0cc6e2fe98305d452234bb8c..a28ffb3586c88d0a92d976531ee682dfb4997337 100644
--- a/base/common/src/com/netscape/certsrv/profile/IEnrollProfile.java
+++ b/base/common/src/com/netscape/certsrv/profile/IEnrollProfile.java
@@ -175,6 +175,11 @@ public interface IEnrollProfile extends IProfile {
public static final String REQUEST_ALGORITHM_PARAMS = "req_algorithm_params";
/**
+ * Reference to requested certificate authority
+ */
+ public static final String REQUEST_AUTHORITY_REF = "req_authority_ref";
+
+ /**
* Set Default X509CertInfo in the request.
*
* @param request profile-based certificate request.
diff --git a/base/server/cms/src/com/netscape/cms/profile/common/CAEnrollProfile.java b/base/server/cms/src/com/netscape/cms/profile/common/CAEnrollProfile.java
index d0bfdb8a64ee857a3f5ff544e41de905b4660f55..990c3e6e66ccf6424feb385df8f6900a7c9fe153 100644
--- a/base/server/cms/src/com/netscape/cms/profile/common/CAEnrollProfile.java
+++ b/base/server/cms/src/com/netscape/cms/profile/common/CAEnrollProfile.java
@@ -95,8 +95,13 @@ public class CAEnrollProfile extends EnrollProfile {
CMS.debug("CAEnrollProfile: execute reqId=" +
request.getRequestId().toString());
ICertificateAuthority ca = (ICertificateAuthority) getAuthority();
+ try {
+ ca = ca.getSubCA(request.getExtDataInString(REQUEST_AUTHORITY_REF));
+ } catch (EBaseException e) {
+ throw new EProfileException("Could not reach requested CA");
+ }
+
ICAService caService = (ICAService) ca.getCAService();
-
if (caService == null) {
throw new EProfileException("No CA Service");
}
diff --git a/base/server/cms/src/com/netscape/cms/profile/common/EnrollProfile.java b/base/server/cms/src/com/netscape/cms/profile/common/EnrollProfile.java
index fc17970b3765fc46c46d0f683ddc16ef9dcbe6fc..3c6344b238967a089491448777e43263d66dff9f 100644
--- a/base/server/cms/src/com/netscape/cms/profile/common/EnrollProfile.java
+++ b/base/server/cms/src/com/netscape/cms/profile/common/EnrollProfile.java
@@ -192,6 +192,9 @@ public abstract class EnrollProfile extends BasicProfile
if (locale != null) {
result[i].setExtData(REQUEST_LOCALE, locale.getLanguage());
}
+
+ // set requested CA
+ result[i].setExtData(REQUEST_AUTHORITY_REF, ctx.get(REQUEST_AUTHORITY_REF));
}
return result;
}
diff --git a/base/server/cms/src/com/netscape/cms/profile/def/AuthInfoAccessExtDefault.java b/base/server/cms/src/com/netscape/cms/profile/def/AuthInfoAccessExtDefault.java
index 36818a90753b75f958cca4dd4c93f18629b93411..3762ad33974529f329eeda7da2dc18b43a3b4306 100644
--- a/base/server/cms/src/com/netscape/cms/profile/def/AuthInfoAccessExtDefault.java
+++ b/base/server/cms/src/com/netscape/cms/profile/def/AuthInfoAccessExtDefault.java
@@ -33,6 +33,7 @@ import com.netscape.certsrv.apps.CMS;
import com.netscape.certsrv.base.IConfigStore;
import com.netscape.certsrv.common.NameValuePairs;
import com.netscape.certsrv.profile.EProfileException;
+import com.netscape.certsrv.profile.IEnrollProfile;
import com.netscape.certsrv.profile.IProfile;
import com.netscape.certsrv.property.Descriptor;
import com.netscape.certsrv.property.EPropertyException;
@@ -403,12 +404,13 @@ public class AuthInfoAccessExtDefault extends EnrollExtDefault {
*/
public void populate(IRequest request, X509CertInfo info)
throws EProfileException {
- AuthInfoAccessExtension ext = createExtension();
+ String caRef = request.getExtDataInString(IEnrollProfile.REQUEST_AUTHORITY_REF);
+ AuthInfoAccessExtension ext = createExtension(caRef);
addExtension(ext.getExtensionId().toString(), ext, info);
}
- public AuthInfoAccessExtension createExtension() {
+ public AuthInfoAccessExtension createExtension(String caRef) {
AuthInfoAccessExtension ext = null;
int num = getNumAds();
@@ -433,6 +435,8 @@ public class AuthInfoAccessExtDefault extends EnrollExtDefault {
if (hostname != null && port != null)
// location = "http://"+hostname+":"+port+"/ocsp/ee/ocsp";
location = "http://" + hostname + ":" + port + "/ca/ocsp";
+ if (caRef != null && !caRef.isEmpty())
+ location += "?caRef=" + caRef;
}
}
diff --git a/base/server/cms/src/com/netscape/cms/profile/def/AuthorityKeyIdentifierExtDefault.java b/base/server/cms/src/com/netscape/cms/profile/def/AuthorityKeyIdentifierExtDefault.java
index 77fd0a5fdaea2de826ee848fd88883910d4c3f3b..e9a808524434b7990efdf19b1d2df3435152a087 100644
--- a/base/server/cms/src/com/netscape/cms/profile/def/AuthorityKeyIdentifierExtDefault.java
+++ b/base/server/cms/src/com/netscape/cms/profile/def/AuthorityKeyIdentifierExtDefault.java
@@ -26,8 +26,11 @@ import netscape.security.x509.PKIXExtensions;
import netscape.security.x509.X509CertInfo;
import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.ca.ICertificateAuthority;
import com.netscape.certsrv.profile.EProfileException;
+import com.netscape.certsrv.profile.IEnrollProfile;
import com.netscape.certsrv.profile.IProfile;
import com.netscape.certsrv.property.Descriptor;
import com.netscape.certsrv.property.EPropertyException;
@@ -161,18 +164,26 @@ public class AuthorityKeyIdentifierExtDefault extends CAEnrollDefault {
*/
public void populate(IRequest request, X509CertInfo info)
throws EProfileException {
- AuthorityKeyIdentifierExtension ext = createExtension(info);
+ ICertificateAuthority ca = (ICertificateAuthority)
+ CMS.getSubsystem(CMS.SUBSYSTEM_CA);
+ try {
+ ca = ca.getSubCA(request.getExtDataInString(IEnrollProfile.REQUEST_AUTHORITY_REF));
+ } catch (EBaseException e) {
+ throw new EProfileException("Could not reach requested CA");
+ }
+ AuthorityKeyIdentifierExtension ext = createExtension(ca, info);
addExtension(PKIXExtensions.AuthorityKey_Id.toString(), ext, info);
}
- public AuthorityKeyIdentifierExtension createExtension(X509CertInfo info) {
+ public AuthorityKeyIdentifierExtension createExtension(
+ ICertificateAuthority ca, X509CertInfo info) {
KeyIdentifier kid = null;
String localKey = getConfig("localKey");
if (localKey != null && localKey.equals("true")) {
kid = getKeyIdentifier(info);
} else {
- kid = getCAKeyIdentifier();
+ kid = getCAKeyIdentifier(ca);
}
if (kid == null)
diff --git a/base/server/cms/src/com/netscape/cms/profile/def/CAEnrollDefault.java b/base/server/cms/src/com/netscape/cms/profile/def/CAEnrollDefault.java
index 1d1d05ed55ef30114781521ac607eae118546250..696830ead842767892f77bd8f8c9ea6f667225aa 100644
--- a/base/server/cms/src/com/netscape/cms/profile/def/CAEnrollDefault.java
+++ b/base/server/cms/src/com/netscape/cms/profile/def/CAEnrollDefault.java
@@ -68,9 +68,7 @@ public abstract class CAEnrollDefault extends EnrollDefault {
return null;
}
- public KeyIdentifier getCAKeyIdentifier() {
- ICertificateAuthority ca = (ICertificateAuthority)
- CMS.getSubsystem(CMS.SUBSYSTEM_CA);
+ public KeyIdentifier getCAKeyIdentifier(ICertificateAuthority ca) {
X509CertImpl caCert = ca.getCACert();
if (caCert == null) {
// during configuration, we dont have the CA certificate
diff --git a/base/server/cms/src/com/netscape/cms/servlet/cert/DisplayBySerial.java b/base/server/cms/src/com/netscape/cms/servlet/cert/DisplayBySerial.java
index 283cf499e1ca6f12da93db40c2cb08cbeba5ad0b..52c0b34def086677e767ce44be8e5a3d2cad4995 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/cert/DisplayBySerial.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/cert/DisplayBySerial.java
@@ -85,7 +85,6 @@ public class DisplayBySerial extends CMSServlet {
private final static String TPL_FILE1 = "displayBySerial.template";
private final static BigInteger MINUS_ONE = new BigInteger("-1");
- private ICertificateRepository mCertDB = null;
private String mForm1Path = null;
private X509Certificate mCACerts[] = null;
@@ -103,9 +102,6 @@ public class DisplayBySerial extends CMSServlet {
*/
public void init(ServletConfig sc) throws ServletException {
super.init(sc);
- if (mAuthority instanceof ICertificateAuthority) {
- mCertDB = ((ICertificateAuthority) mAuthority).getCertificateRepository();
- }
try {
mCACerts = ((ICertAuthority) mAuthority).getCACertChain().getChain();
} catch (Exception e) {
@@ -143,6 +139,9 @@ public class DisplayBySerial extends CMSServlet {
CMSTemplate form = null;
Locale[] locale = new Locale[1];
+ ICertificateAuthority targetCA = certAuthority.getSubCA(req.getParameter("caRef"));
+ ICertificateRepository certDB = targetCA.getCertificateRepository();
+
try {
AuthzToken authzToken = null;
@@ -160,7 +159,7 @@ public class DisplayBySerial extends CMSServlet {
}
serialNumber = getSerialNumber(req);
- getCertRecord(serialNumber, certType); //throw exception on error
+ getCertRecord(certDB, serialNumber, certType); //throw exception on error
if (certType[0].equalsIgnoreCase("x509")) {
form = getTemplate(mForm1Path, req, locale);
@@ -185,7 +184,7 @@ public class DisplayBySerial extends CMSServlet {
try {
if (serialNumber.compareTo(MINUS_ONE) > 0) {
- process(argSet, header, serialNumber,
+ process(certDB, argSet, header, serialNumber,
req, resp, locale[0]);
} else {
error = new ECMSGWException(
@@ -222,7 +221,9 @@ public class DisplayBySerial extends CMSServlet {
/**
* Display information about a particular certificate
*/
- private void process(CMSTemplateParams argSet, IArgBlock header,
+ private void process(
+ ICertificateRepository certDB,
+ CMSTemplateParams argSet, IArgBlock header,
BigInteger seq, HttpServletRequest req,
HttpServletResponse resp,
Locale locale)
@@ -230,10 +231,10 @@ public class DisplayBySerial extends CMSServlet {
String certType[] = new String[1];
try {
- getCertRecord(seq, certType); // throw exception on error
+ getCertRecord(certDB, seq, certType); // throw exception on error
if (certType[0].equalsIgnoreCase("x509")) {
- processX509(argSet, header, seq, req, resp, locale);
+ processX509(certDB, argSet, header, seq, req, resp, locale);
return;
}
} catch (EBaseException e) {
@@ -245,7 +246,9 @@ public class DisplayBySerial extends CMSServlet {
return;
}
- private void processX509(CMSTemplateParams argSet, IArgBlock header,
+ private void processX509(
+ ICertificateRepository certDB,
+ CMSTemplateParams argSet, IArgBlock header,
BigInteger seq, HttpServletRequest req,
HttpServletResponse resp,
Locale locale)
@@ -257,7 +260,7 @@ public class DisplayBySerial extends CMSServlet {
}
try {
- ICertRecord rec = mCertDB.readCertificateRecord(seq);
+ ICertRecord rec = certDB.readCertificateRecord(seq);
if (rec == null) {
CMS.debug("DisplayBySerial: failed to read record");
throw new ECMSGWException(
@@ -461,12 +464,14 @@ public class DisplayBySerial extends CMSServlet {
return;
}
- private ICertRecord getCertRecord(BigInteger seq, String certtype[])
+ private ICertRecord getCertRecord(
+ ICertificateRepository certDB,
+ BigInteger seq, String certtype[])
throws EBaseException {
ICertRecord rec = null;
try {
- rec = mCertDB.readCertificateRecord(seq);
+ rec = certDB.readCertificateRecord(seq);
X509CertImpl x509cert = rec.getCertificate();
if (x509cert != null) {
diff --git a/base/server/cms/src/com/netscape/cms/servlet/cert/DoRevoke.java b/base/server/cms/src/com/netscape/cms/servlet/cert/DoRevoke.java
index 1788be3039d12280d573dc9209ae2dbff3b9efd1..395425a17f88c3da38f00fb73caf5e5a2e29ee98 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/cert/DoRevoke.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/cert/DoRevoke.java
@@ -84,7 +84,6 @@ public class DoRevoke extends CMSServlet {
private static final long serialVersionUID = 1693115906265904238L;
private final static String TPL_FILE = "revocationResult.template";
- private ICertificateRepository mCertDB = null;
private String mFormPath = null;
private IPublisherProcessor mPublisherProcessor = null;
private int mTimeLimits = 30; /* in seconds */
@@ -103,9 +102,6 @@ public class DoRevoke extends CMSServlet {
super.init(sc);
mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE;
- if (mAuthority instanceof ICertificateAuthority) {
- mCertDB = ((ICertificateAuthority) mAuthority).getCertificateRepository();
- }
if (mAuthority instanceof ICertAuthority) {
mPublisherProcessor = ((ICertAuthority) mAuthority).getPublisherProcessor();
}
@@ -375,6 +371,8 @@ public class DoRevoke extends CMSServlet {
CMS.debug("DoRevoke: eeSerialNumber: " + eeSerialNumber);
long startTime = CMS.getCurrentDate().getTime();
+ ICertificateAuthority targetCA = certAuthority.getSubCA(req.getParameter("caRef"));
+
RevocationProcessor processor =
new RevocationProcessor(servletConfig.getServletName(), getLocale(req));
@@ -395,9 +393,9 @@ public class DoRevoke extends CMSServlet {
X509Certificate clientCert = getSSLClientCertificate(req);
if (mAuthority instanceof ICertificateAuthority) {
- processor.setAuthority(certAuthority);
+ processor.setAuthority(targetCA);
- if (certAuthority.noncesEnabled()) {
+ if (targetCA.noncesEnabled()) {
String nonces = req.getParameter("nonce");
if (nonces == null) {
throw new ForbiddenException("Missing nonce.");
@@ -418,7 +416,8 @@ public class DoRevoke extends CMSServlet {
if (mAuthority instanceof ICertificateAuthority) {
- Enumeration<ICertRecord> e = mCertDB.searchCertificates(revokeAll, totalRecordCount, mTimeLimits);
+ ICertificateRepository certDB = targetCA.getCertificateRepository();
+ Enumeration<ICertRecord> e = certDB.searchCertificates(revokeAll, totalRecordCount, mTimeLimits);
while (e != null && e.hasMoreElements()) {
ICertRecord targetRecord = e.nextElement();
@@ -441,7 +440,7 @@ public class DoRevoke extends CMSServlet {
try {
if (mAuthority instanceof ICertificateAuthority &&
- certAuthority.noncesEnabled() &&
+ targetCA.noncesEnabled() &&
!processor.isMemberOfSubsystemGroup(clientCert)) {
// validate nonce for each certificate
Long nonce = nonceMap.get(targetRecord.getSerialNumber());
diff --git a/base/server/cms/src/com/netscape/cms/servlet/cert/EnrollmentProcessor.java b/base/server/cms/src/com/netscape/cms/servlet/cert/EnrollmentProcessor.java
index ee56f01399aa701c18fde4701e0c635772298d3c..b1d2c0f0c95c0160d7b031d408cd09623e7cef2d 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/cert/EnrollmentProcessor.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/cert/EnrollmentProcessor.java
@@ -30,6 +30,7 @@ import com.netscape.certsrv.base.EBaseException;
import com.netscape.certsrv.base.EPropertyNotFound;
import com.netscape.certsrv.base.SessionContext;
import com.netscape.certsrv.cert.CertEnrollmentRequest;
+import com.netscape.certsrv.profile.IEnrollProfile;
import com.netscape.certsrv.profile.IProfile;
import com.netscape.certsrv.profile.IProfileAuthenticator;
import com.netscape.certsrv.profile.IProfileContext;
@@ -145,6 +146,12 @@ public class EnrollmentProcessor extends CertProcessor {
}
IProfileContext ctx = profile.createContext();
+
+ // insert request path into profile context
+ // (it is used to determine the (sub-)CA.
+ //
+ ctx.set(IEnrollProfile.REQUEST_AUTHORITY_REF, request.getParameter("caRef"));
+
CMS.debug("EnrollmentSubmitter: set Inputs into profile Context");
setInputsIntoContext(data, profile, ctx);
diff --git a/base/server/cms/src/com/netscape/cms/servlet/cert/ListCerts.java b/base/server/cms/src/com/netscape/cms/servlet/cert/ListCerts.java
index 185e1fa8e7d24afdde7c4735722609921c6800ea..044a4571b4b62e61b70a90ab5bc171634b266b97 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/cert/ListCerts.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/cert/ListCerts.java
@@ -74,8 +74,6 @@ public class ListCerts extends CMSServlet {
private final static String USE_CLIENT_FILTER = "useClientFilter";
private final static String ALLOWED_CLIENT_FILTERS = "allowedClientFilters";
- private ICertificateRepository mCertDB = null;
- private X500Name mAuthName = null;
private String mFormPath = null;
private boolean mReverse = false;
private boolean mHardJumpTo = false; //jump to the end
@@ -102,13 +100,6 @@ public class ListCerts extends CMSServlet {
// override success to render own template.
mTemplates.remove(ICMSRequest.SUCCESS);
- if (mAuthority instanceof ICertificateAuthority) {
- ICertificateAuthority ca = (ICertificateAuthority) mAuthority;
-
- mCertDB = ca.getCertificateRepository();
- mAuthName = ca.getX500Name();
- }
-
mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE;
if (mOutputTemplatePath != null)
mFormPath = mOutputTemplatePath;
@@ -390,7 +381,10 @@ public class ListCerts extends CMSServlet {
} else
pSize = maxCount;
- ICertRecordList list = mCertDB.findCertRecordsInList(
+ ICertificateAuthority targetCA = certAuthority.getSubCA(req.getParameter("caRef"));
+ ICertificateRepository certDB = targetCA.getCertificateRepository();
+
+ ICertRecordList list = certDB.findCertRecordsInList(
filter, (String[]) null, jumpTo, mHardJumpTo, "serialno",
pSize);
// retrive maxCount + 1 entries
@@ -403,7 +397,7 @@ public class ListCerts extends CMSServlet {
if (!serialToVal.equals(MINUS_ONE)) {
// if user specify a range, we need to
// calculate the totalRecordCount
- tolist = mCertDB.findCertRecordsInList(
+ tolist = certDB.findCertRecordsInList(
filter,
(String[]) null, serialTo,
"serialno", maxCount);
@@ -509,11 +503,14 @@ public class ListCerts extends CMSServlet {
nextRec = e.nextElement();
}
+ header.addStringValue("caRef", req.getParameter("caRef"));
header.addStringValue("op", req.getParameter("op"));
if (revokeAll != null)
header.addStringValue("revokeAll", revokeAll);
- if (mAuthName != null)
- header.addStringValue("issuerName", mAuthName.toString());
+
+ X500Name issuerName = targetCA.getX500Name();
+ if (issuerName != null)
+ header.addStringValue("issuerName", issuerName.toString());
if (!serialToVal.equals(MINUS_ONE))
header.addStringValue("serialTo", serialToVal.toString());
header.addStringValue("serviceURL", req.getRequestURI());
diff --git a/base/server/cms/src/com/netscape/cms/servlet/cert/ReasonToRevoke.java b/base/server/cms/src/com/netscape/cms/servlet/cert/ReasonToRevoke.java
index c65c482b14a8670c2f87274d4194c9a40b883c68..3e3db1fec30cadfbfc9a81ca5169e19be1e85862 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/cert/ReasonToRevoke.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/cert/ReasonToRevoke.java
@@ -65,7 +65,6 @@ public class ReasonToRevoke extends CMSServlet {
private final static String TPL_FILE = "reasonToRevoke.template";
private final static String INFO = "ReasonToRevoke";
- private ICertificateRepository mCertDB = null;
private String mFormPath = null;
private ICertificateAuthority mCA = null;
private Random mRandom = null;
@@ -84,10 +83,8 @@ public class ReasonToRevoke extends CMSServlet {
public void init(ServletConfig sc) throws ServletException {
super.init(sc);
mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE;
- if (mAuthority instanceof ICertificateAuthority) {
+ if (mAuthority instanceof ICertificateAuthority)
mCA = (ICertificateAuthority) mAuthority;
- mCertDB = ((ICertificateAuthority) mAuthority).getCertificateRepository();
- }
if (mCA != null && mCA.noncesEnabled()) {
mRandom = new Random();
@@ -221,6 +218,7 @@ public class ReasonToRevoke extends CMSServlet {
Locale locale)
throws EBaseException {
+ header.addStringValue("caRef", req.getParameter("caRef"));
header.addStringValue("revokeAll", revokeAll);
header.addIntegerValue("totalRecordCount", totalRecordCount);
@@ -234,12 +232,15 @@ public class ReasonToRevoke extends CMSServlet {
}
}
+ ICertificateAuthority targetCA = mCA.getSubCA(req.getParameter("caRef"));
+ ICertificateRepository certDB = targetCA.getCertificateRepository();
+
/**
- * ICertRecordList list = mCertDB.findCertRecordsInList(
+ * ICertRecordList list = certDB.findCertRecordsInList(
* revokeAll, null, totalRecordCount);
* Enumeration e = list.getCertRecords(0, totalRecordCount - 1);
**/
- Enumeration<ICertRecord> e = mCertDB.searchCertificates(revokeAll,
+ Enumeration<ICertRecord> e = certDB.searchCertificates(revokeAll,
totalRecordCount, mTimeLimits);
ArrayList<String> noncesList = new ArrayList<String>();
diff --git a/base/server/cms/src/com/netscape/cms/servlet/cert/SrchCerts.java b/base/server/cms/src/com/netscape/cms/servlet/cert/SrchCerts.java
index 508a8df70a3fc8401879907c62f1939dbb410722..66898cd5d7a83681d8ec3ec364c31eb63866d040 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/cert/SrchCerts.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/cert/SrchCerts.java
@@ -78,8 +78,6 @@ public class SrchCerts extends CMSServlet {
private final static String CURRENT_TIME = "currentTime";
private final static int MAX_RESULTS = 1000;
- private ICertificateRepository mCertDB = null;
- private X500Name mAuthName = null;
private String mFormPath = null;
private int mMaxReturns = MAX_RESULTS;
private int mTimeLimits = 30; /* in seconds */
@@ -115,12 +113,6 @@ public class SrchCerts extends CMSServlet {
}
}
}
- if (mAuthority instanceof ICertificateAuthority) {
- ICertificateAuthority ca = (ICertificateAuthority) mAuthority;
-
- mCertDB = ca.getCertificateRepository();
- mAuthName = ca.getX500Name();
- }
mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE;
@@ -548,7 +540,8 @@ public class SrchCerts extends CMSServlet {
timeLimit = Integer.parseInt(timeLimitStr);
String queryCertFilter = buildFilter(req);
- process(argSet, header, queryCertFilter,
+ ICertificateAuthority targetCA = certAuthority.getSubCA(req.getParameter("caRef"));
+ process(targetCA, argSet, header, queryCertFilter,
revokeAll, maxResults, timeLimit, req, resp, locale[0]);
} catch (NumberFormatException e) {
log(ILogger.LL_FAILURE, CMS.getLogMessage("BASE_INVALID_NUMBER_FORMAT"));
@@ -584,13 +577,16 @@ public class SrchCerts extends CMSServlet {
/**
* Process the key search.
*/
- private void process(CMSTemplateParams argSet, IArgBlock header,
+ private void process(ICertificateAuthority ca,
+ CMSTemplateParams argSet, IArgBlock header,
String filter, String revokeAll,
int maxResults, int timeLimit,
HttpServletRequest req, HttpServletResponse resp,
Locale locale)
throws EBaseException {
try {
+ ICertificateRepository certDB = ca.getCertificateRepository();
+
long startTime = CMS.getCurrentDate().getTime();
if (filter.indexOf(CURRENT_TIME, 0) > -1) {
@@ -608,7 +604,7 @@ public class SrchCerts extends CMSServlet {
}
CMS.debug("Start searching ... "
+ "filter=" + filter + " maxreturns=" + maxResults + " timelimit=" + timeLimit);
- Enumeration<ICertRecord> e = mCertDB.searchCertificates(filter, maxResults, timeLimit);
+ Enumeration<ICertRecord> e = certDB.searchCertificates(filter, maxResults, timeLimit);
int count = 0;
@@ -626,9 +622,11 @@ public class SrchCerts extends CMSServlet {
long endTime = CMS.getCurrentDate().getTime();
+ header.addStringValue("caRef", req.getParameter("caRef"));
header.addStringValue("op", req.getParameter("op"));
- if (mAuthName != null)
- header.addStringValue("issuerName", mAuthName.toString());
+ X500Name issuerName = ca.getX500Name();
+ if (issuerName != null)
+ header.addStringValue("issuerName", issuerName.toString());
header.addStringValue("time", Long.toString(endTime - startTime));
header.addStringValue("serviceURL", req.getRequestURI());
header.addStringValue("queryFilter", filter);
diff --git a/base/server/cms/src/com/netscape/cms/servlet/ocsp/OCSPServlet.java b/base/server/cms/src/com/netscape/cms/servlet/ocsp/OCSPServlet.java
index 940bf657c6febdb9ec01757daa2f1a49ac2ee2be..77554ea24513635e37304a3b8870698c0f3e845d 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/ocsp/OCSPServlet.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/ocsp/OCSPServlet.java
@@ -35,6 +35,7 @@ import com.netscape.certsrv.apps.CMS;
import com.netscape.certsrv.authentication.IAuthToken;
import com.netscape.certsrv.authorization.AuthzToken;
import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.ca.ICertificateAuthority;
import com.netscape.certsrv.common.ICMSRequest;
import com.netscape.certsrv.ocsp.IOCSPService;
import com.netscape.certsrv.util.IStatsSubsystem;
@@ -204,7 +205,9 @@ public class OCSPServlet extends CMSServlet {
throw new Exception("OCSPServlet: Decoded OCSP request "
+ "is empty or malformed");
}
- response = ((IOCSPService) mAuthority).validate(ocspReq);
+ ICertificateAuthority targetCA =
+ certAuthority.getSubCA(httpReq.getParameter("caRef"));
+ response = ((IOCSPService) targetCA).validate(ocspReq);
} catch (Exception e) {
;
CMS.debug("OCSPServlet: " + e.toString());
--
2.1.0
More information about the Pki-devel
mailing list