From 1a0e1d4cb45c611b0a9cdab38ac55e1d9a1c01af Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Tue, 15 Sep 2015 23:36:58 -0400 Subject: [PATCH 48/50] Lightweight CAs: add 'authorityEnabled' attribute Add the 'authortyEnabled' attribute for lightweight CAs and throw new exception CADisabledException when request submission or signing operations are attempted on a disabled authority. Part of: https://fedorahosted.org/pki/ticket/1604 --- .../src/com/netscape/ca/CertificateAuthority.java | 30 +++++++++++++++++++--- .../server/ca/rest/CertRequestService.java | 8 ++++++ .../netscape/certsrv/ca/CADisabledException.java | 13 ++++++++++ .../cms/servlet/cert/EnrollmentProcessor.java | 6 ++++- .../cms/servlet/cert/RequestProcessor.java | 30 +++++++++++++++++++++- base/server/share/conf/schema-subCA.ldif | 3 ++- base/server/share/conf/schema.ldif | 3 ++- 7 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 base/common/src/com/netscape/certsrv/ca/CADisabledException.java diff --git a/base/ca/src/com/netscape/ca/CertificateAuthority.java b/base/ca/src/com/netscape/ca/CertificateAuthority.java index 5df7c77612132d2dc52ca43060d7ba782d9388cc..05ab2a6024ab311b80cfd3ef026d77691169aac8 100644 --- a/base/ca/src/com/netscape/ca/CertificateAuthority.java +++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java @@ -89,6 +89,7 @@ import com.netscape.certsrv.base.ISubsystem; import com.netscape.certsrv.base.Nonces; import com.netscape.certsrv.base.PKIException; import com.netscape.certsrv.ca.AuthorityID; +import com.netscape.certsrv.ca.CADisabledException; import com.netscape.certsrv.ca.CANotFoundException; import com.netscape.certsrv.ca.ECAException; import com.netscape.certsrv.ca.ICRLIssuingPoint; @@ -167,6 +168,7 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori protected AuthorityID authorityID = null; protected AuthorityID authorityParentID = null; protected String authorityDescription = null; + protected boolean authorityEnabled = true; protected ISubsystem mOwner = null; protected IConfigStore mConfig = null; @@ -277,13 +279,15 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori AuthorityID aid, AuthorityID parentAID, String signingKeyNickname, - String authorityDescription + String authorityDescription, + boolean authorityEnabled ) throws EBaseException { setId(topCA.getId()); this.topCA = topCA; this.authorityID = aid; this.authorityParentID = parentAID; this.authorityDescription = authorityDescription; + this.authorityEnabled = authorityEnabled; mNickname = signingKeyNickname; init(topCA.mOwner, topCA.mConfig); } @@ -292,6 +296,11 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori return authorityID == null; } + private void ensureEnabled() throws CADisabledException { + if (!authorityEnabled) + throw new CADisabledException("Authority is disabled"); + } + /** * Retrieves subsystem identifier. */ @@ -1056,6 +1065,7 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori */ public X509CRLImpl sign(X509CRLImpl crl, String algname) throws EBaseException { + ensureEnabled(); X509CRLImpl signedcrl = null; IStatsSubsystem statsSub = (IStatsSubsystem) CMS.getSubsystem("stats"); @@ -1128,6 +1138,7 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori */ public X509CertImpl sign(X509CertInfo certInfo, String algname) throws EBaseException { + ensureEnabled(); X509CertImpl signedcert = null; @@ -1212,6 +1223,7 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori */ public byte[] sign(byte[] data, String algname) throws EBaseException { + ensureEnabled(); return mSigningUnit.sign(data, algname); } @@ -1952,8 +1964,16 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori if (descAttr != null) desc = (String) descAttr.getStringValues().nextElement(); + boolean enabled = true; + LDAPAttribute enabledAttr = entry.getAttribute("authorityEnabled"); + if (enabledAttr != null) { + String enabledString = (String) + enabledAttr.getStringValues().nextElement(); + enabled = enabledString.equalsIgnoreCase("TRUE"); + } + CertificateAuthority subCA = new CertificateAuthority( - this, aid, parentAID, keyNick, desc); + this, aid, parentAID, keyNick, desc, enabled); caMap.put(aid, subCA); } } catch (LDAPException e) { @@ -2131,6 +2151,7 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori } private BasicOCSPResponse sign(ResponseData rd) throws EBaseException { + ensureEnabled(); try (DerOutputStream out = new DerOutputStream()) { DerOutputStream tmp = new DerOutputStream(); @@ -2352,7 +2373,8 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori new LDAPAttribute("objectclass", "authority"), new LDAPAttribute("cn", aidString), new LDAPAttribute("authorityID", aidString), - new LDAPAttribute("authorityKeyNickname", nickname) + new LDAPAttribute("authorityKeyNickname", nickname), + new LDAPAttribute("authorityEnabled", "TRUE") }; LDAPAttributeSet attrSet = new LDAPAttributeSet(attrs); if (this.authorityID != null) @@ -2407,6 +2429,6 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori } return new CertificateAuthority( - topCA, aid, this.authorityID, nickname, description); + topCA, aid, this.authorityID, nickname, description, true); } } diff --git a/base/ca/src/org/dogtagpki/server/ca/rest/CertRequestService.java b/base/ca/src/org/dogtagpki/server/ca/rest/CertRequestService.java index 654d814d8a963892a6b39a1f77745e1071a5408d..f3ded9a207230ef455b1ae49866c8b5069acfb26 100644 --- a/base/ca/src/org/dogtagpki/server/ca/rest/CertRequestService.java +++ b/base/ca/src/org/dogtagpki/server/ca/rest/CertRequestService.java @@ -38,10 +38,12 @@ import com.netscape.certsrv.authentication.EAuthException; import com.netscape.certsrv.authorization.EAuthzException; import com.netscape.certsrv.base.BadRequestDataException; import com.netscape.certsrv.base.BadRequestException; +import com.netscape.certsrv.base.ConflictingOperationException; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.PKIException; import com.netscape.certsrv.base.ResourceNotFoundException; import com.netscape.certsrv.base.UnauthorizedException; +import com.netscape.certsrv.ca.CADisabledException; import com.netscape.certsrv.ca.CANotFoundException; import com.netscape.certsrv.cert.CertEnrollmentRequest; import com.netscape.certsrv.cert.CertRequestInfo; @@ -143,6 +145,9 @@ public class CertRequestService extends PKIService implements CertRequestResourc } catch (BadRequestDataException e) { CMS.debug("enrollCert: bad request data: " + e); throw new BadRequestException(e.toString()); + } catch (CADisabledException e) { + CMS.debug("enrollCert: CA disabled: " + e); + throw new ConflictingOperationException(e.toString()); } catch (CANotFoundException e) { CMS.debug("enrollCert: unknown CA: " + e); throw new ResourceNotFoundException(e.toString()); @@ -219,6 +224,9 @@ public class CertRequestService extends PKIService implements CertRequestResourc } catch (BadRequestDataException e) { CMS.debug("changeRequestState: bad request data: " + e); throw new BadRequestException(e.toString()); + } catch (CADisabledException e) { + CMS.debug("changeRequestState: CA disabled: " + e); + throw new ConflictingOperationException(e.toString()); } catch (EPropertyException e) { CMS.debug("changeRequestState: execution error " + e); throw new PKIException(CMS.getUserMessage(getLocale(headers), diff --git a/base/common/src/com/netscape/certsrv/ca/CADisabledException.java b/base/common/src/com/netscape/certsrv/ca/CADisabledException.java new file mode 100644 index 0000000000000000000000000000000000000000..df5fdf809f716202c38287e670a88e55eb93ce75 --- /dev/null +++ b/base/common/src/com/netscape/certsrv/ca/CADisabledException.java @@ -0,0 +1,13 @@ +package com.netscape.certsrv.ca; + +/** + * Exception to throw when a (sub-)CA cannot perform an operation + * because it is disabled. + */ +public class CADisabledException extends ECAException { + + public CADisabledException(String msgFormat) { + super(msgFormat); + } + +} 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 7e358b87f35b8aef2d3ef9de3f8dfd4c7a2b7053..5e22fc986dab621191c3157df5d0ef9a842eea34 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 @@ -31,6 +31,7 @@ import com.netscape.certsrv.base.EPropertyNotFound; import com.netscape.certsrv.base.SessionContext; import com.netscape.certsrv.cert.CertEnrollmentRequest; import com.netscape.certsrv.ca.AuthorityID; +import com.netscape.certsrv.ca.CADisabledException; import com.netscape.certsrv.ca.CANotFoundException; import com.netscape.certsrv.ca.ICertificateAuthority; import com.netscape.certsrv.profile.IEnrollProfile; @@ -163,8 +164,11 @@ public class EnrollmentProcessor extends CertProcessor { } ICertificateAuthority ca = (ICertificateAuthority) CMS.getSubsystem(CMS.SUBSYSTEM_CA); - if (ca.getCA(aid) == null) + ca = ca.getCA(aid); + if (ca == null) throw new CANotFoundException("CA not found: " + aidString); + if (!ca.getAuthorityEnabled()) + throw new CADisabledException("CA not enabled: " + aidString); ctx.set(IEnrollProfile.REQUEST_AUTHORITY_ID, aidString); } diff --git a/base/server/cms/src/com/netscape/cms/servlet/cert/RequestProcessor.java b/base/server/cms/src/com/netscape/cms/servlet/cert/RequestProcessor.java index 2826f477e358a5e16657e985d7f13079cdb14a33..df318aa93c95c91c7885360654daf2d4a7da77c6 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/cert/RequestProcessor.java +++ b/base/server/cms/src/com/netscape/cms/servlet/cert/RequestProcessor.java @@ -36,6 +36,10 @@ import com.netscape.certsrv.base.BadRequestException; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.EPropertyNotFound; import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.ca.AuthorityID; +import com.netscape.certsrv.ca.CADisabledException; +import com.netscape.certsrv.ca.CANotFoundException; +import com.netscape.certsrv.ca.ICertificateAuthority; import com.netscape.certsrv.cert.CertReviewResponse; import com.netscape.certsrv.logging.ILogger; import com.netscape.certsrv.profile.EDeferException; @@ -346,11 +350,35 @@ public class RequestProcessor extends CertProcessor { * occurred */ private void approveRequest(IRequest req, CertReviewResponse data, IProfile profile, Locale locale) - throws EProfileException { + throws EBaseException { String auditMessage = null; String auditSubjectID = auditSubjectID(); String auditRequesterID = auditRequesterID(req); + // ensure target CA is enabled + String aidString = req.getExtDataInString(IEnrollProfile.REQUEST_AUTHORITY_ID); + if (aidString != null) { + AuthorityID aid = null; + try { + aid = new AuthorityID(aidString); + } catch (IllegalArgumentException e) { + // request already accepted; shouldn't happen + throw new BadRequestDataException("Invalid AuthorityID in request data"); + } + ICertificateAuthority ca = (ICertificateAuthority) + CMS.getSubsystem("ca"); + if (ca == null) + // shouldn't happen + throw new CANotFoundException("Could not get top-level CA"); // shouldn't happen + ca = ca.getCA(aid); + if (ca == null) + // request already accepted; shouldn't happen + throw new CANotFoundException("Unknown CA: " + aidString); + if (!ca.getAuthorityEnabled()) + // authority disabled after request was submitted + throw new CADisabledException("CA '" + aidString + "' is disabled"); + } + try { profile.execute(req); req.setRequestStatus(RequestStatus.COMPLETE); diff --git a/base/server/share/conf/schema-subCA.ldif b/base/server/share/conf/schema-subCA.ldif index d03ca70ab466a6229f0efbbe2df6c587d8d5ea5c..762fc99abe87419da4a6bc79888a800c49219afa 100644 --- a/base/server/share/conf/schema-subCA.ldif +++ b/base/server/share/conf/schema-subCA.ldif @@ -2,4 +2,5 @@ dn: cn=schema attributeTypes: ( authorityID-oid NAME 'authorityID' DESC 'Authority ID' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 X-ORIGIN 'user defined' ) attributeTypes: ( authorityKeyNickname-oid NAME 'authorityKeyNickname' DESC 'Authority key nickname' SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 X-ORIGIN 'user-defined' ) attributeTypes: ( authorityParentID-oid NAME 'authorityParentID' DESC 'Authority Parent ID' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 X-ORIGIN 'user defined' ) -objectClasses: ( authority-oid NAME 'authority' DESC 'Certificate Authority' SUP top STRUCTURAL MUST ( cn $ authorityID $ authorityKeyNickname ) MAY ( authorityParentID $ description ) X-ORIGIN 'user defined' ) +attributeTypes: ( authorityEnabled-oid NAME 'authorityEnabled' DESC 'Authority Enabled' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 X-ORIGIN 'user defined' ) +objectClasses: ( authority-oid NAME 'authority' DESC 'Certificate Authority' SUP top STRUCTURAL MUST ( cn $ authorityID $ authorityKeyNickname $ authorityEnabled ) MAY ( authorityParentID $ description ) X-ORIGIN 'user defined' ) diff --git a/base/server/share/conf/schema.ldif b/base/server/share/conf/schema.ldif index 3a692cac9370e9bb115a35fd0fe56be1d49b9ce9..72d902713500192b75038ef2c980b4e4ee9bb3b8 100644 --- a/base/server/share/conf/schema.ldif +++ b/base/server/share/conf/schema.ldif @@ -674,6 +674,7 @@ add: attributeTypes attributeTypes: ( authorityID-oid NAME 'authorityID' DESC 'Authority ID' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 X-ORIGIN 'user defined' ) attributeTypes: ( authorityKeyNickname-oid NAME 'authorityKeyNickname' DESC 'Authority key nickname' SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 X-ORIGIN 'user-defined' ) attributeTypes: ( authorityParentID-oid NAME 'authorityParentID' DESC 'Authority Parent ID' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 X-ORIGIN 'user defined' ) +attributeTypes: ( authorityEnabled-oid NAME 'authorityEnabled' DESC 'Authority Enabled' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 X-ORIGIN 'user defined' ) - add: objectClasses -objectClasses: ( authority-oid NAME 'authority' DESC 'Certificate Authority' SUP top STRUCTURAL MUST ( cn $ authorityID $ authorityKeyNickname ) MAY ( authorityParentID $ description ) X-ORIGIN 'user defined' ) +objectClasses: ( authority-oid NAME 'authority' DESC 'Certificate Authority' SUP top STRUCTURAL MUST ( cn $ authorityID $ authorityKeyNickname $ authorityEnabled ) MAY ( authorityParentID $ description ) X-ORIGIN 'user defined' ) -- 2.4.3