From a4682ceae6774956461edd03b2485bbacea445f4 Mon Sep 17 00:00:00 2001 From: mharmsen Date: Tue, 4 Oct 2011 01:17:41 +0000 Subject: Bugzilla Bug #688225 - (dogtagIPAv2.1) TRACKER: of the Dogtag fixes for freeIPA 2.1 git-svn-id: svn+ssh://svn.fedorahosted.org/svn/pki/tags/IPA_v2_RHEL_6_2_20111003@2252 c9f7a03b-bd48-0410-a16d-cbbf54688b0b --- .../src/com/netscape/cms/policy/APolicyRule.java | 354 ++++++++++++++ .../cms/policy/constraints/AgentPolicy.java | 165 +++++++ .../constraints/AttributePresentConstraints.java | 401 +++++++++++++++ .../cms/policy/constraints/DSAKeyConstraints.java | 249 ++++++++++ .../cms/policy/constraints/DefaultRevocation.java | 105 ++++ .../cms/policy/constraints/IssuerConstraints.java | 207 ++++++++ .../constraints/KeyAlgorithmConstraints.java | 221 +++++++++ .../policy/constraints/ManualAuthentication.java | 103 ++++ .../cms/policy/constraints/RSAKeyConstraints.java | 274 +++++++++++ .../cms/policy/constraints/RenewalConstraints.java | 235 +++++++++ .../constraints/RenewalValidityConstraints.java | 342 +++++++++++++ .../policy/constraints/RevocationConstraints.java | 208 ++++++++ .../constraints/SigningAlgorithmConstraints.java | 442 +++++++++++++++++ .../policy/constraints/SubCANameConstraints.java | 189 +++++++ .../cms/policy/constraints/UniqueSubjectName.java | 47 ++ .../constraints/UniqueSubjectNameConstraints.java | 299 ++++++++++++ .../policy/constraints/ValidityConstraints.java | 316 ++++++++++++ .../cms/policy/extensions/AuthInfoAccessExt.java | 381 +++++++++++++++ .../extensions/AuthorityKeyIdentifierExt.java | 418 ++++++++++++++++ .../cms/policy/extensions/BasicConstraintsExt.java | 498 +++++++++++++++++++ .../extensions/CRLDistributionPointsExt.java | 464 ++++++++++++++++++ .../policy/extensions/CertificatePoliciesExt.java | 521 ++++++++++++++++++++ .../extensions/CertificateRenewalWindowExt.java | 247 ++++++++++ .../extensions/CertificateScopeOfUseExt.java | 320 ++++++++++++ .../cms/policy/extensions/ExtendedKeyUsageExt.java | 271 +++++++++++ .../cms/policy/extensions/GenericASN1Ext.java | 471 ++++++++++++++++++ .../cms/policy/extensions/IssuerAltNameExt.java | 252 ++++++++++ .../cms/policy/extensions/KeyUsageExt.java | 351 +++++++++++++ .../cms/policy/extensions/NSCCommentExt.java | 288 +++++++++++ .../cms/policy/extensions/NSCertTypeExt.java | 541 +++++++++++++++++++++ .../cms/policy/extensions/NameConstraintsExt.java | 468 ++++++++++++++++++ .../cms/policy/extensions/OCSPNoCheckExt.java | 183 +++++++ .../policy/extensions/PolicyConstraintsExt.java | 282 +++++++++++ .../cms/policy/extensions/PolicyMappingsExt.java | 417 ++++++++++++++++ .../cms/policy/extensions/PresenceExt.java | 164 +++++++ .../extensions/PrivateKeyUsagePeriodExt.java | 250 ++++++++++ .../extensions/RemoveBasicConstraintsExt.java | 141 ++++++ .../cms/policy/extensions/SubjAltNameExt.java | 350 +++++++++++++ .../cms/policy/extensions/SubjectAltNameExt.java | 322 ++++++++++++ .../extensions/SubjectDirectoryAttributesExt.java | 434 +++++++++++++++++ .../policy/extensions/SubjectKeyIdentifierExt.java | 368 ++++++++++++++ 41 files changed, 12559 insertions(+) create mode 100644 pki/base/common/src/com/netscape/cms/policy/APolicyRule.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/constraints/AgentPolicy.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/constraints/AttributePresentConstraints.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/constraints/DSAKeyConstraints.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/constraints/DefaultRevocation.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/constraints/IssuerConstraints.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/constraints/KeyAlgorithmConstraints.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/constraints/ManualAuthentication.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/constraints/RSAKeyConstraints.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/constraints/RenewalConstraints.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/constraints/RenewalValidityConstraints.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/constraints/RevocationConstraints.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/constraints/SigningAlgorithmConstraints.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/constraints/SubCANameConstraints.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/constraints/UniqueSubjectName.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/constraints/UniqueSubjectNameConstraints.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/constraints/ValidityConstraints.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/AuthInfoAccessExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/AuthorityKeyIdentifierExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/BasicConstraintsExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/CRLDistributionPointsExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/CertificatePoliciesExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/CertificateRenewalWindowExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/CertificateScopeOfUseExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/ExtendedKeyUsageExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/GenericASN1Ext.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/IssuerAltNameExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/KeyUsageExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/NSCCommentExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/NSCertTypeExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/NameConstraintsExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/OCSPNoCheckExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/PolicyConstraintsExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/PolicyMappingsExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/PresenceExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/PrivateKeyUsagePeriodExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/RemoveBasicConstraintsExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/SubjAltNameExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/SubjectAltNameExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/SubjectDirectoryAttributesExt.java create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/SubjectKeyIdentifierExt.java (limited to 'pki/base/common/src/com/netscape/cms/policy') diff --git a/pki/base/common/src/com/netscape/cms/policy/APolicyRule.java b/pki/base/common/src/com/netscape/cms/policy/APolicyRule.java new file mode 100644 index 000000000..d0bd6a6bc --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/APolicyRule.java @@ -0,0 +1,354 @@ +// --- 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.cms.policy; + + +import java.util.*; +import java.text.*; +import java.io.IOException; +import java.security.InvalidKeyException; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.request.AgentApprovals; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.apps.*; +import netscape.security.x509.*; +import java.security.*; +import java.security.cert.*; + + +/** + * The abstract policy rule that concrete implementations will + * extend. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public abstract class APolicyRule implements IPolicyRule { + protected String NAME = null; + protected String DESC = null; + protected IExpression mFilterExp = null; + protected String mInstanceName = null; + protected ILogger mLogger = CMS.getLogger(); + + public APolicyRule() { + } + + /** + * Initializes the policy rule. + *

+ * + * @param config The config store reference + */ + public abstract void init(ISubsystem owner, IConfigStore config) + throws EBaseException; + + /** + * Gets the description for this policy rule. + *

+ * @return The Description for this rule. + */ + public String getDescription() { + return DESC; + } + + /** + * Sets a predicate expression for rule matching. + *

+ * + * @param exp The predicate expression for the rule. + */ + public void setPredicate(IExpression exp) { + mFilterExp = exp; + } + + /** + * Returns the predicate expression for the rule. + *

+ * + * @return The predicate expression for the rule. + */ + public IExpression getPredicate() { + return mFilterExp; + } + + /** + * Returns the name of the policy rule. + *

+ * + * @return The name of the policy class. + */ + public String getName() { + return NAME; + } + + /** + * Sets the instance name for a policy rule. + *

+ * + * @param instanceName The name of the rule instance. + */ + public void setInstanceName(String instanceName) { + mInstanceName = instanceName; + } + + /** + * Returns the name of the policy rule instance. + *

+ * + * @return The name of the policy rule instance if set, else + * the name of the rule class. + */ + public String getInstanceName() { + return mInstanceName != null ? mInstanceName : NAME; + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public abstract PolicyResult apply(IRequest req); + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public abstract Vector getInstanceParams(); + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public abstract Vector getDefaultParams(); + + public void setError(IRequest req, String format, Object[] params) { + setPolicyException(req, format, params); + } + + public void setError(IRequest req, String format, String arg1, + String arg2) { + Object[] np = new Object[2]; + + np[0] = arg1; + np[1] = arg2; + setPolicyException(req, format, np); + } + + public void setError(IRequest req, String format, String arg) { + Object[] np = new Object[1]; + + np[0] = arg; + setPolicyException(req, format, np); + } + + public void setPolicyException(IRequest req, EBaseException ex) { + Vector ev = req.getExtDataInStringVector(IRequest.ERRORS); + if (ev == null) { + ev = new Vector(); + } + ev.addElement(ex.toString()); + req.setExtData(IRequest.ERRORS, ev); + + } + + /** + * determines whether a DEFERRED policy result should be returned + * by checking the contents of the AgentApprovals attribute. This + * call should be used by policy modules instead of returning + * PolicyResult.DEFERRED directly. + *

+ */ + protected PolicyResult deferred(IRequest req) { + // Try to find an agent approval + AgentApprovals aa = AgentApprovals.fromStringVector( + req.getExtDataInStringVector(AgentApprovals.class.getName())); + + // Any approvals causes success + if (aa != null && aa.elements().hasMoreElements()) { + return PolicyResult.ACCEPTED; + } else { + return PolicyResult.DEFERRED; + } + } + + /** + * request has previously been approved by an agent + */ + protected boolean agentApproved(IRequest req) { + // Try to find an agent approval + AgentApprovals aa = AgentApprovals.fromStringVector( + req.getExtDataInStringVector(AgentApprovals.class.getName())); + + // Any approvals causes success + if (aa != null && aa.elements().hasMoreElements()) { + return true; + } else { + return false; + } + } + + public void setPolicyException(IRequest req, String format, + Object[] params) { + if (format == null) + return; + + EPolicyException ex; + + if (params == null) + ex = new EPolicyException(format); + else + ex = new EPolicyException(format, params); + + Vector ev = req.getExtDataInStringVector(IRequest.ERRORS); + if (ev == null) { + ev = new Vector(); + } + ev.addElement(ex.toString()); + req.setExtData(IRequest.ERRORS, ev); + } + + /** + * log a message for this policy rule. + */ + protected void log(int level, String msg) { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER, level, + "APolicyRule " + NAME + ": " + msg); + } + + public static KeyIdentifier createKeyIdentifier(X509Key key) + throws NoSuchAlgorithmException, InvalidKeyException { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + + md.update(key.getEncoded()); + return new KeyIdentifier(md.digest()); + } + + /** + * Form a byte array of octet string key identifier from the sha-1 hash of + * the Subject Public Key INFO. (including algorithm ID, etc.) + *

+ * @param certInfo cert info of the certificate. + * @return A Key identifier with the sha-1 hash of subject public key. + */ + protected KeyIdentifier formSpkiSHA1KeyId(X509CertInfo certInfo) + throws EBaseException { + KeyIdentifier keyId = null; + + try { + CertificateX509Key certKey = + (CertificateX509Key) certInfo.get(X509CertInfo.KEY); + + if (certKey == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_MISSING_KEY_1", "")); + throw new EPolicyException(CMS.getUserMessage("CMS_POLICY_MISSING_KEY", NAME)); + } + X509Key key = (X509Key) certKey.get(CertificateX509Key.KEY); + + if (key == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_MISSING_KEY_1", "")); + throw new EPolicyException(CMS.getUserMessage("CMS_POLICY_MISSING_KEY", NAME)); + } + keyId = createKeyIdentifier(key); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_SUBJECT_KEY_ID_1", NAME)); + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_SUBJECT_KEY_ID_ERROR", NAME)); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_SUBJECT_KEY_ID_1", NAME)); + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_SUBJECT_KEY_ID_ERROR", NAME)); + } catch (NoSuchAlgorithmException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_SUBJECT_KEY_ID_1", NAME)); + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_SUBJECT_KEY_ID_ERROR", NAME)); + } catch (InvalidKeyException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_SUBJECT_KEY_ID_1", NAME)); + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_SUBJECT_KEY_ID_ERROR", NAME)); + } + return keyId; + } + + /** + * Form a byte array of octet string key identifier from the sha-1 hash of + * the Subject Public Key BIT STRING. + *

+ * @param certInfo cert info of the certificate. + * @return A Key identifier with the sha-1 hash of subject public key. + */ + protected KeyIdentifier formSHA1KeyId(X509CertInfo certInfo) + throws EBaseException { + KeyIdentifier keyId = null; + + try { + CertificateX509Key certKey = + (CertificateX509Key) certInfo.get(X509CertInfo.KEY); + + if (certKey == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_MISSING_KEY_1", "")); + throw new EPolicyException(CMS.getUserMessage("CMS_POLICY_MISSING_KEY", NAME)); + } + X509Key key = (X509Key) certKey.get(CertificateX509Key.KEY); + + if (key == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_MISSING_KEY_1", "")); + throw new EPolicyException(CMS.getUserMessage("CMS_POLICY_MISSING_KEY", NAME)); + } + byte[] rawKey = key.getKey(); + + MessageDigest md = MessageDigest.getInstance("SHA-1"); + + md.update(rawKey); + keyId = new KeyIdentifier(md.digest()); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_SUBJECT_KEY_ID_1", NAME)); + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_SUBJECT_KEY_ID_ERROR", NAME)); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_SUBJECT_KEY_ID_1", NAME)); + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_SUBJECT_KEY_ID_ERROR", NAME)); + } catch (NoSuchAlgorithmException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_SUBJECT_KEY_ID_1", NAME)); + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_SUBJECT_KEY_ID_ERROR", NAME)); + } + return keyId; + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/constraints/AgentPolicy.java b/pki/base/common/src/com/netscape/cms/policy/constraints/AgentPolicy.java new file mode 100644 index 000000000..0702ef29c --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/constraints/AgentPolicy.java @@ -0,0 +1,165 @@ +// --- 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.cms.policy.constraints; + + +import java.util.*; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.request.IPolicy; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.AgentApprovals; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.apps.CMS; +import netscape.security.x509.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * AgentPolicy is an enrollment policy wraps another policy module. + * Requests are sent first to the contained module, but if the + * policy indicates that the request should be deferred, a check + * for agent approvals is done. If any are found, the request + * is approved. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class AgentPolicy extends APolicyRule + implements IEnrollmentPolicy { + public AgentPolicy() { + NAME = "AgentPolicy"; + DESC = "Agent Approval Policy"; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries may be of the form: + * + * ra.Policy.rule..implName=AgentPolicy + * ra.Policy.rule..enable=true + * ra.Policy.rule..predicate= ou == engineering AND o == netscape.com + * ra.Policy.rule..class=xxxx + * ra.Policy.rule..params.* + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EPolicyException { + + // Create subordinate object + String className = (String) config.get("class"); + + System.err.println("Creating agent policy with class " + className); + if (className != null) { + IConfigStore substore = config.getSubStore("params"); + + try { + Class c = Class.forName(className); + + Object o = c.newInstance(); + + if (!(o instanceof APolicyRule)) { + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_INVALID_POLICY_CLASS", + getInstanceName(), className)); + } + + APolicyRule pr = (APolicyRule) o; + + pr.init(owner, substore); + mPolicy = pr; + } catch (EPolicyException e) { + System.err.println("Agent Policy Error: " + e); + throw e; + } catch (Exception e) { + System.err.println("Agent Policy Error: " + e); + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_LOADING_POLICY_ERROR", + getInstanceName(), className)); + } + } + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + + // The default is to require manual approval for everything + PolicyResult result = PolicyResult.DEFERRED; + + // Give the underlying object a chance + if (mPolicy != null) { + result = mPolicy.apply(req); + System.err.println("Subordinate policy returns " + result); + } + + if (result == PolicyResult.DEFERRED) { + System.err.println("Checking agent approvals"); + // Try to find an agent approval + AgentApprovals aa = AgentApprovals.fromStringVector( + req.getExtDataInStringVector(AgentApprovals.class.getName())); + + //Object o = req.get("agentApprovals"); + + // Any approvals causes success + if (aa != null && aa.elements().hasMoreElements()) //if (o != null) + { + System.err.println("Agent approval found"); + result = PolicyResult.ACCEPTED; + } + } + System.err.println("Agent policy returns " + result); + return result; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + return null; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return null; + } + + APolicyRule mPolicy = null; +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/constraints/AttributePresentConstraints.java b/pki/base/common/src/com/netscape/cms/policy/constraints/AttributePresentConstraints.java new file mode 100644 index 000000000..3410c7baa --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/constraints/AttributePresentConstraints.java @@ -0,0 +1,401 @@ +// --- 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.cms.policy.constraints; + + +import java.io.File; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.ldap.*; +import com.netscape.certsrv.request.*; +import com.netscape.certsrv.authority.*; +import com.netscape.certsrv.notification.*; +import java.security.*; +import java.security.cert.*; +import java.io.IOException; +import java.util.*; +import netscape.security.x509.*; +import netscape.ldap.*; +import com.netscape.certsrv.common.*; +import java.text.DateFormat; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.apps.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * This checks if attribute present. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class AttributePresentConstraints extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + protected static final String PROP_ENABLED = "enabled"; + protected static final String PROP_LDAP = "ldap"; + + protected String mName = null; + protected String mImplName = null; + + private boolean mEnabled = false; + private ILogger mLogger = CMS.getLogger(); + private Hashtable mContentParams = new Hashtable(); + + private ICertAuthority mSub = null; + private IConfigStore mConfig = null; + private IConfigStore mLdapConfig = null; + private RequestId mReqId = null; + private ILdapConnFactory mConnFactory = null; + private LDAPConnection mCheckAttrLdapConnection = null; + + public AttributePresentConstraints() { + DESC = "Rejects request if ldap attribute is not present in the " + + "directory."; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String params[] = { + PROP_ATTR + ";string,required;Ldap attribute to check presence of (default " + + DEF_ATTR + ")", + PROP_VALUE + ";string;if this parameter is non-empty, the attribute must " + + "match this value for the request to proceed ", + PROP_LDAP_BASE + ";string,required;Base DN to start searching " + + "under. If your user's DN is 'uid=jsmith, o=company', you " + + "might want to use 'o=company' here", + PROP_LDAP_HOST + ";string,required;" + + "LDAP host to connect to", + PROP_LDAP_PORT + ";number,required;" + + "LDAP port number (use 389, or 636 if SSL)", + PROP_LDAP_SSL + ";boolean;" + + "Use SSL to connect to directory?", + PROP_LDAP_VER + ";choice(3,2),required;" + + "LDAP protocol version", + PROP_LDAP_BIND + ";string;DN to bind as for attribute checking. " + + "For example 'CN=Pincheck User'", + PROP_LDAP_PW + ";password;Enter password used to bind as " + + "the above user", + PROP_LDAP_AUTH + ";choice(BasicAuth,SslClientAuth),required;" + + "How to bind to the directory", + PROP_LDAP_CERT + ";string;If you want to use " + + "SSL client auth to the directory, set the client " + + "cert nickname here", + PROP_LDAP_BASE + ";string,required;Base DN to start searching " + + "under. If your user's DN is 'uid=jsmith, o=company', you " + + "might want to use 'o=company' here", + PROP_LDAP_MINC + ";number;number of connections " + + "to keep open to directory server. Default " + DEF_LDAP_MINC, + PROP_LDAP_MAXC + ";number;when needed, connection " + + "pool can grow to this many (multiplexed) connections. Default " + DEF_LDAP_MAXC, + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-pinpresent", + IExtendedPluginInfo.HELP_TEXT + + ";" + DESC + " This plugin can be used to " + + "check the presence (and, optionally, the value) of any LDAP " + + "attribute for the user. " + }; + + return params; + } + + public String getName() { + return mName; + } + + public String getImplName() { + return mImplName; + } + + public IConfigStore getConfigStore() { + return mConfig; + } + + public void shutdown() { + } + + // Parameters + + protected static final String PROP_LDAP_HOST = "ldap.ldapconn.host"; + protected static final String DEF_LDAP_HOST = "localhost"; + + protected static final String PROP_LDAP_PORT = "ldap.ldapconn.port"; + protected static final Integer DEF_LDAP_PORT = Integer.valueOf(389); + + protected static final String PROP_LDAP_SSL = "ldap.ldapconn.secureConn"; + protected static final Boolean DEF_LDAP_SSL = Boolean.FALSE; + + protected static final String PROP_LDAP_VER = "ldap.ldapconn.version"; + protected static final Integer DEF_LDAP_VER = Integer.valueOf(3); + + protected static final String PROP_LDAP_BIND = "ldap.ldapauth.bindDN"; + protected static final String DEF_LDAP_BIND = "CN=Directory Manager"; + + protected static final String PROP_LDAP_PW = "ldap.ldapauth.bindPWPrompt"; + protected static final String DEF_LDAP_PW = ""; + + protected static final String PROP_LDAP_CERT = "ldap.ldapauth.clientCertNickname"; + protected static final String DEF_LDAP_CERT = ""; + + protected static final String PROP_LDAP_AUTH = "ldap.ldapauth.authtype"; + protected static final String DEF_LDAP_AUTH = "BasicAuth"; + + protected static final String PROP_LDAP_BASE = "ldap.ldapconn.basedn"; + protected static final String DEF_LDAP_BASE = ""; + + protected static final String PROP_LDAP_MINC = "ldap.ldapconn.minConns"; + protected static final Integer DEF_LDAP_MINC = Integer.valueOf(1); + + protected static final String PROP_LDAP_MAXC = "ldap.ldapconn.maxConns"; + protected static final Integer DEF_LDAP_MAXC = Integer.valueOf(5); + + protected static final String PROP_ATTR = "attribute"; + protected static final String DEF_ATTR = "pin"; + + protected static final String PROP_VALUE = "value"; + protected static final String DEF_VALUE = ""; + + protected static Vector mParamNames; + protected static Hashtable mParamDefault; + protected Hashtable mParamValue = null; + + static { + mParamNames = new Vector(); + mParamDefault = new Hashtable(); + addParam(PROP_LDAP_HOST, DEF_LDAP_HOST); + addParam(PROP_LDAP_PORT, DEF_LDAP_PORT); + addParam(PROP_LDAP_SSL, DEF_LDAP_SSL); + addParam(PROP_LDAP_VER, DEF_LDAP_VER); + addParam(PROP_LDAP_BIND, DEF_LDAP_BIND); + addParam(PROP_LDAP_PW, DEF_LDAP_PW); + addParam(PROP_LDAP_CERT, DEF_LDAP_CERT); + addParam(PROP_LDAP_AUTH, DEF_LDAP_AUTH); + addParam(PROP_LDAP_BASE, DEF_LDAP_BASE); + addParam(PROP_LDAP_MINC, DEF_LDAP_MINC); + addParam(PROP_LDAP_MAXC, DEF_LDAP_MAXC); + addParam(PROP_ATTR, DEF_ATTR); + addParam(PROP_VALUE, DEF_VALUE); + }; + + protected static void addParam(String name, Object value) { + mParamNames.addElement(name); + mParamDefault.put(name, value); + } + + protected void getStringConfigParam(IConfigStore config, String paramName) { + try { + mParamValue.put( + paramName, config.getString(paramName, (String) mParamDefault.get(paramName)) + ); + } catch (Exception e) { + } + } + + protected void getIntConfigParam(IConfigStore config, String paramName) { + try { + mParamValue.put( + paramName, Integer.valueOf( + config.getInteger(paramName, + ((Integer) mParamDefault.get(paramName)).intValue() + ) + ) + ); + } catch (Exception e) { + } + } + + protected void getBooleanConfigParam(IConfigStore config, String paramName) { + try { + mParamValue.put( + paramName, Boolean.valueOf( + config.getBoolean(paramName, + ((Boolean) mParamDefault.get(paramName)).booleanValue() + ) + ) + ); + } catch (Exception e) { + } + } + + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + + mParamValue = new Hashtable(); + + getStringConfigParam(mConfig, PROP_LDAP_HOST); + getIntConfigParam(mConfig, PROP_LDAP_PORT); + getBooleanConfigParam(mConfig, PROP_LDAP_SSL); + getIntConfigParam(mConfig, PROP_LDAP_VER); + getStringConfigParam(mConfig, PROP_LDAP_BIND); + getStringConfigParam(mConfig, PROP_LDAP_PW); + getStringConfigParam(mConfig, PROP_LDAP_CERT); + getStringConfigParam(mConfig, PROP_LDAP_AUTH); + getStringConfigParam(mConfig, PROP_LDAP_BASE); + getIntConfigParam(mConfig, PROP_LDAP_MINC); + getIntConfigParam(mConfig, PROP_LDAP_MAXC); + getStringConfigParam(mConfig, PROP_ATTR); + getStringConfigParam(mConfig, PROP_VALUE); + + mLdapConfig = mConfig.getSubStore(PROP_LDAP); + + mConnFactory = CMS.getLdapBoundConnFactory(); + mConnFactory.init(mLdapConfig); + mCheckAttrLdapConnection = mConnFactory.getConn(); + + } + + public PolicyResult apply(IRequest r) { + PolicyResult res = PolicyResult.ACCEPTED; + + mReqId = r.getRequestId(); + + String requestType = r.getRequestType(); + + if (requestType.equals(IRequest.ENROLLMENT_REQUEST) || + requestType.equals(IRequest.RENEWAL_REQUEST)) { + + String uid = r.getExtDataInString(IRequest.HTTP_PARAMS, "uid"); + + if (uid == null) { + log(ILogger.LL_INFO, "did not find UID parameter in request " + r.getRequestId()); + setError(r, CMS.getUserMessage("CMS_POLICY_PIN_UNAUTHORIZED"), ""); + return PolicyResult.REJECTED; + } + + String userdn = null; + + try { + String[] attrs = { (String) mParamValue.get(PROP_ATTR) }; + LDAPSearchResults searchResult = + mCheckAttrLdapConnection.search((String) mParamValue.get(PROP_LDAP_BASE), + LDAPv2.SCOPE_SUB, "(uid=" + uid + ")", attrs, false); + + if (!searchResult.hasMoreElements()) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMS_AUTH_NO_PIN_FOUND", uid)); + setError(r, CMS.getUserMessage("CMS_POLICY_PIN_UNAUTHORIZED"), ""); + return PolicyResult.REJECTED; + } + + LDAPEntry entry = (LDAPEntry) searchResult.nextElement(); + + userdn = entry.getDN(); + + LDAPAttribute attr = entry.getAttribute((String) mParamValue.get(PROP_ATTR)); + + /* if attribute not present, reject the request */ + if (attr == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMS_AUTH_NO_PIN_FOUND", userdn)); + setError(r, CMS.getUserMessage("CMS_POLICY_PIN_UNAUTHORIZED"), ""); + return PolicyResult.REJECTED; + } + String acceptedValue = ((String) mParamValue.get(PROP_VALUE)); + + if (!acceptedValue.equals("")) { + int matches = 0; + + String[] values = attr.getStringValueArray(); + + for (int i = 0; i < values.length; i++) { + if (values[i].equals(acceptedValue)) { + matches++; + } + } + if (matches == 0) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMS_AUTH_NO_PIN_FOUND", userdn)); + setError(r, CMS.getUserMessage("CMS_POLICY_PIN_UNAUTHORIZED"), ""); + return PolicyResult.REJECTED; + } + } + + CMS.debug("AttributePresentConstraints: Attribute is present for user: \"" + userdn + "\""); + + } catch (LDAPException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_PIN_UNAUTHORIZED")); + setError(r, CMS.getUserMessage("CMS_POLICY_PIN_UNAUTHORIZED"), ""); + return PolicyResult.REJECTED; + } + + } + return res; + } + + public Vector getInstanceParams() { + Vector params = new Vector(); + + Enumeration e = mParamNames.elements(); + + while (e.hasMoreElements()) { + try { + String paramName = (String) e.nextElement(); + String paramValue = mParamValue.get(paramName).toString(); + String temp = paramName + "=" + paramValue; + + params.addElement(temp); + } catch (Exception ex) { + } + } + + return params; + } + + public Vector getDefaultParams() { + Vector params = new Vector(); + + Enumeration e = mParamNames.elements(); + + while (e.hasMoreElements()) { + try { + String paramName = (String) e.nextElement(); + String paramValue = mParamDefault.get(paramName).toString(); + String temp = paramName + "=" + paramValue; + + params.addElement(temp); + } catch (Exception ex) { + } + } + + return params; + + /* + params.addElement("ldap.ldapconn.host=localhost"); + params.addElement("ldap.ldapconn.port=389"); + params.addElement("ldap.ldapconn.secureConn=false"); + params.addElement("ldap.ldapconn.version=3"); + params.addElement("ldap.ldapauth.bindDN=CN=Directory Manager"); + params.addElement("ldap.ldapauth.bindPWPrompt="); + params.addElement("ldap.ldapauth.clientCertNickname="); + params.addElement("ldap.ldapauth.authtype=BasicAuth"); + params.addElement("ldap.basedn="); + params.addElement("ldap.minConns=1"); + params.addElement("ldap.maxConns=5"); + */ + } + + protected void log(int level, String msg) { + if (mLogger == null) return; + + mLogger.log(ILogger.EV_SYSTEM, null, ILogger.S_OTHER, + level, "AttributePresentConstraints: " + msg); + } + +} diff --git a/pki/base/common/src/com/netscape/cms/policy/constraints/DSAKeyConstraints.java b/pki/base/common/src/com/netscape/cms/policy/constraints/DSAKeyConstraints.java new file mode 100644 index 000000000..4623826f0 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/constraints/DSAKeyConstraints.java @@ -0,0 +1,249 @@ +// --- 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.cms.policy.constraints; + + +import java.util.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.apps.CMS; +import netscape.security.x509.*; +import netscape.security.util.*; +import netscape.security.provider.DSAPublicKey; +import java.security.interfaces.DSAParams; +import java.math.BigInteger; +import com.netscape.cms.policy.APolicyRule; + + +/** + * DSAKeyConstraints policy enforces min and max size of the key. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class DSAKeyConstraints extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + private int mMinSize; + private int mMaxSize; + + private final static int INCREMENT = 64; + private final static int DEF_MIN_SIZE = 512; + private final static int DEF_MAX_SIZE = 1024; + + private final static String DSA = "DSA"; + private final static String PROP_MIN_SIZE = "minSize"; + private final static String PROP_MAX_SIZE = "maxSize"; + + private final static Vector defConfParams = new Vector(); + + private IConfigStore mConfig = null; + + static { + defConfParams.addElement(PROP_MIN_SIZE + "=" + DEF_MIN_SIZE); + defConfParams.addElement(PROP_MAX_SIZE + "=" + DEF_MAX_SIZE); + } + + public DSAKeyConstraints() { + NAME = "DSAKeyConstraints"; + DESC = "Enforces DSA Key Constraints."; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_MIN_SIZE + ";number;Minimum key size", + PROP_MAX_SIZE + ";number;Maximum key size", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-dsakeyconstraints", + IExtendedPluginInfo.HELP_TEXT + + ";Rejects request if DSA key size is out of range" + }; + + return params; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries probably are of the form + * ra.Policy.rule..implName=DSAKeyConstraints + * ra.Policy.rule..enable=true + * ra.Policy.rule..minSize=512 + * ra.Policy.rule..maxSize=1024 + * ra.Policy.rule..predicate= ou == engineering AND o == netscape.com + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EPolicyException { + + // Get Min and Max sizes + mConfig = config; + + try { + mMinSize = config.getInteger(PROP_MIN_SIZE, DEF_MIN_SIZE); + mMaxSize = config.getInteger(PROP_MAX_SIZE, DEF_MAX_SIZE); + + if (mMaxSize > DEF_MAX_SIZE) { + String msg = "cannot be more than " + DEF_MAX_SIZE; + + log(ILogger.LL_FAILURE, PROP_MAX_SIZE + " " + msg); + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + PROP_MAX_SIZE, msg)); + } + if (mMinSize < DEF_MIN_SIZE) { + String msg = "cannot be less than " + DEF_MIN_SIZE; + + log(ILogger.LL_FAILURE, PROP_MIN_SIZE + " " + msg); + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + PROP_MIN_SIZE, msg)); + } + if (mMaxSize % INCREMENT != 0) { + String msg = "must be in increments of " + INCREMENT; + + log(ILogger.LL_FAILURE, PROP_MAX_SIZE + " " + msg); + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + PROP_MIN_SIZE, msg)); + } + if (mMaxSize % INCREMENT != 0) { + String msg = "must be in increments of " + INCREMENT; + + log(ILogger.LL_FAILURE, PROP_MIN_SIZE + " " + msg); + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + PROP_MIN_SIZE, msg)); + } + + config.putInteger(PROP_MIN_SIZE, mMinSize); + config.putInteger(PROP_MAX_SIZE, mMaxSize); + + } catch (Exception e) { + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_INVALID_POLICY_CONFIG", getInstanceName(), e.toString())); + } + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + + PolicyResult result = PolicyResult.ACCEPTED; + + try { + // Get the certificate info from the request + X509CertInfo ci[] = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + // There should be a certificate info set. + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO", NAME), ""); + return PolicyResult.REJECTED; + } + + // Else check if the key size(s) are within the limit. + for (int i = 0; i < ci.length; i++) { + CertificateX509Key certKey = (CertificateX509Key) + ci[i].get(X509CertInfo.KEY); + X509Key key = (X509Key) certKey.get(CertificateX509Key.KEY); + String alg = key.getAlgorithmId().toString(); + + if (!alg.equalsIgnoreCase(DSA)) + continue; + + // Check DSAKey parameters. + // size refers to the p parameter. + DSAPublicKey dsaKey = new DSAPublicKey(key.getEncoded()); + DSAParams keyParams = dsaKey.getParams(); + + if (keyParams == null) { + // key parameters could not be parsed. + Object[] params = new Object[] { + getInstanceName(), String.valueOf(i + 1) }; + + setError(req, CMS.getUserMessage("CMS_POLICY_NO_KEY_PARAMS", getInstanceName(), String.valueOf(i + 1)), ""); + return PolicyResult.REJECTED; + } + BigInteger p = keyParams.getP(); + int len = p.bitLength(); + + if (len < mMinSize || len > mMaxSize || + (len % INCREMENT) != 0) { + String[] parms = new String[] { + getInstanceName(), + String.valueOf(len), + String.valueOf(mMinSize), + String.valueOf(mMaxSize), + String.valueOf(INCREMENT) }; + + setError(req, CMS.getUserMessage("CMS_POLICY_KEY_SIZE_VIOLATION_1", parms), ""); + return PolicyResult.REJECTED; + } + } + } catch (Exception e) { + // e.printStackTrace(); + String[] params = { getInstanceName(), e.toString()}; + + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", params), ""); + result = PolicyResult.REJECTED; + } + return result; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector confParams = new Vector(); + + try { + confParams.addElement(PROP_MIN_SIZE + "=" + mConfig.getInteger(PROP_MIN_SIZE, DEF_MIN_SIZE)); + confParams.addElement(PROP_MAX_SIZE + "=" + mConfig.getInteger(PROP_MAX_SIZE, DEF_MAX_SIZE)); + } catch (EBaseException e) {; + } + return confParams; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return defConfParams; + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/constraints/DefaultRevocation.java b/pki/base/common/src/com/netscape/cms/policy/constraints/DefaultRevocation.java new file mode 100644 index 000000000..8fca9a2fa --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/constraints/DefaultRevocation.java @@ -0,0 +1,105 @@ +// --- 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.cms.policy.constraints; + + +import java.util.*; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import netscape.security.x509.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * This is the default revocation policy. Currently this does + * nothing. We can later add checks like whether or not to + * revoke expired certs ..etc here. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class DefaultRevocation extends APolicyRule + implements IRevocationPolicy, IExtendedPluginInfo { + public DefaultRevocation() { + NAME = "DefaultRevocation"; + DESC = "Default Revocation Policy"; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries may be of the form: + * + * ra.Policy.rule..implName=DefaultRevocation + * ra.Policy.rule..enable=true + * ra.Policy.rule..predicate= ou == engineering AND o == netscape.com + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EPolicyException { + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + return PolicyResult.ACCEPTED; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + return null; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return null; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + IExtendedPluginInfo.HELP_TOKEN + ";configuration-policyrules-defaultrevocation" + }; + + return params; + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/constraints/IssuerConstraints.java b/pki/base/common/src/com/netscape/cms/policy/constraints/IssuerConstraints.java new file mode 100644 index 000000000..5746a3b21 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/constraints/IssuerConstraints.java @@ -0,0 +1,207 @@ +// --- 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.cms.policy.constraints; + + +import java.util.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.apps.*; +import netscape.security.x509.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * IssuerConstraints is a rule for restricting the issuers of the + * certificates used for certificate-based enrollments. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$ $Date$ + */ +public class IssuerConstraints extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + private final static String PROP_ISSUER_DN = "issuerDN"; + private static final String CLIENT_ISSUER = "clientIssuer"; + private X500Name mIssuerDN = null; + private String mIssuerDNString; + + /** + * checks the issuer of the ssl client-auth cert. Only one issuer + * is allowed for now + */ + public IssuerConstraints() { + NAME = "IssuerConstraints"; + DESC = "Checks to see if the Issuer is one allowed"; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_ISSUER_DN + ";string;Subject DN of the Issuer. The IssuerDN of the authenticating cert must match what's specified here", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-issuerconstraints", + IExtendedPluginInfo.HELP_TEXT + + ";Rejects the request if the issuer in the certificate is" + + "not of the one specified" + }; + + return params; + + } + + /** + * Initializes this policy rule. + *

+ * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EPolicyException { + try { + mIssuerDNString = config.getString(PROP_ISSUER_DN, null); + if ((mIssuerDNString != null) && + !mIssuerDNString.equals("")) { + mIssuerDN = new X500Name(mIssuerDNString); + } + } catch (Exception e) { + log(ILogger.LL_FAILURE, + NAME + CMS.getLogMessage("CA_GET_ISSUER_NAME_FAILED")); + + String[] params = {getInstanceName(), e.toString()}; + + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_INVALID_POLICY_CONFIG", params)); + } + CMS.debug( + NAME + ": init() done"); + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + PolicyResult result = PolicyResult.ACCEPTED; + + if (mIssuerDN == null) + return result; + + try { + String clientIssuerDN = req.getExtDataInString(CLIENT_ISSUER); + + if (clientIssuerDN != null) { + X500Name ci_name = new X500Name(clientIssuerDN); + + if (!ci_name.equals(mIssuerDN)) { + setError(req, + CMS.getUserMessage("CMS_POLICY_INVALID_ISSUER", + getInstanceName()), ""); + result = PolicyResult.REJECTED; + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CA_GET_ISSUER_NAME_FAILED")); + CMS.debug( + NAME + ": apply() - issuerDN mismatch: client issuerDN = " + clientIssuerDN + "; expected issuerDN = " + mIssuerDNString); + } + } else { + + // Get the certificate info from the request + X509CertInfo certInfo[] = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (certInfo == null) { + log(ILogger.LL_FAILURE, + NAME + ": apply() - missing certInfo"); + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO", + getInstanceName()), ""); + return PolicyResult.REJECTED; + } + + for (int i = 0; i < certInfo.length; i++) { + String oldIssuer = (String) + certInfo[i].get(X509CertInfo.ISSUER).toString(); + + if (oldIssuer == null) { + setError(req, + CMS.getUserMessage("CMS_POLICY_CLIENT_ISSUER_NOT_FOUND", + getInstanceName()), ""); + result = PolicyResult.REJECTED; + log(ILogger.LL_FAILURE, + NAME + ": apply() - client issuerDN not found"); + } + X500Name oi_name = new X500Name(oldIssuer); + + if (!oi_name.equals(mIssuerDN)) { + setError(req, + CMS.getUserMessage("CMS_POLICY_INVALID_ISSUER", + getInstanceName()), ""); + result = PolicyResult.REJECTED; + log(ILogger.LL_FAILURE, + NAME + ": apply() - cert issuerDN mismatch: client issuerDN = " + oldIssuer + "; expected issuerDN = " + mIssuerDNString); + } + } + } + } catch (Exception e) { + String params[] = {getInstanceName(), e.toString()}; + + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", params), ""); + result = PolicyResult.REJECTED; + } + + if (result.equals(PolicyResult.ACCEPTED)) { + log(ILogger.LL_INFO, + NAME + ": apply() - accepted"); + } + return result; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector confParams = new Vector(); + + confParams.addElement(PROP_ISSUER_DN + "=" + + mIssuerDNString); + return confParams; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + Vector defParams = new Vector(); + + defParams.addElement(PROP_ISSUER_DN + "="); + return defParams; + } + +} diff --git a/pki/base/common/src/com/netscape/cms/policy/constraints/KeyAlgorithmConstraints.java b/pki/base/common/src/com/netscape/cms/policy/constraints/KeyAlgorithmConstraints.java new file mode 100644 index 000000000..181752b01 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/constraints/KeyAlgorithmConstraints.java @@ -0,0 +1,221 @@ +// --- 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.cms.policy.constraints; + + +import java.util.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.common.*; +import netscape.security.x509.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * KeyAlgorithmConstraints enforces a constraint that the RA or a CA + * honor only the keys generated using one of the permitted algorithms + * such as RSA, DSA or DH. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class KeyAlgorithmConstraints extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + private Vector mAlgorithms; + private final static String DEF_KEY_ALGORITHM = "RSA,DSA"; + private final static String PROP_ALGORITHMS = "algorithms"; + private final static String[] supportedAlgorithms = + {"RSA", "DSA", "DH" }; + + private final static Vector defConfParams = new Vector(); + + static { + defConfParams.addElement(PROP_ALGORITHMS + "=" + + DEF_KEY_ALGORITHM); + } + + public String[] getExtendedPluginInfo(Locale locale) { + String params[] = { + "algorithms;choice(RSA\\,DSA,RSA,DSA);Certificate's key can be one of these algorithms", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-keyalgorithmconstraints", + IExtendedPluginInfo.HELP_TEXT + + ";Rejects the request if the key in the certificate is " + + "not of the type specified" + }; + + return params; + } + + public KeyAlgorithmConstraints() { + NAME = "KeyAlgorithmConstraints"; + DESC = "Enforces Key Algorithm Constraints."; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries probably are of the form + * ra.Policy.rule..implName=KeyAlgorithmConstraints + * ra.Policy.rule..algorithms=RSA,DSA + * ra.Policy.rule..enable=true + * ra.Policy.rule..predicate=ou==Sales + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EPolicyException { + + mAlgorithms = new Vector(); + + if (config == null || config.size() == 0) { + mAlgorithms.addElement(DEF_KEY_ALGORITHM); + return; + } + + // Get Algorithm names + String algNames = null; + + try { + algNames = config.getString(PROP_ALGORITHMS, null); + } catch (Exception e) { + String[] params = {getInstanceName(), e.toString()}; + + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_INVALID_POLICY_CONFIG", params)); + } + + if (algNames == null) { + mAlgorithms.addElement(DEF_KEY_ALGORITHM); + return; + } + StringTokenizer tok = new StringTokenizer(algNames, ","); + + while (tok.hasMoreTokens()) { + String alg = tok.nextToken().trim().toUpperCase(); + + if (alg.length() == 0) + continue; + mAlgorithms.addElement(alg); + } + + // Check if configured algorithms are supported. + for (Enumeration e = mAlgorithms.elements(); + e.hasMoreElements();) { + int i; + String configuredAlg = (String) e.nextElement(); + + // See if it is a supported algorithm. + for (i = 0; i < supportedAlgorithms.length; i++) { + if (configuredAlg.equals(supportedAlgorithms[i])) + break; + } + + // Did we not find it? + if (i == supportedAlgorithms.length) + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_UNSUPPORTED_KEY_ALG", + getInstanceName(), configuredAlg)); + } + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + + PolicyResult result = PolicyResult.ACCEPTED; + + try { + // Get the certificate info from the request + // X509CertInfo certInfo[] = (X509CertInfo[]) + // req.get(IRequest.CERT_INFO); + X509CertInfo certInfo[] = req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + // We need to have a certificate info set + if (certInfo == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO", + getInstanceName()), ""); + return PolicyResult.REJECTED; + } + + // Else check if the key algorithm is supported. + for (int i = 0; i < certInfo.length; i++) { + CertificateX509Key certKey = (CertificateX509Key) + certInfo[i].get(X509CertInfo.KEY); + X509Key key = (X509Key) certKey.get(CertificateX509Key.KEY); + String alg = key.getAlgorithmId().getName().toUpperCase(); + + if (!mAlgorithms.contains(alg)) { + setError(req, CMS.getUserMessage("CMS_POLICY_KEY_ALG_VIOLATION", + getInstanceName(), alg), ""); + result = PolicyResult.REJECTED; + } + } + } catch (Exception e) { + String params[] = {getInstanceName(), e.toString()}; + + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", + params), ""); + result = PolicyResult.REJECTED; + } + return result; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector v = new Vector(); + StringBuffer sb = new StringBuffer(); + + for (Enumeration e = mAlgorithms.elements(); e.hasMoreElements();) { + sb.append((String) e.nextElement()); + sb.append(","); + } + if (sb.length() > 0) + sb.setLength(sb.length() - 1); + v.addElement(PROP_ALGORITHMS + "=" + sb.toString()); + return v; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return defConfParams; + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/constraints/ManualAuthentication.java b/pki/base/common/src/com/netscape/cms/policy/constraints/ManualAuthentication.java new file mode 100644 index 000000000..d88bb3c02 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/constraints/ManualAuthentication.java @@ -0,0 +1,103 @@ +// --- 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.cms.policy.constraints; + + +import java.util.*; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import netscape.security.x509.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * ManualAuthentication is an enrollment policy that queues + * all requests for issuing agent's approval if no authentication + * is present. The policy rejects a request if any of the auth tokens + * indicates authentication failure. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class ManualAuthentication extends APolicyRule + implements IEnrollmentPolicy { + public ManualAuthentication() { + NAME = "ManualAuthentication"; + DESC = "Manual Authentication Policy"; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries may be of the form: + * + * ra.Policy.rule..implName=ManualAuthentication + * ra.Policy.rule..enable=true + * ra.Policy.rule..predicate= ou == engineering AND o == netscape.com + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EPolicyException { + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + IAuthToken authToken = req.getExtDataInAuthToken(IRequest.AUTH_TOKEN); + + if (authToken == null) + return deferred(req); + + return PolicyResult.ACCEPTED; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + return null; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return null; + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/constraints/RSAKeyConstraints.java b/pki/base/common/src/com/netscape/cms/policy/constraints/RSAKeyConstraints.java new file mode 100644 index 000000000..b30e27901 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/constraints/RSAKeyConstraints.java @@ -0,0 +1,274 @@ +// --- 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.cms.policy.constraints; + + +import java.util.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.common.*; +import netscape.security.x509.*; +import netscape.security.util.*; +import netscape.security.provider.RSAPublicKey; +import com.netscape.cms.policy.APolicyRule; + + +/** + * RSAKeyConstraints policy enforces min and max size of the key. + * Optionally checks the exponents. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class RSAKeyConstraints extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + private Vector mExponents; + private int mMinSize; + private int mMaxSize; + + private final static int DEF_MIN_SIZE = 512; + private final static int DEF_MAX_SIZE = 2048; + private final static String PROP_MIN_SIZE = "minSize"; + private final static String PROP_MAX_SIZE = "maxSize"; + private final static String PROP_EXPONENTS = "exponents"; + private final static String RSA = "RSA"; + + private final static Vector defConfParams = new Vector(); + + static { + defConfParams.addElement(PROP_MIN_SIZE + "=" + DEF_MIN_SIZE); + defConfParams.addElement(PROP_MAX_SIZE + "=" + DEF_MAX_SIZE); + defConfParams.addElement(PROP_EXPONENTS + "=" + " "); + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_MIN_SIZE + ";number;Minimum size of user's RSA key (bits)", + PROP_MAX_SIZE + ";number;Maximum size of user's RSA key (bits)", + PROP_EXPONENTS + ";string;Comma-separated list of permissible exponents", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-rsakeyconstraints", + IExtendedPluginInfo.HELP_TEXT + + ";Reject request if RSA key length is not within the " + + "specified constraints" + }; + + return params; + } + + public RSAKeyConstraints() { + NAME = "RSAKeyConstraints"; + DESC = "Enforces RSA Key Constraints."; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries probably are of the form: + * + * ra.Policy.rule..implName=RSAKeyConstraints + * ra.Policy.rule..enable=true + * ra.Policy.rule..minSize=512 + * ra.Policy.rule..maxSize=2048 + * ra.Policy.rule..predicate=ou==Marketing + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + + if (config == null || config.size() == 0) + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_MISSING_POLICY_CONFIG", + getInstanceName())); + String exponents = null; + + // Get Min and Max sizes + mMinSize = config.getInteger(PROP_MIN_SIZE, DEF_MIN_SIZE); + mMaxSize = config.getInteger(PROP_MAX_SIZE, DEF_MAX_SIZE); + + if (mMinSize <= 0) + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_MUST_BE_POSITIVE_NUMBER", PROP_MIN_SIZE)); + if (mMaxSize <= 0) + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_MUST_BE_POSITIVE_NUMBER", PROP_MAX_SIZE)); + + if (mMinSize > mMaxSize) + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_A_GREATER_THAN_EQUAL_B", PROP_MIN_SIZE, PROP_MAX_SIZE)); + + mExponents = new Vector(); + + // Get exponents + exponents = config.getString(PROP_EXPONENTS, null); + + if (exponents != null) { + StringTokenizer tok = new StringTokenizer(exponents, ","); + + try { + while (tok.hasMoreTokens()) { + String exp = tok.nextToken().trim(); + + mExponents.addElement(new BigInt(Integer.parseInt(exp))); + } + } catch (Exception e) { + // e.printStackTrace(); + String[] params = {getInstanceName(), exponents, + PROP_EXPONENTS}; + + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_INVALID_CONFIG_PARAM", params)); + } + } + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + + PolicyResult result = PolicyResult.ACCEPTED; + + try { + // Get the certificate info from the request + X509CertInfo certInfo[] = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + // There should be a certificate info set. + if (certInfo == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO", + getInstanceName()), ""); + return PolicyResult.REJECTED; + } + + // Else check if the key size(s) are within the limit. + for (int i = 0; i < certInfo.length; i++) { + CertificateX509Key certKey = (CertificateX509Key) + certInfo[i].get(X509CertInfo.KEY); + X509Key key = (X509Key) certKey.get(CertificateX509Key.KEY); + String alg = key.getAlgorithmId().toString(); + + if (!alg.equalsIgnoreCase(RSA)) + continue; + X509Key newkey = null; + + try { + newkey = new X509Key(AlgorithmId.get("RSA"), + key.getKey()); + } catch (Exception e) { + CMS.debug( "RSAKeyConstraints::apply() - " + + "Exception="+e.toString() ); + setError( req, + CMS.getUserMessage( "CMS_POLICY_KEY_SIZE_VIOLATION", + getInstanceName() ), + "" ); + return PolicyResult.REJECTED; + } + RSAPublicKey rsaKey = new RSAPublicKey(newkey.getEncoded()); + int keySize = rsaKey.getKeySize(); + + if (keySize < mMinSize || keySize > mMaxSize) { + String[] params = {getInstanceName(), + String.valueOf(keySize), + String.valueOf(mMinSize), + String.valueOf(mMaxSize)}; + + setError(req, CMS.getUserMessage("CMS_POLICY_KEY_SIZE_VIOLATION", + params), ""); + result = PolicyResult.REJECTED; + } + + // If the exponents are configured, see if the key's + // exponent is a configured one. + if (mExponents.size() > 0) { + BigInt exp = rsaKey.getPublicExponent(); + + if (!mExponents.contains(exp)) { + StringBuffer sb = new StringBuffer(); + + for (Enumeration e = mExponents.elements(); + e.hasMoreElements();) { + BigInt bi = (BigInt) e.nextElement(); + + sb.append(bi.toBigInteger().toString()); + sb.append(" "); + } + String[] params = {getInstanceName(), + exp.toBigInteger().toString(), new String(sb)}; + + setError(req, CMS.getUserMessage("CMS_POLICY_EXPONENT_VIOLATION", params), ""); + result = PolicyResult.REJECTED; + } + } + } + } catch (Exception e) { + // e.printStackTrace(); + String params[] = {getInstanceName(), e.toString()}; + + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", params), ""); + result = PolicyResult.REJECTED; + } + return result; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector confParams = new Vector(); + + confParams.addElement(PROP_MIN_SIZE + "=" + mMinSize); + confParams.addElement(PROP_MAX_SIZE + "=" + mMaxSize); + StringBuffer sb = new StringBuffer(); + + for (Enumeration e = mExponents.elements(); e.hasMoreElements();) { + sb.append(((BigInt) e.nextElement()).toInt()); + sb.append(","); + } + if (sb.length() > 0) + sb.setLength(sb.length() - 1); + confParams.addElement(PROP_EXPONENTS + "=" + sb.toString()); + return confParams; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return defConfParams; + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/constraints/RenewalConstraints.java b/pki/base/common/src/com/netscape/cms/policy/constraints/RenewalConstraints.java new file mode 100644 index 000000000..5cadafa17 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/constraints/RenewalConstraints.java @@ -0,0 +1,235 @@ +// --- 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.cms.policy.constraints; + + +import java.io.*; + +import java.util.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.common.*; +import netscape.security.x509.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Whether to allow renewal of an expired cert. + * @version $Revision$, $Date$ + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class RenewalConstraints extends APolicyRule + implements IRenewalPolicy, IExtendedPluginInfo { + + private static final String PROP_ALLOW_EXPIRED_CERTS = "allowExpiredCerts"; + private static final String PROP_RENEWAL_NOT_AFTER = "renewalNotAfter"; + + private boolean mAllowExpiredCerts = true; + private long mRenewalNotAfter = 0; + + public final static int DEF_RENEWAL_NOT_AFTER = 30; + public final static long DAYS_TO_MS_FACTOR = 24L * 3600 * 1000; + + private final static Vector defConfParams = new Vector(); + static { + defConfParams.addElement(PROP_ALLOW_EXPIRED_CERTS + "=" + true); + defConfParams.addElement(PROP_RENEWAL_NOT_AFTER + "=" + + DEF_RENEWAL_NOT_AFTER); + } + + public RenewalConstraints() { + NAME = "RenewalConstraints"; + DESC = "Whether to allow renewal of expired certs."; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_ALLOW_EXPIRED_CERTS + ";boolean;Allow a user to renew an already-expired certificate", + PROP_RENEWAL_NOT_AFTER + ";number;Number of days since certificate expiry after which renewal request would be rejected", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-renewalconstraints", + IExtendedPluginInfo.HELP_TEXT + + ";Permit administrator to decide policy on whether to " + + "permit renewals for already-expired certificates" + }; + + return params; + + } + + /** + * Initializes this policy rule. + *

+ * + * The entries probably are of the form: + * + * ra.Policy.rule..implName=ValidityConstraints + * ra.Policy.rule..enable=true + * ra.Policy.rule..allowExpiredCerts=true + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EPolicyException { + // Get min and max validity in days and configure them. + try { + mAllowExpiredCerts = + config.getBoolean(PROP_ALLOW_EXPIRED_CERTS, true); + String val = config.getString(PROP_RENEWAL_NOT_AFTER, null); + + if (val == null) + mRenewalNotAfter = DEF_RENEWAL_NOT_AFTER * DAYS_TO_MS_FACTOR; + else { + mRenewalNotAfter = Long.parseLong(val) * DAYS_TO_MS_FACTOR; + } + + } catch (EBaseException e) { + // never happen. + } + + CMS.debug("RenewalConstraints: allow expired certs " + mAllowExpiredCerts); + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + PolicyResult result = PolicyResult.ACCEPTED; + + try { + // Get the certificates being renwed. + X509CertImpl[] oldCerts = + req.getExtDataInCertArray(IRequest.OLD_CERTS); + + if (oldCerts == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_OLD_CERT", + getInstanceName()), ""); + return PolicyResult.REJECTED; + } + + if (mAllowExpiredCerts) { + CMS.debug("checking validity of each cert"); + // check if each cert to be renewed is expired for more than // allowed days. + for (int i = 0; i < oldCerts.length; i++) { + X509CertInfo oldCertInfo = (X509CertInfo) + oldCerts[i].get(X509CertImpl.NAME + "." + + X509CertImpl.INFO); + CertificateValidity oldValidity = (CertificateValidity) + oldCertInfo.get(X509CertInfo.VALIDITY); + Date notAfter = (Date) + oldValidity.get(CertificateValidity.NOT_AFTER); + + // Is the Certificate eligible for renewal ? + + Date now = CMS.getCurrentDate(); + + Date renewedNotAfter = new Date(notAfter.getTime() + + mRenewalNotAfter); + + CMS.debug("RenewalConstraints: cert " + i + " renewedNotAfter " + renewedNotAfter + " now=" + now); + + if (renewedNotAfter.before(now)) { + CMS.debug( + "One or more certificates is expired for more than " + (mRenewalNotAfter / DAYS_TO_MS_FACTOR) + " days"); + String params[] = { getInstanceName(), Long.toString(mRenewalNotAfter / DAYS_TO_MS_FACTOR) }; + + setError(req, + CMS.getUserMessage("CMS_POLICY_CANNOT_RENEW_EXPIRED_CERTS_AFTER_ALLOWED_PERIOD", + params), ""); + return PolicyResult.REJECTED; + } + } + return PolicyResult.ACCEPTED; + } + + CMS.debug("RenewalConstraints: checking validity of each cert"); + // check if each cert to be renewed is expired. + for (int i = 0; i < oldCerts.length; i++) { + X509CertInfo oldCertInfo = (X509CertInfo) + oldCerts[i].get( + X509CertImpl.NAME + "." + X509CertImpl.INFO); + CertificateValidity oldValidity = (CertificateValidity) + oldCertInfo.get(X509CertInfo.VALIDITY); + Date notAfter = (Date) + oldValidity.get(CertificateValidity.NOT_AFTER); + + // Is the Certificate still valid? + Date now = CMS.getCurrentDate(); + + CMS.debug("RenewalConstraints: cert " + i + " notAfter " + notAfter + " now=" + now); + if (notAfter.before(now)) { + CMS.debug( + "RenewalConstraints: One or more certificates is expired."); + String params[] = { getInstanceName() }; + + setError(req, + CMS.getUserMessage("CMS_POLICY_CANNOT_RENEW_EXPIRED_CERTS", + params), ""); + result = PolicyResult.REJECTED; + break; + } + } + + } catch (Exception e) { + String params[] = {getInstanceName(), e.toString()}; + + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", params), ""); + result = PolicyResult.REJECTED; + } + return result; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector confParams = new Vector(); + + confParams.addElement( + PROP_ALLOW_EXPIRED_CERTS + "=" + mAllowExpiredCerts); + confParams.addElement(PROP_RENEWAL_NOT_AFTER + "=" + + mRenewalNotAfter / DAYS_TO_MS_FACTOR); + return confParams; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return defConfParams; + } +} diff --git a/pki/base/common/src/com/netscape/cms/policy/constraints/RenewalValidityConstraints.java b/pki/base/common/src/com/netscape/cms/policy/constraints/RenewalValidityConstraints.java new file mode 100644 index 000000000..60f294e36 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/constraints/RenewalValidityConstraints.java @@ -0,0 +1,342 @@ +// --- 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.cms.policy.constraints; + + +import java.util.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.common.*; +import netscape.security.x509.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * RenewalValidityConstraints is a default rule for Certificate + * Renewal. This policy enforces the no of days before which a + * currently active certificate can be renewed and sets new validity + * period for the renewed certificate starting from the the ending + * period in the old certificate. + * + * The main parameters are: + * + * The renewal leadtime in days: - i.e how many days before the + * expiry of the current certificate can one request the renewal. + * min and max validity duration. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class RenewalValidityConstraints extends APolicyRule + implements IRenewalPolicy, IExtendedPluginInfo { + private long mMinValidity; + private long mMaxValidity; + private long mRenewalInterval; + + private final static String PROP_MIN_VALIDITY = "minValidity"; + private final static String PROP_MAX_VALIDITY = "maxValidity"; + private final static String PROP_RENEWAL_INTERVAL = "renewalInterval"; + public final static int DEF_MIN_VALIDITY = 180; + public final static int DEF_MAX_VALIDITY = 730; + public final static long DEF_RENEWAL_INTERVAL = 15; + public final static long DAYS_TO_MS_FACTOR = 24L * 3600 * 1000; + public static final String CERT_HEADER = "-----BEGIN CERTIFICATE-----\n"; + public static final String CERT_TRAILER = "-----END CERTIFICATE-----\n"; + + private final static Vector defConfParams = new Vector(); + + static { + defConfParams.addElement(PROP_MIN_VALIDITY + "=" + + DEF_MIN_VALIDITY); + defConfParams.addElement(PROP_MAX_VALIDITY + "=" + + DEF_MAX_VALIDITY); + defConfParams.addElement(PROP_RENEWAL_INTERVAL + "=" + + DEF_RENEWAL_INTERVAL); + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_MIN_VALIDITY + ";number;Specifies the minimum validity period, in days, for renewed certificates.", + PROP_MAX_VALIDITY + ";number;Specifies the maximum validity period, in days, for renewed certificates.", + PROP_RENEWAL_INTERVAL + ";number;Specifies how many days before its expiration that a certificate can be renewed.", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-renewalvalidityconstraints", + IExtendedPluginInfo.HELP_TEXT + + ";Reject renewal request if the certificate is too far " + + "before it's expiry date" + }; + + return params; + + } + + public RenewalValidityConstraints() { + NAME = "RenewalValidityConstraints"; + DESC = "Enforces minimum and maximum validity and renewal interval for certificate renewal."; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries probably are of the form: + * + * ra.Policy.rule..implName=ValidityConstraints + * ra.Policy.rule..enable=true + * ra.Policy.rule..minValidity=30 + * ra.Policy.rule..maxValidity=180 + * ra.Policy.rule..renewalInterval=15 + * ra.Policy.rule..predicate=ou==Sales + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EPolicyException { + + // Get min and max validity in days and onfigure them. + try { + String val = config.getString(PROP_MIN_VALIDITY, null); + + if (val == null) + mMinValidity = DEF_MIN_VALIDITY * DAYS_TO_MS_FACTOR; + else + mMinValidity = Long.parseLong(val) * DAYS_TO_MS_FACTOR; + + val = config.getString(PROP_MAX_VALIDITY, null); + if (val == null) + mMaxValidity = DEF_MAX_VALIDITY * DAYS_TO_MS_FACTOR; + else { + mMaxValidity = Long.parseLong(val) * DAYS_TO_MS_FACTOR; + } + val = config.getString(PROP_RENEWAL_INTERVAL, null); + if (val == null) + mRenewalInterval = DEF_RENEWAL_INTERVAL * DAYS_TO_MS_FACTOR; + else { + mRenewalInterval = Long.parseLong(val) * DAYS_TO_MS_FACTOR; + } + + // minValidity can't be bigger than maxValidity. + if (mMinValidity > mMaxValidity) { + String params[] = {getInstanceName(), + String.valueOf(mMinValidity / DAYS_TO_MS_FACTOR), + String.valueOf(mMaxValidity / DAYS_TO_MS_FACTOR) }; + + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_INVALID_RENEWAL_MIN_MAX", params)); + } + + // Renewal interval can't be more than maxValidity. + if (mRenewalInterval > mMaxValidity) { + String params[] = {getInstanceName(), + String.valueOf(mRenewalInterval / DAYS_TO_MS_FACTOR), + String.valueOf(mMaxValidity / DAYS_TO_MS_FACTOR) }; + + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_INVALID_RENEWAL_INTERVAL", params)); + } + } catch (Exception e) { + // e.printStackTrace(); + String[] params = {getInstanceName(), e.toString()}; + + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_INVALID_POLICY_CONFIG", params)); + } + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + + PolicyResult result = PolicyResult.ACCEPTED; + + if (agentApproved(req)) + return result; + + try { + // Get the certificate info from the request + X509CertInfo certInfo[] = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + // Get the certificates being renwed. + X509CertImpl currentCerts[] = + req.getExtDataInCertArray(IRequest.OLD_CERTS); + + // Both certificate info and current certs should be set + if (certInfo == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO", + getInstanceName()), ""); + return PolicyResult.REJECTED; + } + if (currentCerts == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_OLD_CERT", + getInstanceName()), ""); + return PolicyResult.REJECTED; + } + if (certInfo.length != currentCerts.length) { + setError(req, CMS.getUserMessage("CMS_POLICY_MISMATCHED_CERTINFO", + getInstanceName()), ""); + return PolicyResult.REJECTED; + } + + // Else check if the renewal interval is okay and then + // set the validity. + for (int i = 0; i < certInfo.length; i++) { + X509CertInfo oldCertInfo = (X509CertInfo) + currentCerts[i].get(X509CertImpl.NAME + + "." + X509CertImpl.INFO); + CertificateValidity oldValidity = (CertificateValidity) + oldCertInfo.get(X509CertInfo.VALIDITY); + Date notAfter = (Date) + oldValidity.get(CertificateValidity.NOT_AFTER); + + // Is the Certificate still valid? + Date now = CMS.getCurrentDate(); + + if (notAfter.after(now)) { + // Check if the renewal interval is alright. + long interval = notAfter.getTime() - now.getTime(); + + if (interval > mRenewalInterval) { + setError(req, + CMS.getUserMessage("CMS_POLICY_LONG_RENEWAL_LEAD_TIME", + getInstanceName(), + String.valueOf(mRenewalInterval / DAYS_TO_MS_FACTOR)), ""); + setError(req, + CMS.getUserMessage("CMS_POLICY_EXISTING_CERT_DETAILS", + getInstanceName(), + getCertDetails(req, currentCerts[i])), ""); + + result = PolicyResult.REJECTED; + setDummyValidity(certInfo[i]); + continue; + } + } + + // Else compute new validity. + Date renewedNotBef = notAfter; + Date renewedNotAfter = new Date(notAfter.getTime() + + mMaxValidity); + + // If the new notAfter is within renewal interval days from + // today or already expired, set the notBefore to today. + if (renewedNotAfter.before(now) || + (renewedNotAfter.getTime() - now.getTime()) <= + mRenewalInterval) { + renewedNotBef = now; + renewedNotAfter = new Date(now.getTime() + + mMaxValidity); + } + CertificateValidity newValidity = + new CertificateValidity(renewedNotBef, renewedNotAfter); + + certInfo[i].set(X509CertInfo.VALIDITY, newValidity); + } + } catch (Exception e) { + String params[] = {getInstanceName(), e.toString()}; + + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", params), ""); + result = PolicyResult.REJECTED; + } + return result; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector confParams = new Vector(); + + confParams.addElement(PROP_MIN_VALIDITY + "=" + + mMinValidity / DAYS_TO_MS_FACTOR); + confParams.addElement(PROP_MAX_VALIDITY + "=" + + mMaxValidity / DAYS_TO_MS_FACTOR); + confParams.addElement(PROP_RENEWAL_INTERVAL + "=" + + mRenewalInterval / DAYS_TO_MS_FACTOR); + return confParams; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return defConfParams; + } + + // Set dummy validity field so the request will serialize properly + private void setDummyValidity(X509CertInfo certInfo) { + try { + certInfo.set(X509CertInfo.VALIDITY, + new CertificateValidity(CMS.getCurrentDate(), new Date())); + } catch (Exception e) { + } + } + + private String getCertDetails(IRequest req, X509CertImpl cert) { + StringBuffer sb = new StringBuffer(); + + sb.append("\n"); + sb.append("Serial No: " + cert.getSerialNumber().toString(16)); + sb.append("\n"); + sb.append("Validity: " + cert.getNotBefore().toString() + + " - " + cert.getNotAfter().toString()); + sb.append("\n"); + String certType = req.getExtDataInString(IRequest.CERT_TYPE); + + if (certType == null) + certType = IRequest.SERVER_CERT; + if (certType.equals(IRequest.CLIENT_CERT)) { + + /*** Take this our - URL formulation hard to do here. + sb.append("Use the following url with your CA/RA gateway spec to download the certificate."); + sb.append("\n"); + sb.append("/query/certImport?op=displayByserial&serialNumber="); + sb.append(cert.getSerialNumber().toString(16)); + ***/ + sb.append("\n"); + } else { + sb.append("Certificate Content is as follows:"); + sb.append("\n"); + try { + byte[] ba = cert.getEncoded(); + String encodedCert = com.netscape.osutil.OSUtil.BtoA(ba); + + sb.append(CERT_HEADER + encodedCert + CERT_TRAILER); + } catch (Exception e) { + //throw new AssertionException(e.toString()); + } + } + return sb.toString(); + } +} diff --git a/pki/base/common/src/com/netscape/cms/policy/constraints/RevocationConstraints.java b/pki/base/common/src/com/netscape/cms/policy/constraints/RevocationConstraints.java new file mode 100644 index 000000000..1afb9cbba --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/constraints/RevocationConstraints.java @@ -0,0 +1,208 @@ +// --- 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.cms.policy.constraints; + + +import java.util.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.common.*; +import netscape.security.x509.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Whether to allow revocation of an expired cert. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class RevocationConstraints extends APolicyRule + implements IRevocationPolicy, IExtendedPluginInfo { + private static final String PROP_ALLOW_EXPIRED_CERTS = "allowExpiredCerts"; + private static final String PROP_ALLOW_ON_HOLD = "allowOnHold"; + + private boolean mAllowExpiredCerts = true; + private boolean mAllowOnHold = true; + + private final static Vector defConfParams = new Vector(); + static { + defConfParams.addElement(PROP_ALLOW_EXPIRED_CERTS + "=" + true); + defConfParams.addElement(PROP_ALLOW_ON_HOLD + "=" + true); + } + + public RevocationConstraints() { + NAME = "RevocationConstraints"; + DESC = "Whether to allow revocation of expired certs and on-hold."; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_ALLOW_EXPIRED_CERTS + ";boolean;Allow a user to revoke an already-expired certificate", + PROP_ALLOW_ON_HOLD + ";boolean;Allow a user to set reason to On-Hold", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-revocationconstraints", + IExtendedPluginInfo.HELP_TEXT + + ";Allow administrator to decide policy on whether to allow " + + "recovation of expired certificates" + + "and set reason to On-Hold" + + }; + + return params; + + } + + /** + * Initializes this policy rule. + *

+ * + * The entries probably are of the form: + * + * ra.Policy.rule..implName=ValidityConstraints + * ra.Policy.rule..enable=true + * ra.Policy.rule..allowExpiredCerts=true + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EPolicyException { + // Get min and max validity in days and onfigure them. + try { + mAllowExpiredCerts = + config.getBoolean(PROP_ALLOW_EXPIRED_CERTS, true); + mAllowOnHold = + config.getBoolean(PROP_ALLOW_ON_HOLD, true); + } catch (EBaseException e) { + // never happen. + } + + CMS.debug("RevocationConstraints: allow expired certs " + mAllowExpiredCerts); + CMS.debug("RevocationConstraints: allow on hold " + mAllowOnHold); + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + CMS.debug("RevocationConstraints: apply begins"); + if (req.getExtDataInInteger(IRequest.REVOKED_REASON) == null) { + CMS.debug("RevocationConstraints: apply: no revocationReason found in request"); + return PolicyResult.REJECTED; + } + RevocationReason rr = RevocationReason.fromInt( + req.getExtDataInInteger(IRequest.REVOKED_REASON).intValue()); + + if (!mAllowOnHold && (rr != null)) { + int reason = rr.toInt(); + + if (reason == RevocationReason.CERTIFICATE_HOLD.toInt()) { + String params[] = { getInstanceName() }; + + setError(req, CMS.getUserMessage("CMS_POLICY_NO_ON_HOLD_ALLOWED", params), ""); + return PolicyResult.REJECTED; + } + } + + if (mAllowExpiredCerts) + // nothing to check. + return PolicyResult.ACCEPTED; + + PolicyResult result = PolicyResult.ACCEPTED; + + try { + // Get the certificates being renwed. + X509CertImpl[] oldCerts = + req.getExtDataInCertArray(IRequest.OLD_CERTS); + + if (oldCerts == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_OLD_CERT"), + getInstanceName()); + return PolicyResult.REJECTED; + } + + // check if each cert to be renewed is expired. + for (int i = 0; i < oldCerts.length; i++) { + X509CertInfo oldCertInfo = (X509CertInfo) + oldCerts[i].get( + X509CertImpl.NAME + "." + X509CertImpl.INFO); + CertificateValidity oldValidity = (CertificateValidity) + oldCertInfo.get(X509CertInfo.VALIDITY); + Date notAfter = (Date) + oldValidity.get(CertificateValidity.NOT_AFTER); + + // Is the Certificate still valid? + Date now = CMS.getCurrentDate(); + + if (notAfter.before(now)) { + String params[] = { getInstanceName() }; + + setError(req, + CMS.getUserMessage("CMS_POLICY_CANNOT_REVOKE_EXPIRED_CERTS", + params), ""); + result = PolicyResult.REJECTED; + break; + } + } + + } catch (Exception e) { + String params[] = {getInstanceName(), e.toString()}; + + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", params), ""); + result = PolicyResult.REJECTED; + } + return result; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector confParams = new Vector(); + + confParams.addElement( + PROP_ALLOW_EXPIRED_CERTS + "=" + mAllowExpiredCerts); + confParams.addElement( + PROP_ALLOW_ON_HOLD + "=" + mAllowOnHold); + return confParams; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return defConfParams; + } +} diff --git a/pki/base/common/src/com/netscape/cms/policy/constraints/SigningAlgorithmConstraints.java b/pki/base/common/src/com/netscape/cms/policy/constraints/SigningAlgorithmConstraints.java new file mode 100644 index 000000000..be9870935 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/constraints/SigningAlgorithmConstraints.java @@ -0,0 +1,442 @@ +// --- 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.cms.policy.constraints; + + +import java.util.*; +import java.io.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authority.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.apps.CMS; +import netscape.security.x509.*; +import com.netscape.certsrv.ca.*; +import netscape.security.extensions.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * SigningAlgorithmConstraints enforces that only a supported + * signing algorithm be requested. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class SigningAlgorithmConstraints extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + private String[] mAllowedAlgs = null; // algs allowed by this policy + static String[] mDefaultAllowedAlgs = null; // default algs allowed by this policy based on CA's key + private String[] mConfigAlgs = null; // algs listed in config file + private boolean winnowedByKey = false; + IAuthority mAuthority = null; + private final static String PROP_ALGORITHMS = "algorithms"; + + private final static Vector defConfParams = new Vector(); + + static { + StringBuffer sb = new StringBuffer(); + sb.append(PROP_ALGORITHMS); + sb.append("="); + int i = 0; + boolean first = true; + + mDefaultAllowedAlgs = new String[AlgorithmId.ALL_SIGNING_ALGORITHMS.length]; + for (i = 0; i < AlgorithmId.ALL_SIGNING_ALGORITHMS.length; i++) { + mDefaultAllowedAlgs[i] = AlgorithmId.ALL_SIGNING_ALGORITHMS[i]; + if (first == true) { + sb.append(AlgorithmId.ALL_SIGNING_ALGORITHMS[i]); + first = false; + } else { + sb.append(","); + sb.append(AlgorithmId.ALL_SIGNING_ALGORITHMS[i]); + } + } + defConfParams.addElement(sb.toString()); + } + + public SigningAlgorithmConstraints() { + NAME = "SigningAlgorithmConstraints"; + DESC = "Enforces Signing Algorithm Constraints."; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries probably are of the form + * ra.Policy.rule..implName=SigningAlgorithmConstraints + * ra.Policy.rule..algorithms=SHA-1WithRSA, SHA-1WithDSA + * ra.Policy.rule..enable=true + * ra.Policy.rule..predicate=ou==Sales + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mAuthority = (IAuthority) ((IPolicyProcessor) owner).getAuthority(); + + // Get allowed algorithms from config file + if (config != null) { + String algNames = null; + + try { + algNames = config.getString(PROP_ALGORITHMS, null); + } catch (Exception e) { + String[] params = {getInstanceName(), e.toString(), PROP_ALGORITHMS}; + + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_PARAM_CONFIG_ERROR", params)); + } + + if (algNames != null) { + // parse alg names into Vector + StringTokenizer tok = new StringTokenizer(algNames, ","); + Vector algs = new Vector(); + + while (tok.hasMoreTokens()) { + algs.addElement(tok.nextToken().trim()); + } + + // convert to array for speedy traversals during apply() + int itemCount = algs.size(); + + mAllowedAlgs = new String[itemCount]; + for (int i = 0; i < itemCount; i++) { + mAllowedAlgs[i] = (String) algs.elementAt(i); + } + + } + + } + + // these are the algorithms from the config file + mConfigAlgs = mAllowedAlgs; + if (mConfigAlgs == null) { + mConfigAlgs = new String[0]; + } + + if (mAllowedAlgs != null) { + // winnow out unknown algorithms + winnowAlgs(AlgorithmId.ALL_SIGNING_ALGORITHMS, + "CMS_POLICY_UNKNOWN_SIGNING_ALG", true); + } else { + // if nothing was in the config file, allow all known algs + mAllowedAlgs = AlgorithmId.ALL_SIGNING_ALGORITHMS; + } + + // winnow out algorithms that don't make sense for the key + winnowByKey(); + + if (mAllowedAlgs.length == 0) { + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_SIGNALG_NOT_MATCH_CAKEY", NAME)); + } + + } + + /** + * winnow out algorithms that don't make sense for the CA's key + */ + private synchronized void winnowByKey() throws EBaseException { + // only do this successfully once + if (winnowedByKey) { + return; + } + + // don't do this ever for DRM + if (!(mAuthority instanceof ICertAuthority)) { + winnowedByKey = true; + return; + } + + // get list of algorithms allowed for the key + String[] allowedByKey = + ((ICertAuthority) mAuthority).getCASigningAlgorithms(); + + if (allowedByKey != null) { + // don't show algorithms that don't match CA's key in UI. + mDefaultAllowedAlgs = new String[allowedByKey.length]; + for (int i = 0; i < allowedByKey.length; i++) + mDefaultAllowedAlgs[i] = allowedByKey[i]; + // winnow out algorithms that don't match CA's signing key + winnowAlgs(allowedByKey, + "CMS_POLICY_SIGNALG_NOT_MATCH_CAKEY_1", false); + winnowedByKey = true; + } else { + // We don't know the CA's signing algorithms. Maybe we're + // an RA that hasn't talked to the CA yet? Try again later. + } + } + + /** + * Winnows out of mAllowedAlgorithms those algorithms that aren't allowed + * for some reason. + * + * @param allowed An array of allowed algorithms. Only algorithms in this + * list will survive the winnowing process. + * @param reason A string describing the problem with an algorithm + * that is not allowed by this list. Must be a predefined string in PolicyResources. + */ + private void winnowAlgs(String[] allowed, String reason, boolean isError) + throws EBaseException { + int i, j, goodSize; + + // validate the currently-allowed algorithms + Vector goodAlgs = new Vector(); + + for (i = 0; i < mAllowedAlgs.length; i++) { + for (j = 0; j < allowed.length; j++) { + if (mAllowedAlgs[i].equals(allowed[j])) { + goodAlgs.addElement(mAllowedAlgs[i]); + break; + } + } + // if algorithm is not allowed, log a warning + if (j == allowed.length) { + EPolicyException e = new EPolicyException(CMS.getUserMessage(reason, NAME, mAllowedAlgs[i])); + + if (isError) { + log(ILogger.LL_FAILURE, e.toString()); + throw new EPolicyException(CMS.getUserMessage(reason, + NAME, mAllowedAlgs[i])); + } else { + log(ILogger.LL_WARN, e.toString()); + } + } + } + + // convert back into an array + goodSize = goodAlgs.size(); + if (mAllowedAlgs.length != goodSize) { + mAllowedAlgs = new String[ goodSize ]; + for (i = 0; i < goodSize; i++) { + mAllowedAlgs[i] = (String) goodAlgs.elementAt(i); + } + } + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + int i, j; + + PolicyResult result = PolicyResult.ACCEPTED; + + try { + + // Get the certificate info from the request + //X509CertInfo certInfo[] = (X509CertInfo[]) + // req.get(IRequest.CERT_INFO); + X509CertInfo certInfo[] = req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + // We need to have a certificate info set + if (certInfo == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO", + getInstanceName()), ""); + return PolicyResult.REJECTED; + } + + // Else check if the key algorithm is supported. + for (i = 0; i < certInfo.length; i++) { + // make sure our list of allowed algorithms makes + // sense for our key. Do this each time. + if (!winnowedByKey) { + winnowByKey(); + } + + CertificateAlgorithmId certAlgId = (CertificateAlgorithmId) + certInfo[i].get(X509CertInfo.ALGORITHM_ID); + + AlgorithmId algId = (AlgorithmId) + certAlgId.get(CertificateAlgorithmId.ALGORITHM); + String alg = algId.getName(); + + // test against the list of allowed algorithms + for (j = 0; j < mAllowedAlgs.length; j++) { + if (mAllowedAlgs[j].equals(alg)) { + break; + } + } + if (j == mAllowedAlgs.length) { + // if the algor doesn't match the CA's key replace + // it with one that does. + if (mAllowedAlgs[0].equals("SHA1withDSA") || + alg.equals("SHA1withDSA")) { + certInfo[i].set(X509CertInfo.ALGORITHM_ID, + new CertificateAlgorithmId( + AlgorithmId.get(mAllowedAlgs[0]))); + return PolicyResult.ACCEPTED; + } + + // didn't find a match, alg not allowed + setError(req, CMS.getUserMessage("CMS_POLICY_SIGNING_ALG_VIOLATION", + getInstanceName(), alg), ""); + result = PolicyResult.REJECTED; + } + } + } catch (Exception e) { + // e.printStackTrace(); + String params[] = {getInstanceName(), e.toString()}; + + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", + params), ""); + result = PolicyResult.REJECTED; + } + return result; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector confParams = new Vector(); + StringBuffer sb = new StringBuffer(); + + for (int i = 0; i < mConfigAlgs.length; i++) { + sb.append(mConfigAlgs[i]); + sb.append(","); + } + if (sb.length() > 0) + sb.setLength(sb.length() - 1); + confParams.addElement(PROP_ALGORITHMS + "=" + sb.toString()); + return confParams; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + StringBuffer sb = new StringBuffer(); + sb.append(PROP_ALGORITHMS); + sb.append("="); + boolean first = true; + + defConfParams.removeAllElements(); + + for (int i = 0; i < mDefaultAllowedAlgs.length; i++) { + if (first == true) { + sb.append(mDefaultAllowedAlgs[i]); + first = false; + } else { + sb.append(","); + sb.append(mDefaultAllowedAlgs[i]); + } + } + defConfParams.addElement(sb.toString()); + + return defConfParams; + } + + public String[] getExtendedPluginInfo(Locale locale) { + if (!winnowedByKey) { + try { + winnowByKey(); + } catch (Exception e) { + } + } + + String[] params = null; + + String[] params_BOTH = { + PROP_ALGORITHMS + ";" + "choice(MD2withRSA\\,MD5withRSA\\,SHA1withRSA\\,SHA256withRSA\\,SHA512withRSA\\,SHA1withDSA," + + "MD2withRSA\\,MD5withRSA\\,SHA1withRSA\\,SHA1withDSA,"+ + "MD2withRSA\\,MD5withRSA\\,SHA1withRSA," + + "MD2withRSA\\,SHA1withRSA\\,SHA1withDSA," + + "MD5withRSA\\,SHA1withRSA\\,SHA1withDSA," + + "MD2withRSA\\,MD5withRSA\\,SHA1withDSA," + + "MD2withRSA\\,MD5withRSA," + + "MD2withRSA\\,SHA1withRSA," + + "MD2withRSA\\,SHA1withDSA," + + "MD5withRSA\\,SHA1withRSA," + + "MD5withRSA\\,SHA1withDSA," + + "SHA1withRSA\\,SHA1withDSA," + + "MD2withRSA," + + "MD5withRSA," + + "SHA1withRSA," + + "SHA1withDSA);List of algorithms to restrict the requested signing algorithm " + + "to be one of the algorithms supported by Certificate System", + IExtendedPluginInfo.HELP_TOKEN + ";configuration-policyrules-signingalgconstraints", + IExtendedPluginInfo.HELP_TEXT + + ";Restricts the requested signing algorithm to be one of" + + " the algorithms supported by Certificate System" + }; + + String[] params_RSA = { + PROP_ALGORITHMS + ";" + "choice(MD2withRSA\\,MD5withRSA\\,SHA1withRSA," + + "MD2withRSA\\,MD5withRSA," + + "MD2withRSA\\,SHA1withRSA," + + "MD5withRSA\\,SHA1withRSA," + + "MD2withRSA," + + "MD5withRSA," + + "SHA1withRSA);Restrict the requested signing algorithm to be " + + "one of the algorithms supported by Certificate System", + IExtendedPluginInfo.HELP_TOKEN + ";configuration-policyrules-signingalgconstraints", + IExtendedPluginInfo.HELP_TEXT + + ";Restricts the requested signing algorithm to be one of" + + " the algorithms supported by Certificate System" + }; + + String[] params_DSA = { + PROP_ALGORITHMS + ";" + "choice(SHA1withDSA);Restrict the requested signing " + + "algorithm to be one of the algorithms supported by Certificate " + + "System", + IExtendedPluginInfo.HELP_TOKEN + ";configuration-policyrules-signingalgconstraints", + IExtendedPluginInfo.HELP_TEXT + + ";Restricts the requested signing algorithm to be one of" + + " the algorithms supported by Certificate System" + }; + + switch (mDefaultAllowedAlgs.length) { + case 1: + params = params_DSA; + break; + + case 3: + params = params_RSA; + break; + + case 4: + default: + params = params_BOTH; + break; + + } + + return params; + } + +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/constraints/SubCANameConstraints.java b/pki/base/common/src/com/netscape/cms/policy/constraints/SubCANameConstraints.java new file mode 100644 index 000000000..dffde5806 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/constraints/SubCANameConstraints.java @@ -0,0 +1,189 @@ +// --- 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.cms.policy.constraints; + + +import org.mozilla.jss.crypto.*; +import java.util.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.ca.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.security.*; +import com.netscape.certsrv.authority.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.apps.*; +import netscape.security.x509.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * This simple policy checks the subordinate CA CSR to see + * if it is the same as the local CA. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class SubCANameConstraints extends APolicyRule implements IEnrollmentPolicy, IExtendedPluginInfo { + public ICertificateAuthority mCA = null; + public String mIssuerNameStr = null; + + public SubCANameConstraints() { + NAME = "SubCANameConstraints"; + DESC = "Enforces Subordinate CA name."; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-subcanamecheck", + IExtendedPluginInfo.HELP_TEXT + + ";Checks if subordinate CA request matches the local CA. There are no parameters to change" + }; + + return params; + + } + + /** + * Initializes this policy rule. + *

+ * + * The entries probably are of the form + * ra.Policy.rule..implName=KeyAlgorithmConstraints + * ra.Policy.rule..algorithms=RSA,DSA + * ra.Policy.rule..enable=true + * ra.Policy.rule..predicate=ou==Sales + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + // get CA's public key to create authority key id. + ICertAuthority certAuthority = (ICertAuthority) + ((IPolicyProcessor) owner).getAuthority(); + + if (certAuthority == null) { + // should never get here. + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CANT_FIND_MANAGER")); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", + "Cannot find the Certificate Manager")); + } + if (!(certAuthority instanceof ICertificateAuthority)) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CANT_FIND_MANAGER")); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", + "Cannot find the Certificate Manager")); + } + mCA = (ICertificateAuthority) certAuthority; + ISigningUnit su = mCA.getSigningUnit(); + if( su == null || CMS.isPreOpMode() ) { + return; + } + + X509CertImpl cert = su.getCertImpl(); + + if (cert == null) + return; + X500Name issuerName = (X500Name) cert.getSubjectDN(); + + if (issuerName == null) + return; + mIssuerNameStr = issuerName.toString(); + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + PolicyResult result = PolicyResult.ACCEPTED; + + try { + + // Get the certificate templates + X509CertInfo[] certInfos = req.getExtDataInCertInfoArray( + IRequest.CERT_INFO); + + if (certInfos == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_NO_CERT_INFO", getInstanceName())); + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO", NAME + ":" + getInstanceName()), ""); + return PolicyResult.REJECTED; + } + + // retrieve the subject name and check its unqiueness + for (int i = 0; i < certInfos.length; i++) { + CertificateSubjectName subName = (CertificateSubjectName) certInfos[i].get(X509CertInfo.SUBJECT); + + // if there is no name set, set one here. + if (subName == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_NO_SUBJECT_NAME_1", getInstanceName())); + setError(req, CMS.getUserMessage("CMS_POLICY_NO_SUBJECT_NAME", NAME + ":" + getInstanceName()), ""); + return PolicyResult.REJECTED; + } + String certSubjectName = subName.toString(); + + if (certSubjectName.equalsIgnoreCase(mIssuerNameStr)) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_SUBJECT_NAME_EXIST_1", mIssuerNameStr)); + setError(req, CMS.getUserMessage("CMS_POLICY_SUBJECT_NAME_EXIST", NAME + ":" + "Same As Issuer Name " + mIssuerNameStr), ""); + result = PolicyResult.REJECTED; + } + } + } catch (Exception e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_NO_SUBJECT_NAME_1", getInstanceName())); + String params[] = {getInstanceName(), e.toString()}; + + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", + params), ""); + result = PolicyResult.REJECTED; + } + return result; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector v = new Vector(); + + return v; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + Vector v = new Vector(); + + return v; + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/constraints/UniqueSubjectName.java b/pki/base/common/src/com/netscape/cms/policy/constraints/UniqueSubjectName.java new file mode 100644 index 000000000..a2aeef09d --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/constraints/UniqueSubjectName.java @@ -0,0 +1,47 @@ +// --- 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.cms.policy.constraints; + + +import java.io.*; +import java.util.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.common.*; +import netscape.security.x509.*; +import com.netscape.certsrv.ca.*; +import com.netscape.certsrv.dbs.certdb.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * This class is used to help migrate CMS4.1 to CMS4.2. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class UniqueSubjectName extends UniqueSubjectNameConstraints { +} diff --git a/pki/base/common/src/com/netscape/cms/policy/constraints/UniqueSubjectNameConstraints.java b/pki/base/common/src/com/netscape/cms/policy/constraints/UniqueSubjectNameConstraints.java new file mode 100644 index 000000000..040b5e205 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/constraints/UniqueSubjectNameConstraints.java @@ -0,0 +1,299 @@ +// --- 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.cms.policy.constraints; + + +import java.io.*; +import java.util.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authority.*; +import com.netscape.certsrv.common.*; +import netscape.security.x509.*; +import com.netscape.certsrv.ca.*; +import com.netscape.certsrv.dbs.certdb.*; +import com.netscape.cms.policy.APolicyRule; +import com.netscape.certsrv.apps.*; + + +/** + * Checks the uniqueness of the subject name. This policy + * can only be used (installed) in Certificate Authority + * subsystem. + * + * This policy can perform pre-agent-approval checking or + * post-agent-approval checking based on configuration + * setting. + * + * In some situations, user may want to have 2 certificates with + * the same subject name. For example, one key for encryption, + * and one for signing. This policy does not deal with this case + * directly. But it can be easily extended to do that. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class UniqueSubjectNameConstraints extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + protected static final String PROP_PRE_AGENT_APPROVAL_CHECKING = + "enablePreAgentApprovalChecking"; + protected static final String PROP_KEY_USAGE_EXTENSION_CHECKING = + "enableKeyUsageExtensionChecking"; + + public ICertificateAuthority mCA = null; + + public boolean mPreAgentApprovalChecking = false; + public boolean mKeyUsageExtensionChecking = true; + + public UniqueSubjectNameConstraints() { + NAME = "UniqueSubjectName"; + DESC = "Ensure the uniqueness of the subject name."; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_PRE_AGENT_APPROVAL_CHECKING + ";boolean;If checked, check subject name uniqueness BEFORE agent approves, (else checks AFTER approval)", + PROP_KEY_USAGE_EXTENSION_CHECKING + ";boolean;If checked, allow non-unique subject names if Key Usage Extension differs", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-uniquesubjectname", + IExtendedPluginInfo.HELP_TEXT + + ";Rejects a request if there exists an unrevoked, unexpired " + + "certificate with the same subject name" + }; + + return params; + + } + + /** + * Initializes this policy rule. + *

+ * + * The entries probably are of the form: + * + * ca.Policy.rule..implName=UniqueSubjectName + * ca.Policy.rule..enable=true + * ca.Policy.rule..enable=true + * ca.Policy.rule..enablePreAgentApprovalChecking=true + * ca.Policy.rule..enableKeyUsageExtensionChecking=true + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + // get CA's public key to create authority key id. + ICertAuthority certAuthority = (ICertAuthority) + ((IPolicyProcessor) owner).getAuthority(); + + if (certAuthority == null) { + // should never get here. + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CANT_FIND_MANAGER")); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", "Cannot find the Certificate Manager or Registration Manager")); + } + if (!(certAuthority instanceof ICertificateAuthority)) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CANT_FIND_MANAGER")); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", "Cannot find the Certificate Manager")); + } + + mCA = (ICertificateAuthority) certAuthority; + try { + mPreAgentApprovalChecking = + config.getBoolean(PROP_PRE_AGENT_APPROVAL_CHECKING, false); + } catch (EBaseException e) { + } + try { + mKeyUsageExtensionChecking = + config.getBoolean(PROP_KEY_USAGE_EXTENSION_CHECKING, true); + } catch (EBaseException e) { + } + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + if (!mPreAgentApprovalChecking) { + // post agent approval checking + if (!agentApproved(req)) + return PolicyResult.ACCEPTED; + } + PolicyResult result = PolicyResult.ACCEPTED; + + try { + + // Get the certificate templates + X509CertInfo[] certInfos = req.getExtDataInCertInfoArray( + IRequest.CERT_INFO); + + if (certInfos == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO", + getInstanceName()), ""); + return PolicyResult.REJECTED; + } + + // retrieve the subject name and check its unqiueness + for (int i = 0; i < certInfos.length; i++) { + CertificateSubjectName subName = (CertificateSubjectName) + certInfos[i].get(X509CertInfo.SUBJECT); + + // if there is no name set, set one here. + if (subName == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_SUBJECT_NAME", + getInstanceName()), ""); + return PolicyResult.REJECTED; + } + String certSubjectName = subName.toString(); + String filter = "x509Cert.subject=" + certSubjectName; + // subject name is indexed, so we only use subject name + // in the filter + Enumeration matched = + mCA.getCertificateRepository().findCertRecords(filter); + + while (matched.hasMoreElements()) { + ICertRecord rec = (ICertRecord) matched.nextElement(); + String status = rec.getStatus(); + + if (status.equals(ICertRecord.STATUS_REVOKED) || status.equals(ICertRecord.STATUS_EXPIRED) || status.equals(ICertRecord.STATUS_REVOKED_EXPIRED)) { + // accept this only if we have a REVOKED, + // EXPIRED or REVOKED_EXPIRED certificate + continue; + + } + // you already have an VALID or INVALID (not yet valid) certificate + if (mKeyUsageExtensionChecking && agentApproved(req)) { + // This request is agent approved which + // means all requested extensions are finalized + // to the request, + // We will accept duplicated subject name with + // different keyUsage extension if + // keyUsageExtension is different. + if (!sameKeyUsageExtension(rec, certInfos[i])) { + continue; + } + } + + setError(req, CMS.getUserMessage("CMS_POLICY_SUBJECT_NAME_EXIST", + getInstanceName() + " " + certSubjectName), ""); + return PolicyResult.REJECTED; + } + } + } catch (Exception e) { + String params[] = {getInstanceName(), e.toString()}; + + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", + params), ""); + result = PolicyResult.REJECTED; + } + return result; + } + + /** + * Checks if the key extension in the issued certificate + * is the same as the one in the certificate template. + */ + private boolean sameKeyUsageExtension(ICertRecord rec, + X509CertInfo certInfo) { + X509CertImpl impl = rec.getCertificate(); + boolean bits[] = impl.getKeyUsage(); + + CertificateExtensions extensions = null; + + try { + extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + } catch (IOException e) { + } catch (java.security.cert.CertificateException e) { + } + KeyUsageExtension ext = null; + + if (extensions == null) { + if (bits != null) + return false; + } else { + try { + ext = (KeyUsageExtension) extensions.get( + KeyUsageExtension.NAME); + } catch (IOException e) { + // extension isn't there. + } + + if (ext == null) { + if (bits != null) + return false; + } else { + boolean[] InfoBits = ext.getBits(); + + if (InfoBits == null) { + if (bits != null) + return false; + } else { + if (bits == null) + return false; + if (InfoBits.length != bits.length) { + return false; + } + for (int i = 0; i < InfoBits.length; i++) { + if (InfoBits[i] != bits[i]) + return false; + } + } + } + } + return true; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector confParams = new Vector(); + + confParams.addElement(PROP_PRE_AGENT_APPROVAL_CHECKING + + "=" + mPreAgentApprovalChecking); + confParams.addElement(PROP_KEY_USAGE_EXTENSION_CHECKING + + "=" + mKeyUsageExtensionChecking); + return confParams; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + Vector defParams = new Vector(); + + defParams.addElement(PROP_PRE_AGENT_APPROVAL_CHECKING + "="); + defParams.addElement(PROP_KEY_USAGE_EXTENSION_CHECKING + "="); + return defParams; + } +} diff --git a/pki/base/common/src/com/netscape/cms/policy/constraints/ValidityConstraints.java b/pki/base/common/src/com/netscape/cms/policy/constraints/ValidityConstraints.java new file mode 100644 index 000000000..832d77746 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/constraints/ValidityConstraints.java @@ -0,0 +1,316 @@ +// --- 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.cms.policy.constraints; + + +import java.util.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.common.*; +import netscape.security.x509.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * ValidityConstraints is a default rule for Enrollment and + * Renewal that enforces minimum and maximum validity periods + * and changes them if not met. + * + * Optionally the lead and lag times - i.e how far back into the + * front or back the notBefore date could go in minutes can also + * be specified. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class ValidityConstraints extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + protected long mMinValidity; + protected long mMaxValidity; + protected long mLeadTime; + protected long mLagTime; + protected long mNotBeforeSkew; + + private final static String PROP_MIN_VALIDITY = "minValidity"; + private final static String PROP_MAX_VALIDITY = "maxValidity"; + private final static String PROP_LEAD_TIME = "leadTime"; + private final static String PROP_LAG_TIME = "lagTime"; + private final static String PROP_NOT_BEFORE_SKEW = "notBeforeSkew"; + public final static int DEF_MIN_VALIDITY = 180; + public final static int DEF_MAX_VALIDITY = 730; + public final static int DEF_LEAD_TIME = 10; + public final static int DEF_LAG_TIME = 10; + public final static int DEF_NOT_BEFORE_SKEW = 5; + public final static long DAYS_TO_MS_FACTOR = 24L * 3600 * 1000; + public final static long MINS_TO_MS_FACTOR = 60L * 1000; + + private final static Vector defConfParams = new Vector(); + + static { + defConfParams.addElement(PROP_MIN_VALIDITY + "=" + + DEF_MIN_VALIDITY); + defConfParams.addElement(PROP_MAX_VALIDITY + "=" + + DEF_MAX_VALIDITY); + defConfParams.addElement(PROP_LEAD_TIME + "=" + + DEF_LEAD_TIME); + defConfParams.addElement(PROP_LAG_TIME + "=" + + DEF_LAG_TIME); + defConfParams.addElement(PROP_NOT_BEFORE_SKEW + "=" + + DEF_NOT_BEFORE_SKEW); + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_MIN_VALIDITY + ";number;Minimum Validity time, in days", + PROP_MAX_VALIDITY + ";number;Maximum Validity time, in days", + PROP_LEAD_TIME + ";number;Number of minutes in the future a request's notBefore can be", + PROP_LAG_TIME + ";number;NOT CURRENTLY IN USE", + PROP_NOT_BEFORE_SKEW + ";number;Number of minutes a cert's notBefore should be in the past", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-validityconstraints", + IExtendedPluginInfo.HELP_TEXT + + ";Ensures that the user's requested validity period is " + + "acceptable. If not specified, as is usually the case, " + + "this policy will set the validity. See RFC 2459." + }; + + return params; + + } + + public ValidityConstraints() { + NAME = "ValidityConstraints"; + DESC = "Enforces minimum and maximum validity constraints."; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries probably are of the form: + * + * ra.Policy.rule..implName=ValidityConstraints + * ra.Policy.rule..enable=true + * ra.Policy.rule..minValidity=30 + * ra.Policy.rule..maxValidity=180 + * ra.Policy.rule..predicate=ou==Sales + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EPolicyException { + + // Get min and max validity in days and configure them. + try { + String val = config.getString(PROP_MIN_VALIDITY, null); + + if (val == null) + mMinValidity = DEF_MIN_VALIDITY * DAYS_TO_MS_FACTOR; + else + mMinValidity = Long.parseLong(val) * DAYS_TO_MS_FACTOR; + + val = config.getString(PROP_MAX_VALIDITY, null); + if (val == null) + mMaxValidity = DEF_MAX_VALIDITY * DAYS_TO_MS_FACTOR; + else + mMaxValidity = Long.parseLong(val) * DAYS_TO_MS_FACTOR; + + val = config.getString(PROP_LEAD_TIME, null); + if (val != null) + mLeadTime = Long.parseLong(val) * MINS_TO_MS_FACTOR; + else + mLeadTime = DEF_LEAD_TIME * MINS_TO_MS_FACTOR; + + val = config.getString(PROP_LAG_TIME, null); + if (val != null) + mLagTime = Long.parseLong(val) * MINS_TO_MS_FACTOR; + else + mLagTime = DEF_LAG_TIME * MINS_TO_MS_FACTOR; + + val = config.getString(PROP_NOT_BEFORE_SKEW, null); + if (val != null) + mNotBeforeSkew = Long.parseLong(val) * MINS_TO_MS_FACTOR; + else + mNotBeforeSkew = DEF_NOT_BEFORE_SKEW * MINS_TO_MS_FACTOR; + } catch (Exception e) { + // e.printStackTrace(); + String[] params = {getInstanceName(), e.toString()}; + + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_INVALID_POLICY_CONFIG", params)); + } + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + + PolicyResult result = PolicyResult.ACCEPTED; + + try { + // Get the certificate info from the request + //X509CertInfo certInfo[] = (X509CertInfo[]) + // req.get(IRequest.CERT_INFO); + X509CertInfo certInfo[] = req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + // There should be a certificate info set. + if (certInfo == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO", + getInstanceName()), ""); + return PolicyResult.REJECTED; + } + + // Else check if validity is within the limit + for (int i = 0; i < certInfo.length; i++) { + CertificateValidity validity = (CertificateValidity) + certInfo[i].get(X509CertInfo.VALIDITY); + + Date notBefore = null, notAfter = null; + + if (validity != null) { + notBefore = (Date) + validity.get(CertificateValidity.NOT_BEFORE); + notAfter = (Date) + validity.get(CertificateValidity.NOT_AFTER); + } + + // If no validity is supplied yet, make one. The default + // validity is supposed to pass the following checks, so + // bypass further checking. + // (date = 0 is hack for serialization) + + if (validity == null || + (notBefore.getTime() == 0 && notAfter.getTime() == 0)) { + certInfo[i].set(X509CertInfo.VALIDITY, + makeDefaultValidity(req)); + continue; + } + + Date now = CMS.getCurrentDate(); + + if (notBefore.getTime() > (now.getTime() + mLeadTime)) { + setError(req, CMS.getUserMessage("CMS_POLICY_INVALID_BEGIN_TIME", + getInstanceName()), ""); + result = PolicyResult.REJECTED; + } + if ((notAfter.getTime() - notBefore.getTime()) > + mMaxValidity) { + String params[] = {getInstanceName(), + String.valueOf( + ((notAfter.getTime() - notBefore.getTime()) / DAYS_TO_MS_FACTOR)), + String.valueOf(mMaxValidity / DAYS_TO_MS_FACTOR)}; + + setError(req, CMS.getUserMessage("CMS_POLICY_MORE_THAN_MAX_VALIDITY", params), ""); + result = PolicyResult.REJECTED; + } + if ((notAfter.getTime() - notBefore.getTime()) < + mMinValidity) { + String params[] = {getInstanceName(), + String.valueOf( + ((notAfter.getTime() - notBefore.getTime()) / DAYS_TO_MS_FACTOR)), + String.valueOf(mMinValidity / DAYS_TO_MS_FACTOR)}; + + setError(req, CMS.getUserMessage("CMS_POLICY_LESS_THAN_MIN_VALIDITY", params), ""); + result = PolicyResult.REJECTED; + } + } + } catch (Exception e) { + // e.printStackTrace(); + String params[] = {getInstanceName(), e.toString()}; + + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", + params), ""); + result = PolicyResult.REJECTED; + } + return result; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector confParams = new Vector(); + + confParams.addElement(PROP_MIN_VALIDITY + "=" + + mMinValidity / DAYS_TO_MS_FACTOR); + confParams.addElement(PROP_MAX_VALIDITY + "=" + + mMaxValidity / DAYS_TO_MS_FACTOR); + confParams.addElement(PROP_LEAD_TIME + "=" + + mLeadTime / MINS_TO_MS_FACTOR); + confParams.addElement(PROP_LAG_TIME + "=" + + mLagTime / MINS_TO_MS_FACTOR); + confParams.addElement(PROP_NOT_BEFORE_SKEW + "=" + + mNotBeforeSkew / MINS_TO_MS_FACTOR); + return confParams; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return defConfParams; + } + + /** + * Create a default validity value for a request + * + * This code can be easily overridden in a derived class, if the + * calculations here aren't accepatble. + * + * TODO: it might be good to base this calculation on the creation + * time of the request. + */ + protected CertificateValidity makeDefaultValidity(IRequest req) { + long now = roundTimeToSecond((CMS.getCurrentDate()).getTime()); + + // We will set the max duration as the default validity. + long notBeforeTime = now - mNotBeforeSkew; + Date notBefore = new Date(notBeforeTime); + Date notAfter = new Date(notBeforeTime + mMaxValidity); + + return new CertificateValidity(notBefore, notAfter); + } + + /** + * convert a millisecond resolution time into one with 1 second + * resolution. Most times in certificates are storage at 1 + * second resolution, so its better if we deal with things at + * that level. + */ + protected long roundTimeToSecond(long input) { + return (input / 1000) * 1000; + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/AuthInfoAccessExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/AuthInfoAccessExt.java new file mode 100644 index 000000000..054379bb5 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/AuthInfoAccessExt.java @@ -0,0 +1,381 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.logging.ILogger; +import netscape.security.x509.*; +import netscape.security.extensions.*; +import netscape.ldap.*; +import netscape.security.util.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Authority Information Access extension policy. + * If this policy is enabled, it adds an authority + * information access extension to the certificate. + * + * The following listed sample configuration parameters: + * + * ca.Policy.impl.AuthInfoAccess.class=com.netscape.certsrv.policy.AuthInfoAccessExt + * ca.Policy.rule.aia.ad0_location=uriName:http://ocsp1.netscape.com + * ca.Policy.rule.aia.ad0_method=ocsp + * ca.Policy.rule.aia.ad1_location_type=URI + * ca.Policy.rule.aia.ad1_location=http://ocsp2.netscape.com + * ca.Policy.rule.aia.ad1_method=ocsp + * ca.Policy.rule.aia.ad2_location= + * ca.Policy.rule.aia.ad2_method= + * ca.Policy.rule.aia.ad3_location= + * ca.Policy.rule.aia.ad3_method= + * ca.Policy.rule.aia.ad4_location= + * ca.Policy.rule.aia.ad4_method= + * ca.Policy.rule.aia.critical=true + * ca.Policy.rule.aia.enable=true + * ca.Policy.rule.aia.implName=AuthInfoAccess + * ca.Policy.rule.aia.predicate= + * + * Currently, this policy only supports the following location: + * uriName:[URI], dirName:[DN] + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class AuthInfoAccessExt extends APolicyRule implements + IEnrollmentPolicy, IExtendedPluginInfo { + protected static final String PROP_CRITICAL = + "critical"; + protected static final String PROP_AD = + "ad"; + protected static final String PROP_METHOD = + "method"; + protected static final String PROP_LOCATION = + "location"; + protected static final String PROP_LOCATION_TYPE = + "location_type"; + + protected static final String PROP_NUM_ADS = + "numADs"; + + public static final int MAX_AD = 5; + + public IConfigStore mConfig = null; + + public AuthInfoAccessExt() { + NAME = "AuthInfoAccessExt"; + DESC = "Sets authority information access extension for certificates"; + } + + public String[] getExtendedPluginInfo(Locale locale) { + Vector v = new Vector(); + + v.addElement(PROP_CRITICAL + + ";boolean;RFC 2459 recommendation: This extension MUST be non-critical."); + v.addElement(PROP_NUM_ADS + + ";number;The total number of access descriptions."); + v.addElement(IExtendedPluginInfo.HELP_TEXT + + ";Adds Authority Info Access Extension. Defined in RFC 2459 " + "(4.2.2.1)"); + v.addElement(IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-authinfoaccess"); + + for (int i = 0; i < MAX_AD; i++) { + v.addElement(PROP_AD + Integer.toString(i) + "_" + PROP_METHOD + ";string;" + "A unique,valid OID specified in dot-separated numeric component notation. e.g. 1.3.6.1.5.5.7.48.1 (ocsp), 1.3.6.1.5.5.7.48.2 (caIssuers), 2.16.840.1.113730.1.16.1 (renewal)"); + v.addElement(PROP_AD + Integer.toString(i) + "_" + PROP_LOCATION_TYPE + ";" + IGeneralNameUtil.GENNAME_CHOICE_INFO); + v.addElement(PROP_AD + Integer.toString(i) + "_" + PROP_LOCATION + ";" + IGeneralNameUtil.GENNAME_VALUE_INFO); + } + return com.netscape.cmsutil.util.Utils.getStringArrayFromVector(v); + } + + /** + * Initializes this policy rule. + *

+ * + * The entries may be of the form: + * + * ca.Policy.rule..implName=AuthInfoAccessExt + * ca.Policy.rule..enable=true + * ca.Policy.rule..predicate= + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + } + + /** + * Returns a sequence of access descriptions. + */ + private Enumeration getAccessDescriptions() throws EBaseException { + Vector ads = new Vector(); + + // + // read until there is *NO* ad_method + // + for (int i = 0;; i++) { + ObjectIdentifier methodOID = null; + String method = mConfig.getString(PROP_AD + + Integer.toString(i) + "_" + PROP_METHOD, null); + + if (method == null) + break; + method = method.trim(); + if (method.equals("")) + break; + + // + // method ::= ocsp | caIssuers | + // OID ::= [object identifier] + // + try { + if (method.equalsIgnoreCase("ocsp")) { + methodOID = ObjectIdentifier.getObjectIdentifier("1.3.6.1.5.5.7.48.1"); + } else if (method.equalsIgnoreCase("caIssuers")) { + methodOID = ObjectIdentifier.getObjectIdentifier("1.3.6.1.5.5.7.48.2"); + } else if (method.equalsIgnoreCase("renewal")) { + methodOID = ObjectIdentifier.getObjectIdentifier("2.16.840.1.113730.1.16.1"); + } else { + // it could be an object identifier, test it + methodOID = ObjectIdentifier.getObjectIdentifier(method); + } + } catch (IOException e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_ATTRIBUTE_NAME_CAN_NOT_BE_RESOLVED", method)); + } + + // + // location ::= : + // TAG ::= uriName | dirName + // VALUE ::= [value defined by TAG] + // + String location_type = mConfig.getString(PROP_AD + + Integer.toString(i) + + "_" + PROP_LOCATION_TYPE, null); + String location = mConfig.getString(PROP_AD + + Integer.toString(i) + + "_" + PROP_LOCATION, null); + + if (location == null) + break; + GeneralName gn = CMS.form_GeneralName(location_type, location); + Vector e = new Vector(); + + e.addElement(methodOID); + e.addElement(gn); + ads.addElement(e); + } + return ads.elements(); + } + + /** + * If this policy is enabled, add the authority information + * access extension to the certificate. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + PolicyResult res = PolicyResult.ACCEPTED; + + X509CertInfo certInfo; + X509CertInfo[] ci = req.getExtDataInCertInfoArray( + IRequest.CERT_INFO); + + if (ci == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO", NAME), ""); + return PolicyResult.REJECTED; // unrecoverable error. + } + + for (int j = 0; j < ci.length; j++) { + + certInfo = ci[j]; + if (certInfo == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_UNEXPECTED_POLICY_ERROR", NAME, "")); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", + NAME, "Configuration Info Error"), ""); + return PolicyResult.REJECTED; // unrecoverable error. + } + + try { + // Find the extensions in the certInfo + CertificateExtensions extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + + // add access descriptions + Enumeration e = getAccessDescriptions(); + + if (!e.hasMoreElements()) { + return res; + } + + if (extensions == null) { + // create extension if not exist + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } else { + // check to see if AIA is already exist + try { + extensions.delete(AuthInfoAccessExtension.NAME); + log(ILogger.LL_WARN, "Previous extension deleted: " + AuthInfoAccessExtension.NAME); + } catch (IOException ex) { + } + } + + // Create the extension + AuthInfoAccessExtension aiaExt = new + AuthInfoAccessExtension(mConfig.getBoolean( + PROP_CRITICAL, false)); + + while (e.hasMoreElements()) { + Vector ad = (Vector) e.nextElement(); + ObjectIdentifier oid = (ObjectIdentifier) ad.elementAt(0); + GeneralName gn = (GeneralName) ad.elementAt(1); + + aiaExt.addAccessDescription(oid, gn); + } + extensions.set(AuthInfoAccessExtension.NAME, aiaExt); + + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_UNEXPECTED_POLICY_ERROR", NAME, e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", + NAME, e.getMessage()), ""); + return PolicyResult.REJECTED; // unrecoverable error. + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_UNEXPECTED_POLICY_ERROR", NAME, e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", + NAME, "Configuration Info Error"), ""); + return PolicyResult.REJECTED; // unrecoverable error. + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_UNEXPECTED_POLICY_ERROR", NAME, e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", + NAME, "Certificate Info Error"), ""); + return PolicyResult.REJECTED; // unrecoverable error. + } + } + + return res; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector params = new Vector(); + + try { + params.addElement(PROP_CRITICAL + "=" + + mConfig.getBoolean(PROP_CRITICAL, false)); + } catch (EBaseException e) { + params.addElement(PROP_CRITICAL + "=false"); + } + + int numADs = MAX_AD; + + try { + numADs = mConfig.getInteger(PROP_NUM_ADS, MAX_AD); + params.addElement(PROP_NUM_ADS + "=" + numADs); + } catch (EBaseException e) { + params.addElement(PROP_NUM_ADS + "=" + MAX_AD); + } + + for (int i = 0; i < numADs; i++) { + String method = null; + + try { + method = mConfig.getString(PROP_AD + + Integer.toString(i) + "_" + PROP_METHOD, + ""); + } catch (EBaseException e) { + } + params.addElement(PROP_AD + + Integer.toString(i) + + "_" + PROP_METHOD + "=" + method); + String location_type = null; + + try { + location_type = mConfig.getString(PROP_AD + + Integer.toString(i) + "_" + PROP_LOCATION_TYPE, + IGeneralNameUtil.GENNAME_CHOICE_URL); + } catch (EBaseException e) { + } + params.addElement(PROP_AD + + Integer.toString(i) + + "_" + PROP_LOCATION_TYPE + "=" + location_type); + String location = null; + + try { + location = mConfig.getString(PROP_AD + + Integer.toString(i) + "_" + PROP_LOCATION, + ""); + } catch (EBaseException e) { + } + params.addElement(PROP_AD + + Integer.toString(i) + + "_" + PROP_LOCATION + "=" + location); + } + return params; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + Vector defParams = new Vector(); + + defParams.addElement(PROP_CRITICAL + "=false"); + defParams.addElement(PROP_NUM_ADS + "=" + MAX_AD); + + // + // By default, we create MAX_AD access descriptions. + // If this is not enough, admin can manually edit + // the CMS.cfg + // + for (int i = 0; i < MAX_AD; i++) { + defParams.addElement(PROP_AD + Integer.toString(i) + + "_" + PROP_METHOD + "="); + defParams.addElement(PROP_AD + Integer.toString(i) + + "_" + PROP_LOCATION_TYPE + "=" + IGeneralNameUtil.GENNAME_CHOICE_URL); + defParams.addElement(PROP_AD + Integer.toString(i) + + "_" + PROP_LOCATION + "="); + } + return defParams; + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/AuthorityKeyIdentifierExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/AuthorityKeyIdentifierExt.java new file mode 100644 index 000000000..b170925c4 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/AuthorityKeyIdentifierExt.java @@ -0,0 +1,418 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.ca.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authority.*; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.apps.*; +import netscape.security.x509.*; +import netscape.security.util.*; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.InvalidKeyException; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Authority Public Key Extension Policy + * Adds the subject public key id extension to certificates. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class AuthorityKeyIdentifierExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + protected static final String PROP_CRITICAL = "critical"; + protected static final String PROP_ALT_KEYID_TYPE = "AltKeyIdType"; + + protected static final String ALT_KEYID_TYPE_SPKISHA1 = "SpkiSHA1"; + protected static final String ALT_KEYID_TYPE_NONE = "None"; + protected static final String ALT_KEYID_TYPE_EMPTY = "Empty"; + + protected static final boolean DEF_CRITICAL = false; + protected static final String DEF_ALT_KEYID_TYPE = ALT_KEYID_TYPE_SPKISHA1; + + protected boolean mEnabled = false; + protected IConfigStore mConfig = null; + + // config params. + protected boolean mCritical = DEF_CRITICAL; + protected String mAltKeyIdType = DEF_ALT_KEYID_TYPE; + + // the extension to add to certs. + protected AuthorityKeyIdentifierExtension mTheExtension = null; + + // instance params for console + protected Vector mInstanceParams = new Vector(); + + // default params for console. + protected static Vector mDefaultParams = new Vector(); + static { + // form static default params. + mDefaultParams.addElement(PROP_CRITICAL + "=" + DEF_CRITICAL); + mDefaultParams.addElement(PROP_ALT_KEYID_TYPE + "=" + DEF_ALT_KEYID_TYPE); + } + + public AuthorityKeyIdentifierExt() { + NAME = "AuthorityKeyIdentifierExt"; + DESC = "Adds Authority Key Idenifier Extension to certs"; + } + + /** + * Initializes this policy rule. + * Reads configuration file and creates a authority key identifier + * extension to add. Key identifier inside the extension is constructed as + * the CA's subject key identifier extension if it exists. + * If it does not exist this can be configured to use: + * (1) sha-1 hash of the CA's subject public key info + * (what communicator expects if the CA does not have a subject key + * identifier extension) or (2) No extension set (3) Empty sequence + * in Authority Key Identifier extension. + * + *

+ * + * The entries may be of the form: + * + * ca.Policy.rule..predicate= + * ca.Policy.rule..implName= + * ca.Policy.rule..enable=true + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + + mEnabled = mConfig.getBoolean( + IPolicyProcessor.PROP_ENABLE, false); + mCritical = mConfig.getBoolean(PROP_CRITICAL, DEF_CRITICAL); + + mAltKeyIdType = mConfig.getString( + PROP_ALT_KEYID_TYPE, DEF_ALT_KEYID_TYPE); + + if (mAltKeyIdType.equalsIgnoreCase(ALT_KEYID_TYPE_SPKISHA1)) + mAltKeyIdType = ALT_KEYID_TYPE_SPKISHA1; + + /* + else if (mAltKeyIdType.equalsIgnoreCase(ALT_KEYID_TYPE_EMPTY)) + mAltKeyIdType = ALT_KEYID_TYPE_EMPTY; + */ + else if (mAltKeyIdType.equalsIgnoreCase(ALT_KEYID_TYPE_NONE)) + mAltKeyIdType = ALT_KEYID_TYPE_NONE; + else { + log(ILogger.LL_FAILURE, NAME + + CMS.getLogMessage("CA_UNKNOWN_ALT_KEY_ID_TYPE", mAltKeyIdType)); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", PROP_ALT_KEYID_TYPE, + "value must be one of " + ALT_KEYID_TYPE_SPKISHA1 + ", " + ALT_KEYID_TYPE_NONE)); + } + + // create authority key id extension. + ICertAuthority certAuthority = (ICertAuthority) + ((IPolicyProcessor) owner).getAuthority(); + + if (certAuthority == null) { + // should never get here. + String msg = NAME + ": " + + "Cannot find the Certificate Manager or Registration Manager"; + + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CANT_FIND_MANAGER")); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", msg)); + } + if (!(certAuthority instanceof ICertificateAuthority)) { + log(ILogger.LL_FAILURE, NAME + + CMS.getLogMessage("POLICY_INVALID_POLICY", NAME)); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", + NAME + " policy can only be used in a Certificate Authority.")); + } + //CertificateChain caChain = certAuthority.getCACertChain(); + //X509Certificate caCert = caChain.getFirstCertificate(); + X509CertImpl caCert = certAuthority.getCACert(); + if( caCert == null || CMS.isPreOpMode() ) { + return; + } + KeyIdentifier keyId = formKeyIdentifier(caCert); + + if (keyId != null) { + try { + mTheExtension = new AuthorityKeyIdentifierExtension( + mCritical, keyId, null, null); + } catch (IOException e) { + String msg = NAME + ": " + + "Error forming Authority Key Identifier extension: " + e; + + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_ERROR_AUTHORITY_KEY_ID_1", NAME)); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", msg)); + } + } else { + } + + // form instance params + mInstanceParams.addElement(PROP_CRITICAL + "=" + mCritical); + mInstanceParams.addElement(PROP_ALT_KEYID_TYPE + "=" + mAltKeyIdType); + } + + /** + * Adds Authority Key Identifier Extension to a certificate. + * If the extension is already there, accept it if it's from the agent, + * else replace it. + * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + // get certInfo from request. + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO", NAME), ""); + return PolicyResult.REJECTED; + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult certResult = applyCert(req, ci[i]); + + if (certResult == PolicyResult.REJECTED) + return certResult; + } + return PolicyResult.ACCEPTED; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + + try { + // if authority key id extension already exists, leave it if + // from agent. else replace it. + AuthorityKeyIdentifierExtension authorityKeyIdExt = null; + CertificateExtensions extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + + try { + if (extensions != null) { + authorityKeyIdExt = (AuthorityKeyIdentifierExtension) + extensions.get(AuthorityKeyIdentifierExtension.NAME); + } + } catch (IOException e) { + // extension isn't there. + } + if (authorityKeyIdExt != null) { + if (agentApproved(req)) { + CMS.debug( + "AuthorityKeyIdentifierKeyExt: agent approved request id " + req.getRequestId() + + " already has authority key id extension with value " + + authorityKeyIdExt); + return PolicyResult.ACCEPTED; + } else { + CMS.debug( + "AuthorityKeyIdentifierKeyExt: request id from user " + req.getRequestId() + + " had authority key identifier - deleted"); + extensions.delete(AuthorityKeyIdentifierExtension.NAME); + } + } + + // if no authority key identifier should be set b/c CA does not + // have a subject key identifier, return here. + if (mTheExtension == null) + return PolicyResult.ACCEPTED; + + // add authority key id extension. + if (extensions == null) { + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } + extensions.set( + AuthorityKeyIdentifierExtension.NAME, mTheExtension); + CMS.debug( + "AuthorityKeyIdentifierKeyExt: added authority key id ext to request " + req.getRequestId()); + return PolicyResult.ACCEPTED; + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_UNEXPECTED_POLICY_ERROR", NAME, e.toString())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", + NAME, e.getMessage()), ""); + return PolicyResult.REJECTED; + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("BASE_INVALID_CERT", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR", + NAME, "Certificate Info Error"), ""); + return PolicyResult.REJECTED; + } + } + + /** + * Form the Key Identifier in the Authority Key Identifier extension. + * from the CA's cert. + *

+ * @param caCertImpl Certificate Info + * @return A Key Identifier. + * @throws com.netscape.certsrv.base.EBaseException on error + */ + protected KeyIdentifier formKeyIdentifier(X509CertImpl caCertImpl) + throws EBaseException { + KeyIdentifier keyId = null; + + // get CA's certInfo. + X509CertInfo certInfo = null; + + try { + certInfo = (X509CertInfo) caCertImpl.get( + X509CertImpl.NAME + "." + X509CertImpl.INFO); + if (certInfo == null) { + String msg = "Bad CA certificate encountered. " + + "TBS Certificate missing."; + + log(ILogger.LL_FAILURE, CMS.getLogMessage("BASE_INVALID_CERT_FORMAT")); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", NAME + ": " + msg)); + } + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, NAME + ": " + + CMS.getLogMessage("BASE_DECODE_CERT_FAILED_1", e.toString())); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", + NAME + " Error decoding the CA Certificate: " + e)); + } + + // get Key Id from CA's Subject Key Id extension in CA's CertInfo. + keyId = getKeyIdentifier(certInfo); + if (keyId != null) + return keyId; + + // if none exists use the configured alternate. + if (mAltKeyIdType == ALT_KEYID_TYPE_SPKISHA1) { + keyId = formSpkiSHA1KeyId(certInfo); + } /* + else if (mAltKeyIdType == ALT_KEYID_TYPE_EMPTY) { + keyId = formEmptyKeyId(certInfo); + } + */ else if (mAltKeyIdType == ALT_KEYID_TYPE_NONE) { + keyId = null; + } else { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + mAltKeyIdType, + "Unknown Alternate Key Identifier type.")); + } + return keyId; + } + + /** + * Get the Key Identifier in a subject key identifier extension from a + * CertInfo. + * @param certInfo the CertInfo structure. + * @return Key Identifier in a Subject Key Identifier extension if any. + */ + protected KeyIdentifier getKeyIdentifier(X509CertInfo certInfo) + throws EBaseException { + CertificateExtensions exts = null; + SubjectKeyIdentifierExtension subjKeyIdExt = null; + KeyIdentifier keyId = null; + + try { + exts = (CertificateExtensions) certInfo.get(X509CertInfo.EXTENSIONS); + } catch (IOException e) { + // extension isn't there. + CMS.debug(NAME + ": " + "No extensions found. Error " + e); + return null; + } catch (CertificateException e) { + // extension isn't there. + CMS.debug(NAME + ": " + "No extensions found. Error " + e); + return null; + } + if (exts == null) + return null; + + try { + subjKeyIdExt = (SubjectKeyIdentifierExtension) + exts.get(SubjectKeyIdentifierExtension.NAME); + } catch (IOException e) { + // extension isn't there. + CMS.debug( + "AuthorityKeyIdentifierKeyExt: No Subject Key Identifier Extension found. Error: " + e); + return null; + } + if (subjKeyIdExt == null) + return null; + + try { + keyId = (KeyIdentifier) subjKeyIdExt.get( + SubjectKeyIdentifierExtension.KEY_ID); + } catch (IOException e) { + // no key identifier in subject key id extension. + String msg = NAME + ": " + + "Bad Subject Key Identifier Extension found. Error: " + e; + + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_ERROR_AUTHORITY_KEY_ID_1", NAME)); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", msg)); + } + return keyId; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + return mInstanceParams; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return mDefaultParams; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_CRITICAL + ";boolean;" + + "RFC 2459 recommendation: MUST NOT be marked critical.", + PROP_ALT_KEYID_TYPE + ";" + + "choice(" + ALT_KEYID_TYPE_SPKISHA1 + "," + ALT_KEYID_TYPE_NONE + ");" + + "Specifies whether to use a SHA1 hash of the CA's subject " + + "public key info for key identifier or leave out the " + + "authority key identifier extension if the CA certificate " + + "does not have a Subject Key Identifier extension.", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-authkeyid", + IExtendedPluginInfo.HELP_TEXT + + ";Adds Authority Key Identifier Extension. " + + "See RFC 2459 (4.2.1.1)" + }; + + return params; + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/BasicConstraintsExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/BasicConstraintsExt.java new file mode 100644 index 000000000..73a6b58af --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/BasicConstraintsExt.java @@ -0,0 +1,498 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.ra.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.authority.*; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.apps.*; +import netscape.security.x509.*; +import netscape.ldap.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Basic Constraints policy. + * Adds the Basic constraints extension. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class BasicConstraintsExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + protected static final String PROP_MAXPATHLEN = "maxPathLen"; + protected static final String PROP_IS_CA = "isCA"; + protected static final String PROP_IS_CRITICAL = "critical"; + + protected static final String ARG_PATHLEN = "BasicConstraintsPathLen"; + + protected int mMaxPathLen = 0; // < 0 means unlimited + protected String mOrigMaxPathLen = ""; // for UI display only + protected boolean mCritical = true; + protected int mDefaultMaxPathLen = 0; // depends on the CA's path length. + protected int mCAPathLen = 0; + protected boolean mRemoveExt = true; + protected boolean mIsCA = true; + + public static final boolean DEFAULT_CRITICALITY = true; + + /** + * Adds the basic constraints extension as a critical extension in + * CA certificates i.e. certype is ca, with either a requested + * or configured path len. + * The requested or configured path length cannot be greater than + * or equal to the CA's basic constraints path length. + * If the CA path length is 0, all requests for CA certs are rejected. + */ + public BasicConstraintsExt() { + NAME = "BasicConstraintsExt"; + DESC = + "Sets critical basic constraints extension in subordinate CA certs"; + } + + /** + * Initializes this policy rule. + *

+ * The entries may be of the form: + * + * ca.Policy.rule..implName=BasicConstraintsExtImpl + * ca.Policy.rule..pathLen=, -1 for undefined. + * ca.Policy.rule..enable=true + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + + // get the CA's path len to check against configured max path len. + ICertAuthority certAuthority = (ICertAuthority) + ((IPolicyProcessor) owner).getAuthority(); + + if (certAuthority == null) { + // should never get here. + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CANT_FIND_MANAGER")); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", + "Cannot find the Certificate Manager or Registration Manager")); + } + if (certAuthority instanceof IRegistrationAuthority) { + log(ILogger.LL_WARN, + "default basic constraints extension path len to -1."); + mCAPathLen = -1; + } else { + CertificateChain caChain = certAuthority.getCACertChain(); + if( caChain == null || CMS.isPreOpMode() ) { + return; + } + X509Certificate caCert = caChain.getFirstCertificate(); + + mCAPathLen = caCert.getBasicConstraints(); + } + // set default to one less than the CA's pathlen or 0 if CA's + // pathlen is 0. + // If it's unlimited default the max pathlen also to unlimited. + if (mCAPathLen < 0) + mDefaultMaxPathLen = -1; + else if (mCAPathLen > 0) + mDefaultMaxPathLen = mCAPathLen - 1; + else // (mCAPathLen == 0) + { + log(ILogger.LL_WARN, + CMS.getLogMessage("POLICY_PATHLEN_ZERO")); + //return; + } + + // get configured max path len, use defaults if not configured. + boolean pathLenConfigured = true; + + try { + mCritical = config.getBoolean(PROP_IS_CRITICAL, true); + mIsCA = config.getBoolean(PROP_IS_CA, true); + mMaxPathLen = config.getInteger(PROP_MAXPATHLEN); + if (mMaxPathLen < 0) { + log(ILogger.LL_MISCONF, + CMS.getLogMessage("POLICY_INVALID_MAXPATHLEN_4", "", + String.valueOf(mMaxPathLen))); + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_INVALID_MAXPATHLEN_1", + NAME, String.valueOf(mMaxPathLen))); + } + mOrigMaxPathLen = Integer.toString(mMaxPathLen); + } catch (EBaseException e) { + if (!(e instanceof EPropertyNotFound) && + !(e instanceof EPropertyNotDefined)) { + log(ILogger.LL_MISCONF, + CMS.getLogMessage("POLICY_INVALID_MAXPATHLEN")); + throw e; + } + + // Set the max path len to default if not configured. + pathLenConfigured = false; + mMaxPathLen = mDefaultMaxPathLen; + mOrigMaxPathLen = ""; + } + + // check if configured path len is valid. + if (pathLenConfigured) { + // if CA's pathlen is unlimited, any max pathlen is ok. + // else maxPathlen must be at most one less than the CA's + // pathlen or 0 if CA's pathlen is 0. + + if (mCAPathLen > 0 && + (mMaxPathLen >= mCAPathLen || mMaxPathLen < 0)) { + String maxStr = (mMaxPathLen < 0) ? + String.valueOf(mMaxPathLen) + "(unlimited)" : + String.valueOf(mMaxPathLen); + + log(ILogger.LL_MISCONF, + CMS.getLogMessage("POLICY_MAXPATHLEN_TOO_BIG_3", "", + maxStr, + String.valueOf(mCAPathLen))); + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_MAXPATHLEN_TOO_BIG_1", + NAME, maxStr, Integer.toString(mCAPathLen))); + } else if (mCAPathLen == 0 && mMaxPathLen != 0) { + log(ILogger.LL_MISCONF, + CMS.getLogMessage("POLICY_INVALID_MAXPATHLEN_2", "", String.valueOf(mMaxPathLen))); + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_INVALID_MAXPATHLEN", + NAME, String.valueOf(mMaxPathLen))); + } + } + + } + + /** + * Checks if the basic contraints extension in certInfo is valid and + * add the basic constraints extension for CA certs if none exists. + * Non-CA certs do not get a basic constraints extension. + * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + PolicyResult res = PolicyResult.ACCEPTED; + + // get cert info. + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + X509CertInfo certInfo = null; + + if (ci == null || (certInfo = ci[0]) == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO", NAME), ""); + return PolicyResult.REJECTED; // unrecoverable error. + } + + // get cert type + boolean isCA = mIsCA; + + /** + boolean isCA = false; + String type = (String)req.get(IRequest.HTTP_PARAMS, IRequest.CERT_TYPE); + if (type != null && type.equalsIgnoreCase(IRequest.CA_CERT)) { + isCA = true; + } + **/ + + for (int i = 0; i < ci.length; i++) { + PolicyResult certResult = applyCert(req, isCA, certInfo); + + if (certResult == PolicyResult.REJECTED) + return certResult; + } + return PolicyResult.ACCEPTED; + } + + public PolicyResult applyCert( + IRequest req, boolean isCA, X509CertInfo certInfo) { + + // get basic constraints extension from cert info if any. + CertificateExtensions extensions = null; + BasicConstraintsExtension basicExt = null; + + try { + // get basic constraints extension if any. + extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + if (extensions != null) { + basicExt = (BasicConstraintsExtension) + extensions.get(BasicConstraintsExtension.NAME); + } + } catch (IOException e) { + // no extensions or basic constraints extension. + } catch (CertificateException e) { + // no extensions or basic constraints extension. + } + + // for non-CA certs, pkix says it SHOULD NOT have the extension + // so remove it. + if (!isCA) { + if (extensions == null) { + try { + // create extensions set if none. + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } catch (CertificateException e) { + } catch (IOException e) { + // not possible + } + } + if (basicExt != null) { + try { + extensions.delete(BasicConstraintsExtension.NAME); + } catch (IOException e) { + } + } + + BasicConstraintsExtension critExt; + + try { + critExt = new BasicConstraintsExtension(isCA, mCritical, mMaxPathLen); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_BASIC_CONSTRAINTS_2", + e.toString())); + setError(req, + CMS.getUserMessage("CMS_POLICY_BASIC_CONSTRAINTS_ERROR", NAME), ""); + return PolicyResult.REJECTED; // unrecoverable error. + } + + try { + extensions.set(BasicConstraintsExtension.NAME, critExt); + } catch (IOException e) { + } + CMS.debug( + "BasicConstraintsExt: PolicyRule BasicConstraintsExt: added the extension to request " + + req.getRequestId()); + return PolicyResult.ACCEPTED; + } + + // For CA certs, check if existing extension is valid, and adjust. + // Extension must be marked critial and pathlen must be < CA's pathlen. + // if CA's pathlen is 0 all ca certs are rejected. + + if (mCAPathLen == 0) { + // reject all subordinate CA cert requests because CA's + // path length is 0. + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_NO_SUB_CA_CERTS_ALLOWED_1", NAME)); + setError(req, CMS.getUserMessage("CMS_POLICY_NO_SUB_CA_CERTS_ALLOWED", NAME), ""); + return PolicyResult.REJECTED; + } + + if (basicExt != null) { + try { + boolean extIsCA = + ((Boolean) basicExt.get(BasicConstraintsExtension.IS_CA)).booleanValue(); + int pathLen = + ((Integer) basicExt.get(BasicConstraintsExtension.PATH_LEN)).intValue(); + + if (mMaxPathLen > -1) { + if (pathLen > mMaxPathLen || pathLen < 0) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_MAXPATHLEN_TOO_BIG_3", NAME, "unlimited", String.valueOf(pathLen))); + if (pathLen < 0) + setError(req, CMS.getUserMessage("CMS_POLICY_MAXPATHLEN_TOO_BIG", + NAME, "unlimited", Integer.toString(mMaxPathLen)), ""); + else + setError(req, CMS.getUserMessage("CMS_POLICY_MAXPATHLEN_TOO_BIG", + NAME, Integer.toString(pathLen), + Integer.toString(mMaxPathLen)), ""); + return PolicyResult.REJECTED; + } + } + + // adjust isCA field + if (!extIsCA) { + basicExt.set(BasicConstraintsExtension.IS_CA, + Boolean.valueOf(true)); + } + + // adjust path length field. + if (mMaxPathLen == 0) { + if (pathLen != 0) { + basicExt.set(BasicConstraintsExtension.PATH_LEN, + Integer.valueOf(0)); + pathLen = 0; + } + } else if (mMaxPathLen > 0 && pathLen > mMaxPathLen) { + basicExt.set(BasicConstraintsExtension.PATH_LEN, + Integer.valueOf(mMaxPathLen)); + pathLen = mMaxPathLen; + } + + // adjust critical field. + if (!basicExt.isCritical()) { + BasicConstraintsExtension critExt; + + try { + critExt = new BasicConstraintsExtension(isCA, mCritical, pathLen); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_BASIC_CONSTRAINTS_1", NAME)); + setError(req, + CMS.getUserMessage("CMS_POLICY_BASIC_CONSTRAINTS_ERROR", NAME), ""); + return PolicyResult.REJECTED; // unrecoverable error. + } + extensions.delete(BasicConstraintsExtension.NAME); + extensions.set(BasicConstraintsExtension.NAME, critExt); + } + } catch (IOException e) { + // not possible in these cases. + } + CMS.debug( + "BasicConstraintsExt: PolicyRule BasicConstraintsExt: added the extension to request " + + req.getRequestId()); + return PolicyResult.ACCEPTED; + } + + // add the extension for the CA cert. + if (extensions == null) { + try { + // create extensions set if none. + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } catch (CertificateException e) { + // not possible + } catch (IOException e) { + // not possible + } + } + + // set path len to requested path len if it's valid. + // if no path len requested set path len to max allowed path len. + String reqPathLenStr = req.getExtDataInString(ARG_PATHLEN); + int reqPathLen; + + if (reqPathLenStr == null) { + reqPathLen = mMaxPathLen; + } else { + try { + reqPathLen = Integer.parseInt(reqPathLenStr); + if ((mMaxPathLen == 0 && reqPathLen != 0) || + (mMaxPathLen > 0 && + (reqPathLen > mMaxPathLen || reqPathLen < 0))) { + String plenStr = + ((reqPathLen < 0) ? + reqPathLenStr + "(unlimited)" : reqPathLenStr); + + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_PATHLEN_TOO_BIG_3", plenStr, + String.valueOf(mMaxPathLen))); + setError(req, + CMS.getUserMessage("CMS_POLICY_PATHLEN_TOO_BIG", + NAME, plenStr, String.valueOf(mMaxPathLen)), ""); + return PolicyResult.REJECTED; + } + } catch (NumberFormatException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_INVALID_PATHLEN_FORMAT_2", NAME, reqPathLenStr)); + setError(req, CMS.getUserMessage("CMS_POLICY_INVALID_PATHLEN_FORMAT", + NAME, reqPathLenStr), ""); + return PolicyResult.REJECTED; + } + } + BasicConstraintsExtension newExt; + + try { + newExt = new BasicConstraintsExtension(isCA, mCritical, reqPathLen); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_BASIC_CONSTRAINTS_2", e.toString())); + setError(req, + CMS.getUserMessage("CMS_POLICY_BASIC_CONSTRAINTS_ERROR", NAME), ""); + return PolicyResult.REJECTED; // unrecoverable error. + } + try { + extensions.set(BasicConstraintsExtension.NAME, newExt); + }catch (IOException e) { + // doesn't happen. + } + CMS.debug( + "BasicConstraintsExt: added the extension to request " + + req.getRequestId()); + return PolicyResult.ACCEPTED; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector params = new Vector(); + + // Because of one of the UI bugs 385273, we should leave the empty space + // as is. Do not convert the space to some definite numbers. + params.addElement(PROP_MAXPATHLEN + "=" + mOrigMaxPathLen); + params.addElement(PROP_IS_CRITICAL + "=" + mCritical); + params.addElement(PROP_IS_CA + "=" + mIsCA); + return params; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + Vector defParams = new Vector(); + + defParams.addElement(PROP_IS_CRITICAL + "=true"); + defParams.addElement(PROP_MAXPATHLEN + "="); + defParams.addElement(PROP_IS_CA + "=true"); + return defParams; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_MAXPATHLEN + ";number;'0' means : no subordinates allowed, 'n' means : at most n subordinates allowed.", + PROP_IS_CRITICAL + ";boolean;" + + "RFC 2459 recommendation: MUST be critical in CA certs, SHOULD NOT appear in EE certs.", + PROP_IS_CA + ";boolean;" + + "Identifies the subject of the certificate is a CA or not.", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-basicconstraints", + IExtendedPluginInfo.HELP_TEXT + + ";Adds the Basic Constraints extension. See RFC 2459 (4.2.1.10)" + }; + + return params; + } + +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/CRLDistributionPointsExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/CRLDistributionPointsExt.java new file mode 100644 index 000000000..84664b09d --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/CRLDistributionPointsExt.java @@ -0,0 +1,464 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.apps.*; +import netscape.security.util.BitArray; +import netscape.security.x509.*; +import netscape.security.x509.CRLDistributionPointsExtension.Reason; +import com.netscape.cms.policy.APolicyRule; + + +/** + * The type of the distribution point or issuer name. The name is expressed + * as a simple string in the configuration file, so this attribute is needed + * to tell whether the simple string should be stored in an X.500 Name, + * a URL, or an RDN. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +class NameType { + private NameType() { + } // no default constructor + + private String stringRep; // string representation of this type + + private NameType(String s) { + map.put(s, this); + stringRep = s; + } + + private static Hashtable map = new Hashtable(); + + /** + * Looks up a NameType from its string representation. Returns null + * if no matching NameType was found. + */ + public static NameType fromString(String s) { + return (NameType) map.get(s); + } + + public String toString() { + return stringRep; + } + + public static final NameType DIRECTORY_NAME = new NameType("DirectoryName"); + public static final NameType URI = new NameType("URI"); + public static final NameType RELATIVE_TO_ISSUER = + new NameType("RelativeToIssuer"); +} + + +/** + * These are the parameters that may be given in the configuration file + * for each distribution point. They are parsed by DPParamsToDP(). + * Any of them may be null. + */ +class DistPointParams { + public String pointName; + public String pointType; + + public String reasons; + + public String issuerName; + public String issuerType; + + public DistPointParams() { + } + + public DistPointParams(DistPointParams old) { + pointName = old.pointName; + pointType = old.pointType; + reasons = old.reasons; + issuerName = old.issuerName; + issuerType = old.issuerType; + } + +} + + +/** + * CRL Distribution Points policy. + * Adds the CRL Distribution Points extension to the certificate. + */ +public class CRLDistributionPointsExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + + public static final String PROP_IS_CRITICAL = "critical"; + public static final String PROP_NUM_POINTS = "numPoints"; + public static final String PROP_POINT_TYPE = "pointType"; + public static final String PROP_POINT_NAME = "pointName"; + public static final String PROP_REASONS = "reasons"; + public static final String PROP_ISSUER_NAME = "issuerName"; + public static final String PROP_ISSUER_TYPE = "issuerType"; + + private static final int MAX_POINTS = 10; + private static final int DEFAULT_NUM_BLANK_POINTS = 3; + private int mNumPoints = DEFAULT_NUM_BLANK_POINTS; + + // PKIX specifies the that the extension SHOULD NOT be critical + public static final boolean DEFAULT_CRITICALITY = false; + + private Vector defaultParams = new Vector(); + + private Vector mParams = new Vector(); + private String mExtParams[] = null; + private CRLDistributionPointsExtension mCrldpExt = null; + + public CRLDistributionPointsExt() { + NAME = "CRLDistributionPointsExt"; + DESC = "Sets CRL distribution points extension"; + defaultParams.addElement(PROP_IS_CRITICAL + "=" + DEFAULT_CRITICALITY); + defaultParams.addElement(PROP_NUM_POINTS + "=0"); + for (int i = 0; i < DEFAULT_NUM_BLANK_POINTS; i++) { + defaultParams.addElement(PROP_POINT_NAME + i + "="); + defaultParams.addElement(PROP_POINT_TYPE + i + "="); + defaultParams.addElement(PROP_REASONS + i + "="); + defaultParams.addElement(PROP_ISSUER_NAME + i + "="); + defaultParams.addElement(PROP_ISSUER_TYPE + i + "="); + } + } + + private void setExtendedPluginInfo() { + Vector v = new Vector(); + + // should replace MAX_POINTS with mNumPoints if bug 385118 is fixed + for (int i = 0; i < MAX_POINTS; i++) { + v.addElement(PROP_POINT_TYPE + Integer.toString(i) + ";choice(" + + "DirectoryName,URI,RelativeToIssuer);" + + "The type of the CRL distribution point."); + v.addElement(PROP_POINT_NAME + Integer.toString(i) + ";string;" + + "The name of the CRL distribution point depending on the CRLDP type."); + v.addElement(PROP_REASONS + Integer.toString(i) + ";string;" + + "The revocation reasons for the CRL maintained at this distribution point. It's a comma-seperated list of the following constants: unused, keyCompromise, cACompromise, affiliationChanged, superseded, cessationOfOperation, certificateHold."); + v.addElement(PROP_ISSUER_TYPE + Integer.toString(i) + ";choice(" + + "DirectoryName,URI);" + + "The type of the issuer that has signed the CRL maintained at this distribution point."); + v.addElement(PROP_ISSUER_NAME + Integer.toString(i) + ";string;" + + "The name of the issuer that has signed the CRL maintained at this distribution point. The value depends on the issuer type."); + } + + v.addElement(PROP_NUM_POINTS + + ";number;The total number of CRL distribution points to be contained or allowed in the extension."); + v.addElement(PROP_IS_CRITICAL + + ";boolean;RFC 2459 recommendation: SHOULD be non-critical. But recommends support for this extension by CAs and applications."); + v.addElement(IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-crldistributionpoints"); + v.addElement(IExtendedPluginInfo.HELP_TEXT + + ";This policy inserts the CRL Distribution Points " + + "Extension into the certificate. See RFC 2459 (4.2.1.14). " + ); + + mExtParams = com.netscape.cmsutil.util.Utils.getStringArrayFromVector(v); + } + + public String[] getExtendedPluginInfo(Locale locale) { + if (mExtParams == null) { + setExtendedPluginInfo(); + } + return mExtParams; + + } + + /** + * Performs one-time initialization of the policy. + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + // Register the CRL Distribution Points extension. + try { + netscape.security.x509.OIDMap.addAttribute( + CRLDistributionPointsExtension.class.getName(), + CRLDistributionPointsExtension.OID, + CRLDistributionPointsExtension.NAME); + } catch (CertificateException e) { + // ignore, just means it has already been added + } + + // assemble the list of Distribution Points from the config file + int numPoints = config.getInteger(PROP_NUM_POINTS, 0); + + mParams.addElement(PROP_NUM_POINTS + "=" + numPoints); + mNumPoints = numPoints; + + for (int i = 0; i < numPoints; i++) { + // construct a distribution point from the parameters + DistPointParams params = new DistPointParams(); + + params.pointType = config.getString(PROP_POINT_TYPE + i, ""); + params.pointName = config.getString(PROP_POINT_NAME + i, ""); + params.reasons = config.getString(PROP_REASONS + i, ""); + params.issuerType = config.getString(PROP_ISSUER_TYPE + i, ""); + params.issuerName = config.getString(PROP_ISSUER_NAME + i, ""); + + DistPointParams configparams = new DistPointParams(params); + CRLDistributionPoint crldp = DPParamsToDP(params); + + mParams.addElement(PROP_POINT_TYPE + i + "=" + configparams.pointType); + mParams.addElement(PROP_POINT_NAME + i + "=" + configparams.pointName); + mParams.addElement(PROP_REASONS + i + "=" + configparams.reasons); + mParams.addElement(PROP_ISSUER_TYPE + i + "=" + configparams.issuerType); + mParams.addElement(PROP_ISSUER_NAME + i + "=" + configparams.issuerName); + + // add the distribution point to the extension + if (mCrldpExt == null) { + mCrldpExt = new CRLDistributionPointsExtension(crldp); + } else { + mCrldpExt.addPoint(crldp); + } + } + + boolean crit = config.getBoolean(PROP_IS_CRITICAL, + DEFAULT_CRITICALITY); + + mParams.addElement(PROP_IS_CRITICAL + "=" + crit); + if (mCrldpExt != null) { + // configure the extension itself + mCrldpExt.setCritical(crit); + } + setExtendedPluginInfo(); + + } + + /** + * Parses the parameters in the config file to create an + * actual CRL Distribution Point object. + */ + private CRLDistributionPoint DPParamsToDP(DistPointParams params) + throws EBaseException { + CRLDistributionPoint crlDP = new CRLDistributionPoint(); + + try { + + if (params.pointName != null && params.pointName.length() == 0) { + params.pointName = null; + } + if (params.pointType != null && params.pointType.length() == 0) { + params.pointType = null; + } + if (params.reasons != null && params.reasons.length() == 0) { + params.reasons = null; + } + if (params.issuerName != null && params.issuerName.length() == 0) { + params.issuerName = null; + } + if (params.issuerType != null && params.issuerType.length() == 0) { + params.issuerType = null; + } + + // deal with the distribution point name + if (params.pointName != null && params.pointType != null) { + // decode the type of the name + NameType nType = NameType.fromString(params.pointType); + + if (nType == null) { + String err = "Unknown name type: " + params.pointType; + + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_UNKNOWN_NAME_TYPE", params.pointType)); + throw new EBaseException(err); + } + + if (nType == NameType.DIRECTORY_NAME) { + GeneralNames gen = new GeneralNames(); + + gen.addElement(new GeneralName(new X500Name(params.pointName))); + crlDP.setFullName(gen); + } else if (nType == NameType.URI) { + GeneralNames gen = new GeneralNames(); + + gen.addElement(new GeneralName(new URIName(params.pointName))); + crlDP.setFullName(gen); + } else if (nType == NameType.RELATIVE_TO_ISSUER) { + crlDP.setRelativeName(new RDN(params.pointName)); + } else { + String err = "Unknown name type: " + nType.toString(); + + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_UNKNOWN_NAME_TYPE", nType.toString())); + throw new EBaseException(err); + } + } + + // deal with the reasons + if (params.reasons != null) { + StringTokenizer tok = new StringTokenizer(params.reasons, ", \t"); + byte reasonBits = 0; + + while (tok.hasMoreTokens()) { + String s = tok.nextToken(); + Reason r = Reason.fromString(s); + + if (r == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_UNKNOWN_REASON", s)); + throw new EBaseException("Unknown reason: " + s); + } else { + reasonBits |= r.getBitMask(); + } + } + if (reasonBits != 0) { + BitArray ba = new BitArray(8, new byte[] { reasonBits } + ); + + crlDP.setReasons(ba); + } + } + + // deal with the issuer name + if (params.issuerName != null && params.issuerType != null) { + // decode the type of the name + NameType nType = NameType.fromString(params.issuerType); + + if (nType == null) { + String err = "Unknown name type: " + params.issuerType; + + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_UNKNOWN_NAME_TYPE", params.issuerType)); + throw new EBaseException(err); + } + + if (nType == NameType.DIRECTORY_NAME) { + GeneralNames gen = new GeneralNames(); + + gen.addElement(new GeneralName(new X500Name(params.issuerName))); + crlDP.setCRLIssuer(gen); + } else if (nType == NameType.URI) { + GeneralNames gen = new GeneralNames(); + + gen.addElement(new GeneralName(new URIName(params.issuerName))); + crlDP.setCRLIssuer(gen); + } else { + String err = "Unknown name type: " + nType.toString(); + + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_UNKNOWN_NAME_TYPE", nType.toString())); + throw new EBaseException(err); + } + } + + } catch (GeneralNamesException e) { + throw new EBaseException(e.getMessage()); + } catch (IOException e) { + throw new EBaseException(e.getMessage()); + } + + // done, return this distribution point + return crlDP; + } + + /** + * Applies the policy to the given request. + */ + public PolicyResult apply(IRequest req) { + + // if the extension was not configured correctly, just skip it + if (mCrldpExt == null) { + return PolicyResult.ACCEPTED; + } + + X509CertInfo[] ci = req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult certRes = applyCert(req, ci[i]); + + if (certRes == PolicyResult.REJECTED) + return certRes; + } + return PolicyResult.ACCEPTED; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + + try { + // find the extensions in the certInfo + CertificateExtensions extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + + // prepare the extensions data structure + if (extensions == null) { + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } else { + // remove any previously computed version of the extension + try { + extensions.delete(CRLDistributionPointsExtension.NAME); + } catch (IOException e) { + // extension isn't there + } + } + extensions.set(CRLDistributionPointsExtension.NAME, mCrldpExt); + + return PolicyResult.ACCEPTED; + + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_UNEXPECTED_POLICY_ERROR", NAME, e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), NAME, + e.getMessage()); + return PolicyResult.REJECTED; + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CERT_INFO_ERROR", + e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), NAME, + e.getMessage()); + return PolicyResult.REJECTED; + } + } + + // parameters must be entered in the config file + public Vector getDefaultParams() { + for (int i = DEFAULT_NUM_BLANK_POINTS; i < mNumPoints; i++) { + defaultParams.addElement(PROP_POINT_NAME + i + "="); + defaultParams.addElement(PROP_POINT_TYPE + i + "="); + defaultParams.addElement(PROP_REASONS + i + "="); + defaultParams.addElement(PROP_ISSUER_NAME + i + "="); + defaultParams.addElement(PROP_ISSUER_TYPE + i + "="); + } + return defaultParams; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + return mParams; + } +} diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/CertificatePoliciesExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/CertificatePoliciesExt.java new file mode 100644 index 000000000..bcf9d11cb --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/CertificatePoliciesExt.java @@ -0,0 +1,521 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.ca.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.logging.ILogger; +import netscape.security.x509.*; +import netscape.security.x509.PolicyQualifierInfo; +import netscape.security.util.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Certificate Policies. + * Adds certificate policies extension. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class CertificatePoliciesExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + protected static final String PROP_CRITICAL = "critical"; + protected static final String PROP_NUM_CERTPOLICIES = "numCertPolicies"; + + protected static final String PROP_CERTPOLICY = "certPolicy"; + + protected static final boolean DEF_CRITICAL = false; + protected static final int DEF_NUM_CERTPOLICIES = 1; + + protected boolean mEnabled = false; + protected IConfigStore mConfig = null; + + protected boolean mCritical = DEF_CRITICAL; + protected int mNumCertPolicies = DEF_NUM_CERTPOLICIES; + protected CertPolicy[] mCertPolicies = null; + + protected Vector mInstanceParams = new Vector(); + protected CertificatePoliciesExtension mCertificatePoliciesExtension = null; + + public CertificatePoliciesExt() { + NAME = "CertificatePoliciesExt"; + DESC = "Sets non-critical certificate policies extension in certs"; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries may be of the form: + * + * ca.Policy.rule..predicate=certType==ca + * ca.Policy.rule..implName= + * ca.Policy.rule..enable=true + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + + mEnabled = mConfig.getBoolean( + IPolicyProcessor.PROP_ENABLE, false); + mCritical = mConfig.getBoolean(PROP_CRITICAL, DEF_CRITICAL); + + mNumCertPolicies = mConfig.getInteger( + PROP_NUM_CERTPOLICIES, DEF_NUM_CERTPOLICIES); + if (mNumCertPolicies < 1) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("BASE_INVALID_ATTR_VALUE_2", NAME, "")); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + PROP_NUM_CERTPOLICIES, + "value must be greater than or equal to 1")); + } + + // init Policy Mappings, check values if enabled. + mCertPolicies = new CertPolicy[mNumCertPolicies]; + for (int i = 0; i < mNumCertPolicies; i++) { + String subtreeName = PROP_CERTPOLICY + i; + + try { + mCertPolicies[i] = new CertPolicy(subtreeName, mConfig, mEnabled); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, NAME + ": " + + CMS.getLogMessage("POLICY_ERROR_CREATE_CERT_POLICY", e.toString())); + throw e; + } + } + + // create instance of certificate policy extension if enabled. + if (mEnabled) { + try { + Vector CertPolicies = new Vector(); + + for (int j = 0; j < mNumCertPolicies; j++) { + CertPolicies.addElement( + mCertPolicies[j].mCertificatePolicyInfo); + } + mCertificatePoliciesExtension = + new CertificatePoliciesExtension(mCritical, CertPolicies); + } catch (IOException e) { + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", + "Error initializing " + NAME + " Error: " + e)); + } + } + + // form instance params + mInstanceParams.addElement(PROP_CRITICAL + "=" + mCritical); + mInstanceParams.addElement( + PROP_NUM_CERTPOLICIES + "=" + mNumCertPolicies); + for (int i = 0; i < mNumCertPolicies; i++) { + mCertPolicies[i].getInstanceParams(mInstanceParams); + } + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + + // get certInfo from request. + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult certRes = applyCert(req, ci[i]); + + if (certRes == PolicyResult.REJECTED) + return certRes; + } + return PolicyResult.ACCEPTED; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + CertificateExtensions extensions = null; + + try { + extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + if (extensions == null) { + extensions = new CertificateExtensions(); + try { + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } catch (Exception e) { + } + } else { + // remove any previously computed version of the extension + try { + extensions.delete(CertificatePoliciesExtension.NAME); + } catch (IOException e) { + // this is the hack: for some reason, the key which is the name + // of the policy has been converted into the OID + try { + extensions.delete("2.5.29.32"); + } catch (IOException ee) { + } + } + } + extensions.set(CertificatePoliciesExtension.NAME, + mCertificatePoliciesExtension); + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_ERROR_CERTIFICATE_POLICIES_1", + e.toString())); + setError(req, + CMS.getUserMessage("CMS_POLICY_CERTIFICATE_POLICIES_ERROR"), NAME); + return PolicyResult.REJECTED; + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_ERROR_CERTIFICATE_POLICIES_1", + e.toString())); + setError(req, + CMS.getUserMessage("CMS_POLICY_CERTIFICATE_POLICIES_ERROR"), NAME); + return PolicyResult.REJECTED; + } catch (Exception e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_ERROR_CERTIFICATE_POLICIES_1", + e.toString())); + setError(req, + CMS.getUserMessage("CMS_POLICY_CERTIFICATE_POLICIES_ERROR"), NAME); + return PolicyResult.REJECTED; + } + return PolicyResult.ACCEPTED; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + return mInstanceParams; + } + + /** + * Default config parameters. + * To add more permitted or excluded subtrees, + * increase the num to greater than 0 and more configuration params + * will show up in the console. + */ + private static Vector mDefParams = new Vector(); + static { + mDefParams.addElement(PROP_CRITICAL + "=" + DEF_CRITICAL); + mDefParams.addElement( + PROP_NUM_CERTPOLICIES + "=" + DEF_NUM_CERTPOLICIES); + String certPolicy0Dot = PROP_CERTPOLICY + "0."; + + mDefParams.addElement( + certPolicy0Dot + CertPolicy.PROP_POLICY_IDENTIFIER + "=" + ""); + mDefParams.addElement( + certPolicy0Dot + CertPolicy.PROP_NOTICE_REF_ORG + "=" + ""); + mDefParams.addElement( + certPolicy0Dot + CertPolicy.PROP_NOTICE_REF_NUMS + "=" + ""); + mDefParams.addElement( + certPolicy0Dot + CertPolicy.PROP_USER_NOTICE_TEXT + "=" + ""); + mDefParams.addElement( + certPolicy0Dot + CertPolicy.PROP_CPS_URI + "=" + ""); + + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return mDefParams; + } + + public String[] getExtendedPluginInfo(Locale locale) { + Vector theparams = new Vector(); + + theparams.addElement(PROP_CRITICAL + ";boolean;RFC 3280 recommendation: MUST be non-critical."); + theparams.addElement(PROP_NUM_CERTPOLICIES + ";number; Number of certificate policies. The value must be greater than or equal to 1"); + + for (int k = 0; k < 5; k++) { + String certPolicykDot = PROP_CERTPOLICY + k + "."; + + theparams.addElement(certPolicykDot + + CertPolicy.PROP_POLICY_IDENTIFIER + ";string,required;An object identifier in the form n.n.n.n"); + theparams.addElement(certPolicykDot + + CertPolicy.PROP_NOTICE_REF_ORG + ";string;See RFC 3280 sec 4.2.1.5"); + theparams.addElement(certPolicykDot + + CertPolicy.PROP_NOTICE_REF_NUMS + + ";string;comma-separated list of numbers. See RFC 3280 sec 4.2.1.5"); + theparams.addElement(certPolicykDot + + CertPolicy.PROP_USER_NOTICE_TEXT + ";string;See RFC 3280 sec 4.2.1.5"); + theparams.addElement(certPolicykDot + + CertPolicy.PROP_CPS_URI + ";string;See RFC 3280 sec 4.2.1.5"); + } + + theparams.addElement(IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-certificatepolicies"); + theparams.addElement(IExtendedPluginInfo.HELP_TEXT + + ";Adds Certificate Policies Extension. See RFC 3280 (4.2.1.5)"); + + String[] params = new String[theparams.size()]; + + theparams.copyInto(params); + return params; + } +} + + +class CertPolicy { + + protected static final String PROP_POLICY_IDENTIFIER = "policyId"; + protected static final String PROP_NOTICE_REF_ORG = "noticeRefOrganization"; + protected static final String PROP_NOTICE_REF_NUMS = "noticeRefNumbers"; + protected static final String PROP_USER_NOTICE_TEXT = "userNoticeExplicitText"; + protected static final String PROP_CPS_URI = "cpsURI"; + + protected String mName = null; + protected String mNameDot = null; + protected IConfigStore mConfig = null; + + protected String mPolicyId = null; + protected String mNoticeRefOrg = null; + protected String mNoticeRefNums = null; + protected String mNoticeRefExplicitText = null; + protected String mCpsUri = null; + + protected CertificatePolicyInfo mCertificatePolicyInfo = null; + + /** + * forms policy map parameters. + * @param name name of this policy map, for example certPolicy0 + * @param config parent's config from where we find this configuration. + * @param enabled whether policy was enabled. + */ + protected CertPolicy(String name, IConfigStore config, boolean enabled) + throws EBaseException { + mName = name; + mConfig = config.getSubStore(mName); + mNameDot = mName + "."; + + if( mConfig == null ) { + CMS.debug( "CertificatePoliciesExt::CertPolicy - mConfig is " + + "null!" ); + throw new EBaseException( "mConfig is null" ); + } + + // if there's no configuration for this policy put it there. + if (mConfig.size() == 0) { + config.putString(mNameDot + PROP_POLICY_IDENTIFIER, ""); + config.putString(mNameDot + PROP_NOTICE_REF_ORG, ""); + config.putString(mNameDot + PROP_NOTICE_REF_NUMS, ""); + config.putString(mNameDot + PROP_USER_NOTICE_TEXT, ""); + config.putString(mNameDot + PROP_CPS_URI, ""); + mConfig = config.getSubStore(mName); + if(mConfig == null || mConfig.size() == 0) { + CMS.debug( "CertificatePoliciesExt::CertPolicy - mConfig " + + "is null or empty!" ); + throw new EBaseException( "mConfig is null or empty" ); + } + } + + // get policy ids from configuration. + mPolicyId = mConfig.getString(PROP_POLICY_IDENTIFIER, null); + mNoticeRefOrg = mConfig.getString(PROP_NOTICE_REF_ORG, null); + mNoticeRefNums = mConfig.getString(PROP_NOTICE_REF_NUMS, null); + mNoticeRefExplicitText = mConfig.getString(PROP_USER_NOTICE_TEXT, null); + mCpsUri = mConfig.getString(PROP_CPS_URI, null); + + // adjust for "" and console returning "null" + if (mPolicyId != null && + (mPolicyId.length() == 0 || + mPolicyId.equals("null"))) { + mPolicyId = null; + } + if (mNoticeRefOrg != null && + (mNoticeRefOrg.length() == 0 || + mNoticeRefOrg.equals("null"))) { + mNoticeRefOrg = null; + } + if (mNoticeRefNums != null && + (mNoticeRefNums.length() == 0 || + mNoticeRefNums.equals("null"))) { + mNoticeRefNums = null; + } + if (mNoticeRefExplicitText != null && + (mNoticeRefExplicitText.length() == 0 || + mNoticeRefExplicitText.equals("null"))) { + mNoticeRefExplicitText = null; + } + if (mCpsUri != null && + (mCpsUri.length() == 0 || + mCpsUri.equals("null"))) { + mCpsUri = null; + } + + // policy ids cannot be null if policy is enabled. + String msg = "value cannot be null."; + + if (mPolicyId == null && enabled) + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + mNameDot + PROP_POLICY_IDENTIFIER, msg)); + msg = "NoticeReference is optional; If chosen to include, NoticeReference must at least has 'organization'"; + if (mNoticeRefOrg == null && mNoticeRefNums != null && enabled) + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + mNameDot + PROP_NOTICE_REF_ORG, msg)); + + // if a policy id is not null check that it is a valid OID. + ObjectIdentifier policyId = null; + + if (mPolicyId != null) + policyId = CMS.checkOID( + mNameDot + PROP_POLICY_IDENTIFIER, mPolicyId); + + // if enabled, form CertificatePolicyInfo to be encoded in + // extension. Policy ids should be all set. + if (enabled) { + CMS.debug("CertPolicy: in CertPolicy"); + DisplayText displayText = null; + + if (mNoticeRefExplicitText != null && + !mNoticeRefExplicitText.equals("")) + displayText = new DisplayText(DisplayText.tag_VisibleString, mNoticeRefExplicitText); + // new DisplayText(DisplayText.tag_IA5String, mNoticeRefExplicitText); + DisplayText orgName = null; + + if (mNoticeRefOrg != null && + !mNoticeRefOrg.equals("")) + orgName = + new DisplayText(DisplayText.tag_VisibleString, mNoticeRefOrg); + // new DisplayText(DisplayText.tag_VisibleString, mNoticeRefOrg); + + int[] nums = new int[0];; + if (mNoticeRefNums != null && + !mNoticeRefNums.equals("")) { + + // should add a method to NoticeReference to take a + // Vector...but let's do this for now + + Vector numsVector = new Vector(); + StringTokenizer tokens = new StringTokenizer(mNoticeRefNums, + ","); + + while (tokens.hasMoreTokens()) { + String num = tokens.nextToken().trim(); + + numsVector.addElement(num); + } + + nums = new int[numsVector.size()]; + + for (int i = 0; i < numsVector.size(); i++) { + Integer ii = new Integer((String) numsVector.elementAt(i)); + + nums[i] = ii.intValue(); + } + } + CertificatePolicyId cpolicyId = null; + + try { + cpolicyId = new CertificatePolicyId(ObjectIdentifier.getObjectIdentifier(mPolicyId)); + } catch (Exception e) { + throw new + EBaseException(CMS.getUserMessage("CMS_POLICY_CERTIFICATE_POLICIES_ERROR", mPolicyId)); + } + + PolicyQualifiers policyQualifiers = new PolicyQualifiers(); + + NoticeReference noticeReference = null; + + if (orgName != null) + noticeReference = new NoticeReference(orgName, nums); + + UserNotice userNotice = null; + + if (displayText != null || noticeReference != null) { + userNotice = new UserNotice (noticeReference, displayText); + + PolicyQualifierInfo policyQualifierInfo1 = + new PolicyQualifierInfo(PolicyQualifierInfo.QT_UNOTICE, userNotice); + + policyQualifiers.add(policyQualifierInfo1); + } + + CPSuri cpsUri = null; + + if (mCpsUri != null && mCpsUri.length() > 0) { + cpsUri = new CPSuri (mCpsUri); + PolicyQualifierInfo policyQualifierInfo2 = + new PolicyQualifierInfo(PolicyQualifierInfo.QT_CPS, cpsUri); + + policyQualifiers.add(policyQualifierInfo2); + } + + if ((mNoticeRefOrg == null || mNoticeRefOrg.equals("")) && + (mNoticeRefExplicitText == null || mNoticeRefExplicitText.equals("")) && + (mCpsUri == null || mCpsUri.equals(""))) { + CMS.debug("CertPolicy mNoticeRefOrg = "+mNoticeRefOrg); + CMS.debug("CertPolicy mNoticeRefExplicitText = "+mNoticeRefExplicitText); + CMS.debug("CertPolicy mCpsUri = "+mCpsUri); + + mCertificatePolicyInfo = new CertificatePolicyInfo(cpolicyId); + } else { + CMS.debug("CertPolicy mNoticeRefOrg = "+mNoticeRefOrg); + CMS.debug("CertPolicy mNoticeRefExplicitText = "+mNoticeRefExplicitText); + CMS.debug("CertPolicy mCpsUri = "+mCpsUri); + mCertificatePolicyInfo = new CertificatePolicyInfo(cpolicyId, policyQualifiers); + } + } + } + + protected void getInstanceParams(Vector instanceParams) { + instanceParams.addElement( + mNameDot + PROP_POLICY_IDENTIFIER + "=" + (mPolicyId == null ? "" : + mPolicyId)); + instanceParams.addElement( + mNameDot + PROP_NOTICE_REF_ORG + "=" + (mNoticeRefOrg == null ? "" : + mNoticeRefOrg)); + instanceParams.addElement( + mNameDot + PROP_NOTICE_REF_NUMS + "=" + (mNoticeRefNums == null ? "" : + mNoticeRefNums)); + instanceParams.addElement( + mNameDot + PROP_USER_NOTICE_TEXT + "=" + (mNoticeRefExplicitText == null ? "" : + mNoticeRefExplicitText)); + instanceParams.addElement( + mNameDot + PROP_CPS_URI + "=" + (mCpsUri == null ? "" : + mCpsUri)); + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/CertificateRenewalWindowExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/CertificateRenewalWindowExt.java new file mode 100644 index 000000000..e761ecfab --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/CertificateRenewalWindowExt.java @@ -0,0 +1,247 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.logging.ILogger; +import netscape.security.util.*; +import netscape.security.x509.*; +import netscape.security.extensions.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Certificate Renewal Window Extension Policy + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class CertificateRenewalWindowExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + + protected static final String PROP_END_TIME = "relativeEndTime"; + protected static final String PROP_BEGIN_TIME = "relativeBeginTime"; + protected static final String PROP_CRITICAL = "critical"; + + protected boolean mCritical; + protected String mBeginTime; + protected String mEndTime; + + /** + * Adds the Netscape comment in the end-entity certificates or + * CA certificates. The policy is set to be non-critical with the + * provided OID. + */ + public CertificateRenewalWindowExt() { + NAME = "CertificateRenewalWindowExt"; + DESC = "Sets non-critical Certificate Renewal Window extension in certs"; + } + + /** + * Initializes this policy rule. + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mCritical = config.getBoolean(PROP_CRITICAL, false); + mBeginTime = config.getString(PROP_BEGIN_TIME, null); + mEndTime = config.getString(PROP_END_TIME, null); + + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + PolicyResult res = PolicyResult.ACCEPTED; + + // get cert info. + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; // unrecoverable error. + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult r = applyCert(req, ci[i]); + + if (r == PolicyResult.REJECTED) + return r; + } + return res; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + + CertificateExtensions extensions = null; + + try { + extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + } catch (IOException e) { + } catch (CertificateException e) { + } + + if (extensions == null) { + extensions = new CertificateExtensions(); + try { + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } catch (Exception e) { + } + } else { + // remove any previously computed version of the extension + try { + extensions.delete(CertificateRenewalWindowExtension.NAME); + + } catch (IOException e) { + // this is the hack: for some reason, the key which is the name + // of the policy has been converted into the OID + try { + extensions.delete("2.16.840.1.113730.1.15"); + } catch (IOException ee) { + } + } + } + + try { + Date now = CMS.getCurrentDate(); + CertificateRenewalWindowExtension crwExt = null; + + if (mEndTime == null || mEndTime.equals("")) { + crwExt = new CertificateRenewalWindowExtension( + mCritical, + getDateValue(now, mBeginTime), + null); + } else { + crwExt = new CertificateRenewalWindowExtension( + mCritical, + getDateValue(now, mBeginTime), + getDateValue(now, mEndTime)); + } + extensions.set(CertificateRenewalWindowExtension.NAME, + crwExt); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_CERTIFICATE_POLICIES_1", NAME)); + setError(req, + CMS.getUserMessage("CMS_POLICY_CERTIFICATE_POLICIES_ERROR"), NAME); + return PolicyResult.REJECTED; + } + return PolicyResult.ACCEPTED; + } + + public Date getDateValue(Date relativeFrom, String s) { + long time; + + if (s.endsWith("s")) { + time = 1000 * Long.parseLong(s.substring(0, + s.length() - 1)); + } else if (s.endsWith("m")) { + time = 60 * 1000 * Long.parseLong(s.substring(0, + s.length() - 1)); + } else if (s.endsWith("h")) { + time = 60 * 60 * 1000 * Long.parseLong(s.substring(0, + s.length() - 1)); + } else if (s.endsWith("D")) { + time = 24 * 60 * 60 * 1000 * Long.parseLong( + s.substring(0, s.length() - 1)); + } else if (s.endsWith("M")) { + time = 30 * 60 * 60 * 1000 * Long.parseLong( + s.substring(0, s.length() - 1)); + } else { + time = 1000 * Long.parseLong(s); + } + + return new Date(relativeFrom.getTime() + time); + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_CRITICAL + ";boolean;Netscape recommendation: non-critical.", + PROP_BEGIN_TIME + ";string;Start Time in seconds (Relative to the time of issuance). Optionally, time unit (s - seconds, m - minutes, h - hours, D - days, M - months) can be specified right after the value. For example, 5 days can be expressed as 5D.", + PROP_END_TIME + ";string;End Time in seconds (Optional, Relative to the time of issuance). Optionally, time unit (s - seconds, m - minutes, h - hours, D - days, M - months) can be specified right after the value. For example, 5 days can be expressed as 5D.", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-certificaterenewalwindow", + IExtendedPluginInfo.HELP_TEXT + + ";Adds 'Certificate Renewal Window' extension. See manual" + }; + + return params; + + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector params = new Vector(); + + params.addElement(PROP_CRITICAL + "=" + mCritical); + if (mBeginTime == null) { + params.addElement(PROP_BEGIN_TIME + "="); + } else { + params.addElement(PROP_BEGIN_TIME + "=" + mBeginTime); + } + if (mEndTime == null) { + params.addElement(PROP_END_TIME + "="); + } else { + params.addElement(PROP_END_TIME + "=" + mEndTime); + } + return params; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + Vector defParams = new Vector(); + + defParams.addElement(PROP_CRITICAL + "=false"); + defParams.addElement(PROP_BEGIN_TIME + "="); + defParams.addElement(PROP_END_TIME + "="); + return defParams; + } +} diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/CertificateScopeOfUseExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/CertificateScopeOfUseExt.java new file mode 100644 index 000000000..a8d5f8a0c --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/CertificateScopeOfUseExt.java @@ -0,0 +1,320 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.logging.ILogger; +import netscape.security.x509.*; +import netscape.security.extensions.*; +import netscape.ldap.*; +import netscape.security.util.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Certificate Scope Of Use extension policy. This extension + * is defined in draft-thayes-cert-scope-00.txt + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class CertificateScopeOfUseExt extends APolicyRule implements + IEnrollmentPolicy, IExtendedPluginInfo { + protected static final String PROP_CRITICAL = + "critical"; + protected static final String PROP_ENTRY = + "entry"; + protected static final String PROP_NAME = + "name"; + protected static final String PROP_NAME_TYPE = + "name_type"; + protected static final String PROP_PORT_NUMBER = + "port_number"; + + public static final int MAX_ENTRY = 5; + + public IConfigStore mConfig = null; + + public CertificateScopeOfUseExt() { + NAME = "CertificateScopeOfUseExt"; + DESC = "Sets scope of use extension for certificates"; + } + + public String[] getExtendedPluginInfo(Locale locale) { + Vector v = new Vector(); + + v.addElement(PROP_CRITICAL + + ";boolean; This extension may be either critical or non-critical."); + v.addElement(IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-certificatescopeofuse"); + v.addElement(IExtendedPluginInfo.HELP_TEXT + + ";Adds Certificate Scope of Use Extension."); + + for (int i = 0; i < MAX_ENTRY; i++) { + v.addElement(PROP_ENTRY + Integer.toString(i) + "_" + PROP_NAME + ";" + IGeneralNameUtil.GENNAME_VALUE_INFO); + v.addElement(PROP_ENTRY + Integer.toString(i) + "_" + PROP_NAME_TYPE + ";" + IGeneralNameUtil.GENNAME_CHOICE_INFO); + v.addElement(PROP_ENTRY + Integer.toString(i) + "_" + PROP_PORT_NUMBER + ";string;" + "The port number (optional)."); + } + return com.netscape.cmsutil.util.Utils.getStringArrayFromVector(v); + } + + /** + * Initializes this policy rule. + *

+ * + * The entries may be of the form: + * + * ca.Policy.rule..implName=AuthInfoAccessExt + * ca.Policy.rule..enable=true + * ca.Policy.rule..predicate= + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + } + + /** + * Returns a sequence of scope entry. + */ + private Vector getScopeEntries() throws EBaseException { + Vector entries = new Vector(); + + // + // read until there is *NO* ad_method + // + for (int i = 0;; i++) { + // get port number (optional) + String port = mConfig.getString(PROP_ENTRY + + Integer.toString(i) + "_" + PROP_PORT_NUMBER, null); + BigInt portNumber = null; + + if (port != null && !port.equals("")) { + portNumber = new BigInt(Integer.parseInt(port)); + } + + // + // location ::= : + // TAG ::= uriName | dirName + // VALUE ::= [value defined by TAG] + // + String name_type = mConfig.getString(PROP_ENTRY + + Integer.toString(i) + + "_" + PROP_NAME_TYPE, null); + String name = mConfig.getString(PROP_ENTRY + + Integer.toString(i) + + "_" + PROP_NAME, null); + + if (name == null || name.equals("")) + break; + GeneralName gn = CMS.form_GeneralNameAsConstraints(name_type, name); + + entries.addElement(new CertificateScopeEntry(gn, portNumber)); + } + return entries; + } + + /** + * If this policy is enabled, add the authority information + * access extension to the certificate. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + PolicyResult res = PolicyResult.ACCEPTED; + + X509CertInfo certInfo; + X509CertInfo[] ci = req.getExtDataInCertInfoArray( + IRequest.CERT_INFO); + + if (ci == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; // unrecoverable error. + } + + for (int j = 0; j < ci.length; j++) { + + certInfo = ci[j]; + if (certInfo == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CA_CERT_INFO_ERROR", NAME)); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Configuration Info Error"); + return PolicyResult.REJECTED; // unrecoverable error. + } + + try { + // Find the extensions in the certInfo + CertificateExtensions extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + + // add access descriptions + Vector entries = getScopeEntries(); + + if (entries.size() == 0) { + return res; + } + + if (extensions == null) { + // create extension if not exist + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } else { + // check to see if AIA is already exist + try { + extensions.delete(CertificateScopeOfUseExtension.NAME); + log(ILogger.LL_INFO, "Previous extension deleted: " + CertificateScopeOfUseExtension.NAME); + } catch (IOException ex) { + } + } + + // Create the extension + CertificateScopeOfUseExtension suExt = new + CertificateScopeOfUseExtension(mConfig.getBoolean( + PROP_CRITICAL, false), entries); + + extensions.set(CertificateScopeOfUseExtension.NAME, suExt); + + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("BASE_IO_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, e.getMessage()); + return PolicyResult.REJECTED; // unrecoverable error. + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, + "Configuration Info Error encountered: " + + e.getMessage()); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Configuration Info Error"); + return PolicyResult.REJECTED; // unrecoverable error. + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CA_CERT_INFO_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Certificate Info Error"); + return PolicyResult.REJECTED; // unrecoverable error. + } + } + + return res; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector params = new Vector(); + + try { + params.addElement(PROP_CRITICAL + "=" + + mConfig.getBoolean(PROP_CRITICAL, false)); + } catch (EBaseException e) { + } + + for (int i = 0;; i++) { + String name_type = null; + + try { + name_type = mConfig.getString(PROP_ENTRY + + Integer.toString(i) + "_" + PROP_NAME_TYPE, + null); + } catch (EBaseException e) { + } + if (name_type == null) + break; + params.addElement(PROP_ENTRY + + Integer.toString(i) + + "_" + PROP_NAME_TYPE + "=" + name_type); + String name = null; + + try { + name = mConfig.getString(PROP_ENTRY + + Integer.toString(i) + "_" + PROP_NAME, + null); + } catch (EBaseException e) { + } + if (name == null) + break; + params.addElement(PROP_ENTRY + + Integer.toString(i) + + "_" + PROP_NAME + "=" + name); + String port = null; + + try { + port = mConfig.getString(PROP_ENTRY + + Integer.toString(i) + "_" + PROP_PORT_NUMBER, + ""); + } catch (EBaseException e) { + } + params.addElement(PROP_ENTRY + + Integer.toString(i) + + "_" + PROP_PORT_NUMBER + "=" + port); + } + return params; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + Vector defParams = new Vector(); + + defParams.addElement(PROP_CRITICAL + "=false"); + + // + // By default, we create MAX_AD access descriptions. + // If this is not enough, admin can manually edit + // the CMS.cfg + // + for (int i = 0; i < MAX_ENTRY; i++) { + defParams.addElement(PROP_ENTRY + Integer.toString(i) + + "_" + PROP_NAME_TYPE + "="); + defParams.addElement(PROP_ENTRY + Integer.toString(i) + + "_" + PROP_NAME + "="); + defParams.addElement(PROP_ENTRY + Integer.toString(i) + + "_" + PROP_PORT_NUMBER + "="); + } + return defParams; + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/ExtendedKeyUsageExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/ExtendedKeyUsageExt.java new file mode 100644 index 000000000..783ab2b6e --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/ExtendedKeyUsageExt.java @@ -0,0 +1,271 @@ +// --- 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.cms.policy.extensions; + + +import com.netscape.certsrv.request.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.apps.*; +import netscape.security.x509.*; +import netscape.security.extensions.*; +import netscape.security.util.*; +import java.security.cert.*; +import java.io.*; +import java.util.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * This implements the extended key usage extension. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class ExtendedKeyUsageExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + public static final String PROP_CRITICAL = "critical"; + protected static final String PROP_PURPOSE_ID = "id"; + protected static final String PROP_NUM_IDS = "numIds"; + protected static int MAX_PURPOSE_ID = 10; + private boolean mCritical = false; + private IConfigStore mConfig = null; + private Vector mUsages = null; + + private String[] mParams = null; + + // PKIX specifies the that the extension SHOULD NOT be critical + public static final boolean DEFAULT_CRITICALITY = false; + + private ExtendedKeyUsageExtension mExtendedKeyUsage = null; + + /** + * Constructs extended Key Usage extension. + */ + public ExtendedKeyUsageExt() { + NAME = "ExtendedKeyUsageExt"; + DESC = "Sets ExtendedKeyUsage extension for certificates"; + } + + /** + * Performs one-time initialization of the policy. + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + setExtendedPluginInfo(); + setupParams(); + mExtendedKeyUsage = new ExtendedKeyUsageExtension(mCritical, mUsages); + } + + /** + * Applies the policy to the given request. + */ + public PolicyResult apply(IRequest req) { + + // if the extension was not configured correctly, just skip it + if (mExtendedKeyUsage == null) { + return PolicyResult.ACCEPTED; + } + + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult certRes = applyCert(req, ci[i]); + + if (certRes == PolicyResult.REJECTED) + return certRes; + } + return PolicyResult.ACCEPTED; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + try { + // find the extensions in the certInfo + CertificateExtensions extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + + // prepare the extensions data structure + if (extensions == null) { + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } else { + try { + extensions.delete(ExtendedKeyUsageExtension.NAME); + } catch (IOException ex) { + // ExtendedKeyUsage extension is not already there + } + } + + extensions.set(ExtendedKeyUsageExtension.NAME, mExtendedKeyUsage); + + return PolicyResult.ACCEPTED; + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("BASE_IO_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), NAME, + e.getMessage()); + return PolicyResult.REJECTED; + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CERT_INFO_ERROR", + e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), NAME, + e.getMessage()); + return PolicyResult.REJECTED; + } + } + + /** + * Returns instance specific parameters. + */ + public Vector getInstanceParams() { + Vector params = new Vector(); + + params.addElement(PROP_CRITICAL + "=" + mCritical); + int numIds = MAX_PURPOSE_ID; + + try { + numIds = mConfig.getInteger(PROP_NUM_IDS, MAX_PURPOSE_ID); + } catch (EBaseException e) { + } + params.addElement(PROP_NUM_IDS + "=" + numIds); + String usage = null; + + for (int i = 0; i < numIds; i++) { + if (mUsages.size() <= i) { + params.addElement(PROP_PURPOSE_ID + + Integer.toString(i) + "="); + } else { + usage = ((ObjectIdentifier) mUsages.elementAt(i)).toString(); + if (usage == null) { + params.addElement(PROP_PURPOSE_ID + + Integer.toString(i) + "="); + } else { + params.addElement(PROP_PURPOSE_ID + + Integer.toString(i) + "=" + usage); + } + } + } + return params; + } + + private void setExtendedPluginInfo() { + Vector v = new Vector(); + int mNum = MAX_PURPOSE_ID; + + if (mConfig != null) { + try { + mConfig.getInteger(PROP_NUM_IDS, MAX_PURPOSE_ID); + } catch (EBaseException e) { + } + } + for (int i = 0; i < mNum; i++) { + v.addElement(PROP_PURPOSE_ID + Integer.toString(i) + ";string;" + + "A unique,valid OID specified in dot-separated numeric component notation. e.g. 2.16.840.1.113730.1.99"); + } + + v.addElement(PROP_NUM_IDS + ";number;The total number of policy IDs."); + v.addElement(PROP_CRITICAL + + ";boolean;RFC 2459 recommendation: This extension may, at the option of the certificate issuer, be either critical or non-critical."); + v.addElement(IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-extendedkeyusage"); + v.addElement(IExtendedPluginInfo.HELP_TEXT + + ";Adds Extended Key Usage Extension. Defined in RFC 2459 " + + "(4.2.1.13)"); + + mParams = com.netscape.cmsutil.util.Utils.getStringArrayFromVector(v); + } + + public String[] getExtendedPluginInfo(Locale locale) { + if (mParams == null) { + setExtendedPluginInfo(); + } + return mParams; + } + + /** + * Returns default parameters. + */ + public Vector getDefaultParams() { + Vector defParams = new Vector(); + + defParams.addElement(PROP_CRITICAL + "=false"); + defParams.addElement(PROP_NUM_IDS + "=" + MAX_PURPOSE_ID); + for (int i = 0; i < MAX_PURPOSE_ID; i++) { + defParams.addElement(PROP_PURPOSE_ID + Integer.toString(i) + "="); + } + return defParams; + } + + /** + * Setups parameters. + */ + private void setupParams() throws EBaseException { + + mCritical = mConfig.getBoolean(PROP_CRITICAL, false); + if (mUsages == null) { + mUsages = new Vector(); + } + + int mNum = mConfig.getInteger(PROP_NUM_IDS, MAX_PURPOSE_ID); + + for (int i = 0; i < mNum; i++) { + ObjectIdentifier usageOID = null; + + String usage = mConfig.getString(PROP_PURPOSE_ID + + Integer.toString(i), null); + + try { + + if (usage == null) break; + usage = usage.trim(); + if (usage.equals("")) break; + if (usage.equalsIgnoreCase("ocspsigning")) { + usageOID = ObjectIdentifier.getObjectIdentifier(ExtendedKeyUsageExtension.OID_OCSPSigning); + } else if (usage.equalsIgnoreCase("codesigning")) { + usageOID = ObjectIdentifier.getObjectIdentifier(ExtendedKeyUsageExtension.OID_CODESigning); + } else { + // it could be an object identifier, test it + usageOID = ObjectIdentifier.getObjectIdentifier(usage); + } + } catch (IOException ex) { + throw new EBaseException(this.getClass().getName() + ":" + + ex.getMessage()); + } catch (NumberFormatException ex) { + throw new EBaseException(this.getClass().getName() + ":" + + "OID '" + usage + "' format error"); + } + mUsages.addElement(usageOID); + } + } +} diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/GenericASN1Ext.java b/pki/base/common/src/com/netscape/cms/policy/extensions/GenericASN1Ext.java new file mode 100644 index 000000000..9a07cb020 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/GenericASN1Ext.java @@ -0,0 +1,471 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.text.ParseException; +import java.security.cert.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.logging.ILogger; +import netscape.ldap.*; +import netscape.security.x509.*; +import netscape.security.extensions.*; +import netscape.security.util.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Private Integer extension policy. + * If this policy is enabled, it adds an Private Integer + * extension to the certificate. + * + * The following listed sample configuration parameters: + * + * ca.Policy.impl.privateInteger.class=com.netscape.certsrv.policy.genericASNExt + * ca.Policy.rule.genericASNExt.enable=true + * ca.Policy.rule.genericASNExt.name=myIntegerExtension + * ca.Policy.rule.genericASNExt.pattern={{{12}34}5} + * ca.Policy.rule.genericASNExt.oid=280.230.123.1234.1 + * ca.Policy.rule.genericASNExt.critical=false + * ca.Policy.rule.genericASNExt.attribute1.type=integer + * ca.Policy.rule.genericASNExt.attribute1.source=value + * ca.Policy.rule.genericASNExt.attribute1.value=9999 + * ca.Policy.rule.genericASNExt.attribute2.type=ia5string + * ca.Policy.rule.genericASNExt.attribute2.source=value + * ca.Policy.rule.genericASNExt.attribute2.value=hello + * ca.Policy.rule.genericASNExt.attribute3.type=octetstring + * ca.Policy.rule.genericASNExt.attribute3.source=value + * ca.Policy.rule.genericASNExt.attribute3.value=hellohello + * ca.Policy.rule.genericASNExt.attribute4.type=octetstring + * ca.Policy.rule.genericASNExt.attribute4.source=file + * ca.Policy.rule.genericASNExt.attribute4.value=c:/tmp/test.txt + * ca.Policy.rule.genericASNExt.attribute5.type= + * ca.Policy.rule.genericASNExt.attribute5.source= + * ca.Policy.rule.genericASNExt.attribute5.value= + * ca.Policy.rule.genericASNExt.implName=genericASNExt + * ca.Policy.rule.genericASNExt.predicate= + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class GenericASN1Ext extends APolicyRule implements + IEnrollmentPolicy, IExtendedPluginInfo { + protected static final int MAX_ATTR = 10; + + protected static final String PROP_CRITICAL = + "critical"; + protected static final String PROP_NAME = + "name"; + protected static final String PROP_OID = + "oid"; + protected static final String PROP_PATTERN = + "pattern"; + protected static final String PROP_ATTRIBUTE = + "attribute"; + protected static final String PROP_TYPE = + "type"; + protected static final String PROP_SOURCE = + "source"; + protected static final String PROP_VALUE = + "value"; + protected static final String PROP_PREDICATE = + "predicate"; + + protected static final String PROP_ENABLE = + "enable"; + + public IConfigStore mConfig = null; + + private String pattern = null; + + public String[] getExtendedPluginInfo(Locale locale) { + String s[] = { + "enable" + ";boolean;Enable this policy", + "predicate" + ";string;", + PROP_CRITICAL + ";boolean;", + PROP_NAME + ";string;Name for this extension.", + PROP_OID + ";string;OID number for this extension. It should be unique.", + PROP_PATTERN + ";string;Pattern for extension; {012}34", + // Attribute 0 + PROP_ATTRIBUTE + "." + "0" + "." + PROP_TYPE + ";choice(Integer,IA5String,OctetString,PrintableString,VisibleString,UTCTime,OID,Boolean);Attribute type for extension", + PROP_ATTRIBUTE + "." + "0" + "." + PROP_SOURCE + ";choice(Value,File);Data Source for the extension. You can specify the value here or file name has value.", + PROP_ATTRIBUTE + "." + "0" + "." + PROP_VALUE + ";string;If data source is 'value', specity value here. If data source is 'file', specify the file name with full path.", + // Attribute 1 + PROP_ATTRIBUTE + "." + "1" + "." + PROP_TYPE + ";choice(Integer,IA5String,OctetString,PrintableString,VisibleString,UTCTime,OID,Boolean);Attribute type for extension", + PROP_ATTRIBUTE + "." + "1" + "." + PROP_SOURCE + ";choice(Value,File);Data Source for the extension. You can specify the value here or file name has value.", + PROP_ATTRIBUTE + "." + "1" + "." + PROP_VALUE + ";string;If data source is 'value', specity value here. If data source is 'file', specify the file name with full path.", + // Attribute 2 + PROP_ATTRIBUTE + "." + "2" + "." + PROP_TYPE + ";choice(Integer,IA5String,OctetString,PrintableString,VisibleString,UTCTime,OID,Boolean);Attribute type for extension", + PROP_ATTRIBUTE + "." + "2" + "." + PROP_SOURCE + ";choice(Value,File);Data Source for the extension. You can specify the value here or file name has value.", + PROP_ATTRIBUTE + "." + "2" + "." + PROP_VALUE + ";string;If data source is 'value', specity value here. If data source is 'file', specify the file name with full path.", + // Attribute 3 + PROP_ATTRIBUTE + "." + "3" + "." + PROP_TYPE + ";choice(Integer,IA5String,OctetString,PrintableString,VisibleString,UTCTime,OID,Boolean);Attribute type for extension", + PROP_ATTRIBUTE + "." + "3" + "." + PROP_SOURCE + ";choice(Value,File);Data Source for the extension. You can specify the value here or file name has value.", + PROP_ATTRIBUTE + "." + "3" + "." + PROP_VALUE + ";string;If data source is 'value', specity value here. If data source is 'file', specify the file name with full path.", + // Attribute 4 + PROP_ATTRIBUTE + "." + "4" + "." + PROP_TYPE + ";choice(Integer,IA5String,OctetString,PrintableString,VisibleString,UTCTime,OID,Boolean);Attribute type for extension", + PROP_ATTRIBUTE + "." + "4" + "." + PROP_SOURCE + ";choice(Value,File);Data Source for the extension. You can specify the value here or file name has value.", + PROP_ATTRIBUTE + "." + "4" + "." + PROP_VALUE + ";string;If data source is 'value', specity value here. If data source is 'file', specify the file name with full path.", + // Attribute 5 + PROP_ATTRIBUTE + "." + "5" + "." + PROP_TYPE + ";choice(Integer,IA5String,OctetString,PrintableString,VisibleString,UTCTime,OID,Boolean);Attribute type for extension", + PROP_ATTRIBUTE + "." + "5" + "." + PROP_SOURCE + ";choice(Value,File);Data Source for the extension. You can specify the value here or file name has value.", + PROP_ATTRIBUTE + "." + "5" + "." + PROP_VALUE + ";string;If data source is 'value', specity value here. If data source is 'file', specify the file name with full path.", + // Attribute 6 + PROP_ATTRIBUTE + "." + "6" + "." + PROP_TYPE + ";choice(Integer,IA5String,OctetString,PrintableString,VisibleString,UTCTime,OID,Boolean);Attribute type for extension", + PROP_ATTRIBUTE + "." + "6" + "." + PROP_SOURCE + ";choice(Value,File);Data Source for the extension. You can specify the value here or file name has value.", + PROP_ATTRIBUTE + "." + "6" + "." + PROP_VALUE + ";string;If data source is 'value', specity value here. If data source is 'file', specify the file name with full path.", + // Attribute 7 + PROP_ATTRIBUTE + "." + "7" + "." + PROP_TYPE + ";choice(Integer,IA5String,OctetString,PrintableString,VisibleString,UTCTime,OID,Boolean);Attribute type for extension", + PROP_ATTRIBUTE + "." + "7" + "." + PROP_SOURCE + ";choice(Value,File);Data Source for the extension. You can specify the value here or file name has value.", + PROP_ATTRIBUTE + "." + "7" + "." + PROP_VALUE + ";string;If data source is 'value', specity value here. If data source is 'file', specify the file name with full path.", + // Attribute 8 + PROP_ATTRIBUTE + "." + "8" + "." + PROP_TYPE + ";choice(Integer,IA5String,OctetString,PrintableString,VisibleString,UTCTime,OID,Boolean);Attribute type for extension", + PROP_ATTRIBUTE + "." + "8" + "." + PROP_SOURCE + ";choice(Value,File);Data Source for the extension. You can specify the value here or file name has value.", + PROP_ATTRIBUTE + "." + "8" + "." + PROP_VALUE + ";string;If data source is 'value', specity value here. If data source is 'file', specify the file name with full path.", + // Attribute 9 + PROP_ATTRIBUTE + "." + "9" + "." + PROP_TYPE + ";choice(Integer,IA5String,OctetString,PrintableString,VisibleString,UTCTime,OID,Boolean);Attribute type for extension", + PROP_ATTRIBUTE + "." + "9" + "." + PROP_SOURCE + ";choice(Value,File);Data Source for the extension. You can specify the value here or file name has value.", + PROP_ATTRIBUTE + "." + "9" + "." + PROP_VALUE + ";string;If data source is 'value', specity value here. If data source is 'file', specify the file name with full path.", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-genericasn1ext", + IExtendedPluginInfo.HELP_TEXT + + ";Adds Private extension based on ASN1. See manual" + }; + + return s; + } + + public GenericASN1Ext() { + NAME = "GenericASN1Ext"; + DESC = "Sets Generic extension for certificates"; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries may be of the form: + * + * ca.Policy.rule..implName=genericASNExt + * ca.Policy.rule..enable=true + * ca.Policy.rule..predicate= + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + if (mConfig == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_INIT_ERROR")); + return; + } + + boolean enable = mConfig.getBoolean(PROP_ENABLE, false); + + if (enable == false) + return; + + String oid = mConfig.getString(PROP_OID, null); + + if ((oid == null) || (oid.length() == 0)) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_INIT_ERROR")); + return; + } + + String name = mConfig.getString(PROP_NAME, null); + + if ((name == null) || (name.length() == 0)) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_INIT_ERROR")); + return; + } + + try { + if (File.separatorChar == '\\') { + pattern = mConfig.getString(PROP_PATTERN, null); + checkFilename(0); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, "" + e.toString()); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, "" + e.toString()); + } + + // Check OID value + CMS.checkOID(name, oid); + pattern = mConfig.getString(PROP_PATTERN, null); + checkOID(0); + + try { + ObjectIdentifier tmpid = new ObjectIdentifier(oid); + + if (OIDMap.getName(tmpid) == null) + OIDMap.addAttribute("netscape.security.extensions.GenericASN1Extension", oid, name); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, "" + e.toString()); + } + + } + + // Check filename + private int checkFilename(int index) + throws IOException, EBaseException { + String source = null; + + while (index < pattern.length()) { + char ch = pattern.charAt(index); + + switch (ch) { + case '{': + index++; + index = checkFilename(index); + break; + + case '}': + return index; + + default: + source = mConfig.getString(PROP_ATTRIBUTE + "." + ch + "." + PROP_SOURCE, null); + if ((source != null) && (source.equalsIgnoreCase("file"))) { + String oValue = mConfig.getString(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE, null); + String nValue = oValue.replace('\\', '/'); + + mConfig.putString(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE, nValue); + FileInputStream fis = new FileInputStream(nValue); + fis.close(); + } + } + index++; + } + + return index; + } + + // Check oid + private int checkOID(int index) + throws EBaseException { + String type = null; + String oid = null; + + while (index < pattern.length()) { + char ch = pattern.charAt(index); + + switch (ch) { + case '{': + index++; + index = checkOID(index); + break; + + case '}': + return index; + + default: + type = mConfig.getString(PROP_ATTRIBUTE + "." + ch + "." + PROP_TYPE, null); + if ((type != null) && (type.equalsIgnoreCase("OID"))) { + oid = mConfig.getString(PROP_ATTRIBUTE + "." + ch + "." + PROP_VALUE, null); + CMS.checkOID(oid, oid); + } + } + index++; + } + + return index; + } + + /** + * If this policy is enabled, add the private Integer + * information extension to the certificate. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + PolicyResult res = PolicyResult.ACCEPTED; + X509CertInfo certInfo; + X509CertInfo[] ci = req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; // unrecoverable error. + } + + for (int j = 0; j < ci.length; j++) { + + certInfo = ci[j]; + if (certInfo == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CERT_INFO_ERROR", "")); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), NAME, "Configuration Info Error"); + return PolicyResult.REJECTED; // unrecoverable error. + } + + try { + // Find the extensions in the certInfo + CertificateExtensions extensions = (CertificateExtensions) certInfo.get(X509CertInfo.EXTENSIONS); + + if (extensions == null) { + // create extension if not exist + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } else { + // + // Remove any previousely computed extension + // + try { + extensions.delete(mConfig.getString(PROP_NAME, "")); + } catch (Exception e) {/* extension isn't there */ + } + } + + // Create the extension + GenericASN1Extension priExt = mkExtension(); + + extensions.set(GenericASN1Extension.NAME, priExt); + + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("BASE_IO_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, e.getMessage()); + return PolicyResult.REJECTED; // unrecoverable error. + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CERT_INFO_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Configuration Info Error"); + return PolicyResult.REJECTED; // unrecoverable error. + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CERT_INFO_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Certificate Info Error"); + return PolicyResult.REJECTED; // unrecoverable error. + } catch (ParseException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("BASE_EXTENSION_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Pattern parsing error"); + return PolicyResult.REJECTED; // unrecoverable error. + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("BASE_UNKNOWN_EXCEPTION", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Unknown Error"); + return PolicyResult.REJECTED; // unrecoverable error. + } + } + return res; + } + + /** + * Construct GenericASN1Extension with value from CMS.cfg + */ + protected GenericASN1Extension mkExtension() + throws IOException, EBaseException, ParseException { + GenericASN1Extension ext; + + Hashtable h = new Hashtable(); + // This only show one level, not substores! + Enumeration e = mConfig.getPropertyNames(); + + while (e.hasMoreElements()) { + String n = (String) e.nextElement(); + + h.put(n, mConfig.getString(n)); + } + for (int idx = 0; idx < MAX_ATTR; idx++) { + String proptype = PROP_ATTRIBUTE + "." + idx + "." + PROP_TYPE; + String propsource = PROP_ATTRIBUTE + "." + idx + "." + PROP_SOURCE; + String propvalue = PROP_ATTRIBUTE + "." + idx + "." + PROP_VALUE; + + h.put(proptype, mConfig.getString(proptype, null)); + h.put(propsource, mConfig.getString(propsource, null)); + h.put(propvalue, mConfig.getString(propvalue, null)); + } + ext = new GenericASN1Extension(h); + return ext; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + int idx = 0; + Vector params = new Vector(); + + try { + params.addElement(PROP_CRITICAL + "=" + mConfig.getBoolean(PROP_CRITICAL, false)); + params.addElement(PROP_NAME + "=" + mConfig.getString(PROP_NAME, null)); + params.addElement(PROP_OID + "=" + mConfig.getString(PROP_OID, null)); + params.addElement(PROP_PATTERN + "=" + mConfig.getString(PROP_PATTERN, null)); + + for (idx = 0; idx < MAX_ATTR; idx++) { + String proptype = PROP_ATTRIBUTE + "." + idx + "." + PROP_TYPE; + String propsource = PROP_ATTRIBUTE + "." + idx + "." + PROP_SOURCE; + String propvalue = PROP_ATTRIBUTE + "." + idx + "." + PROP_VALUE; + + params.addElement(proptype + "=" + mConfig.getString(proptype, null)); + params.addElement(propsource + "=" + mConfig.getString(propsource, null)); + params.addElement(propvalue + "=" + mConfig.getString(propvalue, null)); + } + params.addElement(PROP_PREDICATE + "=" + mConfig.getString(PROP_PREDICATE, null)); + } catch (EBaseException e) {; + } + + return params; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + int idx = 0; + + Vector defParams = new Vector(); + + defParams.addElement(PROP_CRITICAL + "=false"); + defParams.addElement(PROP_NAME + "="); + defParams.addElement(PROP_OID + "="); + defParams.addElement(PROP_PATTERN + "="); + + for (idx = 0; idx < MAX_ATTR; idx++) { + defParams.addElement(PROP_ATTRIBUTE + "." + idx + "." + PROP_TYPE + "="); + defParams.addElement(PROP_ATTRIBUTE + "." + idx + "." + PROP_SOURCE + "="); + defParams.addElement(PROP_ATTRIBUTE + "." + idx + "." + PROP_VALUE + "="); + } + + return defParams; + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/IssuerAltNameExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/IssuerAltNameExt.java new file mode 100644 index 000000000..240076c95 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/IssuerAltNameExt.java @@ -0,0 +1,252 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.net.*; +import java.security.cert.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.authority.*; +import com.netscape.certsrv.logging.ILogger; +import netscape.security.x509.*; +import netscape.security.util.*; +import netscape.ldap.*; +import com.netscape.certsrv.ra.*; +import com.netscape.certsrv.ca.*; +import java.util.StringTokenizer; +import netscape.security.util.DerValue; +import java.util.Enumeration; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Issuer Alt Name Extension policy. + * + * This extension is used to associate Internet-style identities + * with the Certificate issuer. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class IssuerAltNameExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + public static final String PROP_CRITICAL = "critical"; + + // PKIX specifies the that the extension SHOULD NOT be critical + public static final boolean DEFAULT_CRITICALITY = false; + + private static Vector defaultParams = new Vector(); + private static String[] mInfo = null; + + static { + defaultParams.addElement(PROP_CRITICAL + "=" + DEFAULT_CRITICALITY); + CMS.getGeneralNamesConfigDefaultParams(null, true, defaultParams); + + Vector info = new Vector(); + + info.addElement(PROP_CRITICAL + ";boolean;RFC 2459 recommendation: SHOULD NOT be marked critical."); + info.addElement(IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-issueraltname"); + info.addElement(IExtendedPluginInfo.HELP_TEXT + + ";This policy inserts the Issuer Alternative Name " + + "Extension into the certificate. See RFC 2459 (4.2.1.8). "); + + CMS.getGeneralNamesConfigExtendedPluginInfo(null, true, info); + + mInfo = new String[info.size()]; + info.copyInto(mInfo); + } + + private Vector mParams = new Vector(); + private IConfigStore mConfig = null; + private boolean mCritical = DEFAULT_CRITICALITY; + private boolean mEnabled = false; + IGeneralNamesConfig mGNs = null; + IssuerAlternativeNameExtension mExtension = null; + + /** + * Adds the issuer alternate name extension to all certs. + */ + public IssuerAltNameExt() { + NAME = "IssuerAltNameExt"; + DESC = "Associate Internet-style Identities with Issuer"; + } + + /** + * Initializes this policy rule. + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + + // get criticality + mCritical = mConfig.getBoolean(PROP_CRITICAL, DEFAULT_CRITICALITY); + + // get enabled. + mEnabled = mConfig.getBoolean( + IPolicyProcessor.PROP_ENABLE, false); + + // form general names. + mGNs = CMS.createGeneralNamesConfig(null, config, true, mEnabled); + + // form extension + try { + if (mEnabled && + mGNs.getGeneralNames() != null && !mGNs.getGeneralNames().isEmpty()) { + mExtension = + new IssuerAlternativeNameExtension( + Boolean.valueOf(mCritical), mGNs.getGeneralNames()); + } + } catch (Exception e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString())); + } + + // init instance params + mParams.addElement(PROP_CRITICAL + "=" + mCritical); + mGNs.getInstanceParams(mParams); + + return; + } + + /** + * Adds a extension if none exists. + * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + PolicyResult res = PolicyResult.ACCEPTED; + + if (mEnabled == false || mExtension == null) + return res; + + // get cert info. + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + X509CertInfo certInfo = null; + + if (ci == null || (certInfo = ci[0]) == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; // unrecoverable error. + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult certRes = applyCert(req, ci[i]); + + if (certRes == PolicyResult.REJECTED) + return certRes; + } + return PolicyResult.ACCEPTED; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + + // get extension from cert info if any. + CertificateExtensions extensions = null; + + try { + // get extension if any. + extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + } catch (IOException e) { + // no extensions. + } catch (CertificateException e) { + // no extension. + } + + if (extensions == null) { + extensions = new CertificateExtensions(); + try { + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } catch (CertificateException e) { + // not possible + } catch (Exception e) { + } + } else { + + // remove any previously computed version of the extension + try { + extensions.delete(IssuerAlternativeNameExtension.NAME); + + } catch (IOException e) { + // this is the hack + // If name is not found, try deleting using the OID + + try { + extensions.delete("2.5.29.18"); + } catch (IOException ee) { + } + } + } + + try { + extensions.set(IssuerAlternativeNameExtension.NAME, mExtension); + } catch (Exception e) { + if (e instanceof RuntimeException) + throw (RuntimeException) e; + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CRL_CREATE_ISSUER_ALT_NAME_EXT", e.toString())); + setError(req, CMS.getUserMessage("CMS_POLICY_SUBJECT_KEY_ID_ERROR"), NAME); + return PolicyResult.REJECTED; + } + return PolicyResult.ACCEPTED; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return Empty Vector since this policy has no configuration parameters. + * for this policy instance. + */ + public Vector getInstanceParams() { + return mParams; + } + + /** + * Return default parameters for a policy implementation. + * + * @return Empty Vector since this policy implementation has no + * configuration parameters. + */ + public Vector getDefaultParams() { + return defaultParams; + } + + public String[] getExtendedPluginInfo(Locale locale) { + return mInfo; + } + +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/KeyUsageExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/KeyUsageExt.java new file mode 100644 index 000000000..d824e452e --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/KeyUsageExt.java @@ -0,0 +1,351 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.ca.*; +import com.netscape.certsrv.authority.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.extensions.*; +import com.netscape.certsrv.ca.*; +import com.netscape.certsrv.apps.*; +import netscape.security.x509.*; +import netscape.ldap.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Policy to add Key Usage Extension. + * Adds the key usage extension based on what's requested. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class KeyUsageExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + + private final static String HTTP_INPUT = "HTTP_INPUT"; + protected static final boolean[] DEF_BITS = + new boolean[KeyUsageExtension.NBITS]; + protected int mCAPathLen = -1; + protected IConfigStore mConfig = null; + protected static final String PROP_CRITICAL = "critical"; + protected static final String PROP_DIGITAL_SIGNATURE = "digitalSignature"; + protected static final String PROP_NON_REPUDIATION = "nonRepudiation"; + protected static final String PROP_KEY_ENCIPHERMENT = "keyEncipherment"; + protected static final String PROP_DATA_ENCIPHERMENT = "dataEncipherment"; + protected static final String PROP_KEY_AGREEMENT = "keyAgreement"; + protected static final String PROP_KEY_CERTSIGN = "keyCertsign"; + protected static final String PROP_CRL_SIGN = "crlSign"; + protected static final String PROP_ENCIPHER_ONLY = "encipherOnly"; + protected static final String PROP_DECIPHER_ONLY = "decipherOnly"; + + protected boolean mCritical; + protected String mDigitalSignature; + protected String mNonRepudiation; + protected String mKeyEncipherment; + protected String mDataEncipherment; + protected String mKeyAgreement; + protected String mKeyCertsign; + protected String mCrlSign; + protected String mEncipherOnly; + protected String mDecipherOnly; + + protected KeyUsageExtension mKeyUsage; + + public KeyUsageExt() { + NAME = "KeyUsageExtPolicy"; + DESC = "Sets Key Usage Extension in certificates."; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries may be of the form: + * + * ca.Policy.rule..implName=KeyUsageExt + * ca.Policy.rule..enable=true + * ca.Policy.rule.. + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + + ICertAuthority certAuthority = (ICertAuthority) + ((IPolicyProcessor) owner).getAuthority(); + + if (certAuthority == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CANT_FIND_MANAGER")); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", + "Cannot find the Certificate Manager or Registration Manager")); + } + + if (certAuthority instanceof ICertificateAuthority) { + CertificateChain caChain = certAuthority.getCACertChain(); + X509Certificate caCert = null; + + // Note that in RA the chain could be null if CA was not up when + // RA was started. In that case just set the length to -1 and let + // CA reject if it does not allow any subordinate CA certs. + if (caChain != null) { + caCert = caChain.getFirstCertificate(); + mCAPathLen = caCert.getBasicConstraints(); + } + } + + mCritical = mConfig.getBoolean(PROP_CRITICAL, true); + mDigitalSignature = mConfig.getString(PROP_DIGITAL_SIGNATURE, HTTP_INPUT); + mNonRepudiation = mConfig.getString(PROP_NON_REPUDIATION, HTTP_INPUT); + mKeyEncipherment = mConfig.getString(PROP_KEY_ENCIPHERMENT, HTTP_INPUT); + mDataEncipherment = mConfig.getString(PROP_DATA_ENCIPHERMENT, HTTP_INPUT); + mKeyAgreement = mConfig.getString(PROP_KEY_AGREEMENT, HTTP_INPUT); + mKeyCertsign = mConfig.getString(PROP_KEY_CERTSIGN, HTTP_INPUT); + mCrlSign = mConfig.getString(PROP_CRL_SIGN, HTTP_INPUT); + mEncipherOnly = mConfig.getString(PROP_ENCIPHER_ONLY, HTTP_INPUT); + mDecipherOnly = mConfig.getString(PROP_DECIPHER_ONLY, HTTP_INPUT); + } + + /** + * Adds the key usage extension if not set already. + * (CRMF, agent, authentication (currently) or PKCS#10 (future) + * or RA could have set the extension.) + * If not set, set from http input parameters or use default if + * no http input parameters are set. + * + * Note: this allows any bits requested - does not check if user + * authenticated is allowed to have a Key Usage Extension with + * those bits. Unless the CA's certificate path length is 0, then + * we do not allow CA sign or CRL sign bits in any request. + * + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + PolicyResult res = PolicyResult.ACCEPTED; + + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; // unrecoverable error. + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult certRes = applyCert(req, ci[i]); + + if (certRes == PolicyResult.REJECTED) + return certRes; + } + return PolicyResult.ACCEPTED; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + try { + CertificateExtensions extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + KeyUsageExtension ext = null; + + if (extensions != null) { + try { + ext = (KeyUsageExtension) + extensions.get(KeyUsageExtension.NAME); + } catch (IOException e) { + // extension isn't there. + ext = null; + } + // check if CA does not allow subordinate CA certs. + // otherwise accept existing key usage extension. + if (ext != null) { + if (mCAPathLen == 0) { + boolean[] bits = ext.getBits(); + + if ((bits.length > KeyUsageExtension.KEY_CERTSIGN_BIT && + bits[KeyUsageExtension.KEY_CERTSIGN_BIT] == true) || + (bits.length > KeyUsageExtension.CRL_SIGN_BIT && + bits[KeyUsageExtension.CRL_SIGN_BIT] == true)) { + setError(req, + CMS.getUserMessage("CMS_POLICY_NO_SUB_CA_CERTS_ALLOWED"), + NAME); + return PolicyResult.REJECTED; + } + } + return PolicyResult.ACCEPTED; + } + } else { + // create extensions set if none. + if (extensions == null) { + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } + } + + boolean[] bits = new boolean[KeyUsageExtension.NBITS]; + + bits[KeyUsageExtension.DIGITAL_SIGNATURE_BIT] = getBit("digital_signature", + mDigitalSignature, req); + bits[KeyUsageExtension.NON_REPUDIATION_BIT] = getBit("non_repudiation", + mNonRepudiation, req); + bits[KeyUsageExtension.KEY_ENCIPHERMENT_BIT] = getBit("key_encipherment", + mKeyEncipherment, req); + bits[KeyUsageExtension.DATA_ENCIPHERMENT_BIT] = getBit("data_encipherment", + mDataEncipherment, req); + bits[KeyUsageExtension.KEY_AGREEMENT_BIT] = getBit("key_agreement", + mKeyAgreement, req); + bits[KeyUsageExtension.KEY_CERTSIGN_BIT] = getBit("key_certsign", + mKeyCertsign, req); + bits[KeyUsageExtension.CRL_SIGN_BIT] = getBit("crl_sign", mCrlSign, req); + bits[KeyUsageExtension.ENCIPHER_ONLY_BIT] = getBit("encipher_only", + mEncipherOnly, req); + bits[KeyUsageExtension.DECIPHER_ONLY_BIT] = getBit("decipher_only", + mDecipherOnly, req); + + // don't allow no bits set or the extension does not + // encode/decode properlly. + boolean bitset = false; + + for (int i = 0; i < bits.length; i++) { + if (bits[i]) { + bitset = true; + break; + } + } + if (!bitset) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_NO_KEYUSAGE_EXTENSION_BITS_SET", NAME)); + setError(req, CMS.getUserMessage("CMS_POLICY_NO_KEYUSAGE_EXTENSION_BITS_SET"), + NAME); + return PolicyResult.REJECTED; + } + + // create the extension. + try { + mKeyUsage = new KeyUsageExtension(mCritical, bits); + } catch (IOException e) { + } + extensions.set(KeyUsageExtension.NAME, mKeyUsage); + return PolicyResult.ACCEPTED; + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("BASE_IO_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, e.getMessage()); + return PolicyResult.REJECTED; // unrecoverable error. + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CERT_INFO_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Certificate Info Error"); + return PolicyResult.REJECTED; // unrecoverable error. + } + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector params = new Vector(); + + params.addElement(PROP_CRITICAL + "=" + mCritical); + params.addElement(PROP_DIGITAL_SIGNATURE + "=" + mDigitalSignature); + params.addElement(PROP_NON_REPUDIATION + "=" + mNonRepudiation); + params.addElement(PROP_KEY_ENCIPHERMENT + "=" + mKeyEncipherment); + params.addElement(PROP_DATA_ENCIPHERMENT + "=" + mDataEncipherment); + params.addElement(PROP_KEY_AGREEMENT + "=" + mKeyAgreement); + params.addElement(PROP_KEY_CERTSIGN + "=" + mKeyCertsign); + params.addElement(PROP_CRL_SIGN + "=" + mCrlSign); + params.addElement(PROP_ENCIPHER_ONLY + "=" + mEncipherOnly); + params.addElement(PROP_DECIPHER_ONLY + "=" + mDecipherOnly); + return params; + } + + private static Vector mDefParams = new Vector(); + static { + mDefParams.addElement(PROP_CRITICAL + "=true"); + mDefParams.addElement(PROP_DIGITAL_SIGNATURE + "="); + mDefParams.addElement(PROP_NON_REPUDIATION + "="); + mDefParams.addElement(PROP_KEY_ENCIPHERMENT + "="); + mDefParams.addElement(PROP_DATA_ENCIPHERMENT + "="); + mDefParams.addElement(PROP_KEY_AGREEMENT + "="); + mDefParams.addElement(PROP_KEY_CERTSIGN + "="); + mDefParams.addElement(PROP_CRL_SIGN + "="); + mDefParams.addElement(PROP_ENCIPHER_ONLY + "="); + mDefParams.addElement(PROP_DECIPHER_ONLY + "="); + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_CRITICAL + ";boolean;RFC 2459 recommendation: SHOULD be critical", + PROP_DIGITAL_SIGNATURE + ";choice(true,false,HTTP_INPUT);true means always set this bit, false means don't set this bit, HTTP_INPUT means get this bit from the HTTP input", + PROP_NON_REPUDIATION + ";choice(true,false,HTTP_INPUT);true means always set this bit, false means don't set this bit, HTTP_INPUT means get this bit from the HTTP input", + PROP_KEY_ENCIPHERMENT + ";choice(true,false,HTTP_INPUT);true means always set this bit, false means don't set this bit, HTTP_INPUT means get this bit from the HTTP input", + PROP_DATA_ENCIPHERMENT + ";choice(true,false,HTTP_INPUT);true means always set this bit, false means don't set this bit, HTTP_INPUT means get this bit from the HTTP input", + PROP_KEY_AGREEMENT + ";choice(true,false,HTTP_INPUT);true means always set this bit, false means don't set this bit, HTTP_INPUT means get this bit from the HTTP input", + PROP_KEY_CERTSIGN + ";choice(true,false,HTTP_INPUT);true means always set this bit, false means don't set this bit, HTTP_INPUT means get this bit from the HTTP input", + PROP_CRL_SIGN + ";choice(true,false,HTTP_INPUT);true means always set this bit, false means don't set this bit, HTTP_INPUT means get this bit from the HTTP input", + PROP_ENCIPHER_ONLY + ";choice(true,false,HTTP_INPUT);true means always set this bit, false means don't set this bit, HTTP_INPUT means get this bit from the HTTP input", + PROP_DECIPHER_ONLY + ";choice(true,false,HTTP_INPUT);true means always set this bit, false means don't set this bit, HTTP_INPUT means get this bit from the HTTP input", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-keyusage", + IExtendedPluginInfo.HELP_TEXT + + ";Adds Key Usage Extension; See in RFC 2459 (4.2.1.3)" + + }; + + return params; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return mDefParams; + } + + private boolean getBit(String usage, String choice, IRequest req) { + if (choice.equals(HTTP_INPUT)) { + choice = req.getExtDataInString(IRequest.HTTP_PARAMS, usage); + if (choice == null) + choice = "false"; + } + return Boolean.valueOf(choice).booleanValue(); + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/NSCCommentExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/NSCCommentExt.java new file mode 100644 index 000000000..05a17cfcd --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/NSCCommentExt.java @@ -0,0 +1,288 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.logging.ILogger; +import netscape.security.util.*; +import netscape.security.x509.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Netscape comment + * Adds Netscape comment policy + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class NSCCommentExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + + protected static final String PROP_USER_NOTICE_DISPLAY_TEXT = "displayText"; + protected static final String PROP_COMMENT_FILE = "commentFile"; + protected static final String PROP_CRITICAL = "critical"; + protected static final String PROP_INPUT_TYPE = "inputType"; + protected static final String TEXT = "Text"; + protected static final String FILE = "File"; + + protected String mUserNoticeDisplayText; + protected String mCommentFile; + protected String mInputType; + protected boolean mCritical; + private Vector mParams = new Vector(); + + protected String tempCommentFile; + protected boolean certApplied = false; + + /** + * Adds the Netscape comment in the end-entity certificates or + * CA certificates. The policy is set to be non-critical with the + * provided OID. + */ + public NSCCommentExt() { + NAME = "NSCCommentExt"; + DESC = "Sets non-critical Netscape Comment extension in certs"; + } + + /** + * Initializes this policy rule. + *

+ * The entries may be of the form: + * + * ca.Policy.rule..implName=NSCCommentExtImpl + * ca.Policy.rule..displayText= + * ca.Policy.rule..commentFile= + * ca.Policy.rule..enable=false + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + + FileInputStream fileStream = null; + + try { + mCritical = config.getBoolean(PROP_CRITICAL, false); + mParams.addElement(PROP_CRITICAL + "=" + mCritical); + + mInputType = config.getString(PROP_INPUT_TYPE, null); + mParams.addElement(PROP_INPUT_TYPE + "=" + mInputType); + + mUserNoticeDisplayText = config.getString(PROP_USER_NOTICE_DISPLAY_TEXT, ""); + mParams.addElement(PROP_USER_NOTICE_DISPLAY_TEXT + "=" + mUserNoticeDisplayText); + + tempCommentFile = config.getString(PROP_COMMENT_FILE, ""); + + boolean enable = config.getBoolean(PROP_ENABLE, false); + + if ((enable == true)) { + + if (mInputType.equals("File")) { + if (tempCommentFile.equals("")) + throw new Exception("No file name provided"); + + fileStream = new FileInputStream(tempCommentFile); + fileStream.close(); + } + } + + if (tempCommentFile.equals("")) + mCommentFile = ""; + else + mCommentFile = tempCommentFile.replace('\\', '/'); + + config.putString(PROP_COMMENT_FILE, mCommentFile); + + mParams.addElement(PROP_COMMENT_FILE + "=" + mCommentFile); + } catch (FileNotFoundException e) { + Object[] params = {getInstanceName(), "File not found : " + tempCommentFile}; + + throw new EPolicyException(CMS.getUserMessage("CMS_POLICY_INVALID_POLICY_CONFIG"), params); + } catch (Exception e) { + Object[] params = {getInstanceName(), e.getMessage()}; + + throw new EPolicyException(CMS.getUserMessage("CMS_POLICY_INVALID_POLICY_CONFIG"), params); + } + } + + /** + * Applies the policy on the given Request. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + PolicyResult res = PolicyResult.ACCEPTED; + + // get cert info. + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; // unrecoverable error. + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult r = applyCert(req, ci[i]); + + if (r == PolicyResult.REJECTED) + return r; + } + return res; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + + certApplied = false; + CertificateExtensions extensions = null; + + try { + extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + } catch (IOException e) { + } catch (CertificateException e) { + } + + if (extensions == null) { + extensions = new CertificateExtensions(); + try { + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } catch (Exception e) { + } + } else { + // remove any previously computed version of the extension + try { + extensions.delete(NSCCommentExtension.NAME); + + } catch (IOException e) { + // this is the hack: for some reason, the key which is the name + // of the policy has been converted into the OID + try { + extensions.delete("2.16.840.1.113730.1.13"); + } catch (IOException ee) { + } + } + } + if (mInputType.equals("File")) { + // if ((mUserNoticeDisplayText.equals("")) && !(mCommentFile.equals(""))) { + try { + // Read the comments file + BufferedReader fis = new BufferedReader(new FileReader(mCommentFile)); + + String line = null; + StringBuffer buffer = new StringBuffer(); + + while ((line = fis.readLine()) != null) + buffer.append(line); + mUserNoticeDisplayText = new String(buffer); + fis.close(); + } catch (IOException e) { + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, " Comment Text file not found : " + mCommentFile); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_COMMENT_FILE_NOT_FOUND", e.toString())); + return PolicyResult.REJECTED; + + } + + } + + certApplied = true; + + DisplayText displayText = + new DisplayText(DisplayText.tag_IA5String, mUserNoticeDisplayText); + + try { + NSCCommentExtension cpExt = + new NSCCommentExtension(mCritical, mUserNoticeDisplayText); + + extensions.set(NSCCommentExtension.NAME, cpExt); + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_CERTIFICATE_POLICIES_1", NAME)); + setError(req, + CMS.getUserMessage("CMS_POLICY_CERTIFICATE_POLICIES_ERROR"), NAME); + return PolicyResult.REJECTED; + } + return PolicyResult.ACCEPTED; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_CRITICAL + ";boolean;Netscape recommendation: non-critical.", + PROP_INPUT_TYPE + ";choice(Text,File);Whether the comments " + + "would be entered in the displayText field or come from " + + "a file.", + PROP_USER_NOTICE_DISPLAY_TEXT + ";string;The comment that may be " + + "displayed to the user when the certificate is viewed.", + PROP_COMMENT_FILE + ";string; If data source is 'File', specify " + + "the file name with full path.", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-nsccomment", + IExtendedPluginInfo.HELP_TEXT + + ";Adds 'netscape comment' extension. See manual" + }; + + return params; + + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + return mParams; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + Vector defParams = new Vector(); + + defParams.addElement(PROP_CRITICAL + "=false"); + defParams.addElement(PROP_INPUT_TYPE + "=" + TEXT); + defParams.addElement(PROP_USER_NOTICE_DISPLAY_TEXT + "="); + defParams.addElement(PROP_COMMENT_FILE + "="); + return defParams; + } +} diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/NSCertTypeExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/NSCertTypeExt.java new file mode 100644 index 000000000..5fa6bae9c --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/NSCertTypeExt.java @@ -0,0 +1,541 @@ +// --- 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.cms.policy.extensions; + + +import java.io.IOException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Locale; +import java.util.Vector; + +import netscape.security.extensions.NSCertTypeExtension; +import netscape.security.x509.CertificateChain; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.KeyUsageExtension; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.AuthToken; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authority.ICertAuthority; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.policy.IPolicyProcessor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.cms.policy.APolicyRule; + + +/** + * NS Cert Type policy. + * Adds the ns cert type extension depending on cert type requested. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class NSCertTypeExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + protected static final String PROP_SET_DEFAULT_BITS = "setDefaultBits"; + protected static final boolean DEF_SET_DEFAULT_BITS = true; + protected static final String DEF_SET_DEFAULT_BITS_VAL = + Boolean.valueOf(DEF_SET_DEFAULT_BITS).toString(); + + protected static final int DEF_PATHLEN = -1; + + protected static final boolean[] DEF_BITS = + new boolean[NSCertTypeExtension.NBITS]; + + // XXX for future use. currenlty always allow. + protected static final String PROP_AGENT_OVERR = "allowAgentOverride"; + protected static final String PROP_EE_OVERR = "AllowEEOverride"; + + // XXX for future use. currently always critical + // (standard says SHOULD be marked critical if included.) + protected static final String PROP_CRITICAL = "critical"; + + // XXX for future use to allow overrides from forms. + // request must be agent approved or authenticated. + protected boolean mAllowAgentOverride = false; + protected boolean mAllowEEOverride = false; + + // XXX for future use. currently always non-critical + protected boolean mCritical = false; + + protected int mCAPathLen = -1; + + protected IConfigStore mConfig = null; + protected boolean mSetDefaultBits = false; + + static { + // set default bits used when request missing ns cert type info. + // default is a client cert + DEF_BITS[NSCertTypeExtension.SSL_CLIENT_BIT] = true; + DEF_BITS[NSCertTypeExtension.SSL_SERVER_BIT] = false; + DEF_BITS[NSCertTypeExtension.EMAIL_BIT] = true; + DEF_BITS[NSCertTypeExtension.OBJECT_SIGNING_BIT] = true; + DEF_BITS[NSCertTypeExtension.SSL_CA_BIT] = false; + DEF_BITS[NSCertTypeExtension.EMAIL_CA_BIT] = false; + DEF_BITS[NSCertTypeExtension.OBJECT_SIGNING_CA_BIT] = false; + } + + public NSCertTypeExt() { + NAME = "NSCertType"; + DESC = "Sets Netscape Cert Type on all certs"; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries may be of the form: + * + * ra.Policy.rule..implName=nsCertTypeExt + * ra.Policy.rule..enable=true + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + + // XXX future use. + //mAllowAgentOverride = config.getBoolean(PROP_AGENT_OVERR, false); + //mAllowEEOverride = config.getBoolean(PROP_EE_OVERR, false); + mCritical = config.getBoolean(PROP_CRITICAL, false); + + ICertAuthority certAuthority = (ICertAuthority) + ((IPolicyProcessor) owner).getAuthority(); + + if (certAuthority instanceof ICertificateAuthority) { + CertificateChain caChain = certAuthority.getCACertChain(); + X509Certificate caCert = null; + + // Note that in RA the chain could be null if CA was not up when + // RA was started. In that case just set the length to -1 and let + // CA reject if it does not allow any subordinate CA certs. + if (caChain != null) { + caCert = caChain.getFirstCertificate(); + if (caCert != null) + mCAPathLen = caCert.getBasicConstraints(); + } + } + + mSetDefaultBits = mConfig.getBoolean( + PROP_SET_DEFAULT_BITS, DEF_SET_DEFAULT_BITS); + } + + /** + * Adds the ns cert type if not set already. + * reads ns cert type choices from form. If no choices from form + * will defaults to all. + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + CMS.debug("NSCertTypeExt: Impl: " + NAME + ", Instance: " + getInstanceName() + "::apply()"); + PolicyResult res = PolicyResult.ACCEPTED; + + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + X509CertInfo certInfo = null; + + if (ci == null || (certInfo = ci[0]) == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; // unrecoverable error. + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult certRes = applyCert(req, ci[i]); + + if (certRes == PolicyResult.REJECTED) + return certRes; + } + return PolicyResult.ACCEPTED; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + try { + String certType = + req.getExtDataInString(IRequest.HTTP_PARAMS, IRequest.CERT_TYPE); + CertificateExtensions extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + NSCertTypeExtension nsCertTypeExt = null; + + if (extensions != null) { + // See if extension is already set and contains correct values. + try { + nsCertTypeExt = (NSCertTypeExtension) + extensions.get(NSCertTypeExtension.NAME); + } catch (IOException e) { + // extension isn't there. + nsCertTypeExt = null; + } + // XXX agent servlet currently sets this. it should be + // delayed to here. + if (nsCertTypeExt != null && + extensionIsGood(nsCertTypeExt, req)) { + CMS.debug( + "NSCertTypeExt: already has correct ns cert type ext"); + return PolicyResult.ACCEPTED; + } else if ((nsCertTypeExt != null) && + (certType.equals("ocspResponder"))) { + // Fix for #528732 : Always delete + // this extension from OCSP signing cert + extensions.delete(NSCertTypeExtension.NAME); + return PolicyResult.ACCEPTED; + } + } else { + // create extensions set if none. + if (extensions == null) { + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + CMS.debug( + "NSCertTypeExt: Created extensions for adding ns cert type.."); + } + } + // add ns cert type extension if not set or not set correctly. + boolean[] bits = null; + + bits = getBitsFromRequest(req, mSetDefaultBits); + + // check if ca doesn't allow any subordinate ca + if (mCAPathLen == 0 && bits != null) { + if (bits[NSCertTypeExtension.SSL_CA_BIT] || + bits[NSCertTypeExtension.EMAIL_CA_BIT] || + bits[NSCertTypeExtension.OBJECT_SIGNING_CA_BIT]) { + setError(req, + CMS.getUserMessage("CMS_POLICY_NO_SUB_CA_CERTS_ALLOWED"), NAME); + return PolicyResult.REJECTED; + } + } + + if (nsCertTypeExt != null) { + // replace with correct bits to comply to policy. + // take all that are true. + extensions.delete(NSCertTypeExtension.NAME); + } + + int j; + + for (j = 0; bits != null && j < bits.length; j++) + if (bits[j]) break; + if (bits == null || j == bits.length) { + if (!mSetDefaultBits) { + CMS.debug( + "NSCertTypeExt: no bits requested, not setting default."); + return PolicyResult.ACCEPTED; + } else + bits = DEF_BITS; + } + + nsCertTypeExt = new NSCertTypeExtension(mCritical, bits); + extensions.set(NSCertTypeExtension.NAME, nsCertTypeExt); + return PolicyResult.ACCEPTED; + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("BASE_IO_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, e.getMessage()); + return PolicyResult.REJECTED; // unrecoverable error. + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CERT_INFO_ERROR", e.getMessage())); + + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Certificate Info Error"); + return PolicyResult.REJECTED; // unrecoverable error. + } + } + + /** + * check if ns cert type extension is set correctly, + * correct bits if not. + * if not authorized to set extension, bits will be replaced. + */ + protected boolean extensionIsGood( + NSCertTypeExtension nsCertTypeExt, IRequest req) + throws IOException, CertificateException { + // always return false for now to make sure minimum is set. + // agents and ee can add others. + + // must be agent approved or authenticated for allowing extensions + // which is always the case if we get to this point. + IAuthToken token = req.getExtDataInAuthToken(IRequest.AUTH_TOKEN); + + if (!agentApproved(req) && token == null) { + // don't know where this came from. + // set all bits to false to reset. + CMS.debug( + "NSCertTypeExt: unknown origin: setting ns cert type bits to false"); + boolean[] bits = new boolean[8]; + + for (int i = bits.length - 1; i >= 0; i--) { + nsCertTypeExt.set(i, false); + } + return false; + } else { + // check for min bits, set default if not there. + String certType = req.getExtDataInString(IRequest.HTTP_PARAMS, + IRequest.CERT_TYPE); + + if ((certType != null) && certType.equals("ocspResponder")) { + return false; + } + if (certType == null || certType.length() == 0) { + // if don't know cert type let agent override anything. + return true; + } + if (certType.equals(IRequest.CA_CERT)) { + if (!nsCertTypeExt.isSet(NSCertTypeExtension.SSL_CA_BIT) && + !nsCertTypeExt.isSet(NSCertTypeExtension.EMAIL_CA_BIT) && + !nsCertTypeExt.isSet( + NSCertTypeExtension.OBJECT_SIGNING_CA_BIT)) { + // min not set so set all. + CMS.debug( + "NSCertTypeExt: is extension good: no ca bits set. set all"); + + nsCertTypeExt.set(NSCertTypeExtension.SSL_CA, + Boolean.valueOf(true)); + nsCertTypeExt.set(NSCertTypeExtension.EMAIL_CA, + Boolean.valueOf(true)); + nsCertTypeExt.set(NSCertTypeExtension.OBJECT_SIGNING_CA, + Boolean.valueOf(true)); + } + return true; + } else if (certType.equals(IRequest.CLIENT_CERT)) { + if (!nsCertTypeExt.isSet(NSCertTypeExtension.SSL_CLIENT_BIT) && + !nsCertTypeExt.isSet(NSCertTypeExtension.EMAIL_BIT) && + !nsCertTypeExt.isSet(NSCertTypeExtension.SSL_SERVER_BIT) && + !nsCertTypeExt.isSet( + NSCertTypeExtension.OBJECT_SIGNING_BIT)) { + // min not set so set all. + CMS.debug( + "NSCertTypeExt: is extension good: no cl bits set. set all"); + nsCertTypeExt.set(NSCertTypeExtension.SSL_CLIENT, + new Boolean(true)); + nsCertTypeExt.set(NSCertTypeExtension.EMAIL, + new Boolean(true)); + nsCertTypeExt.set(NSCertTypeExtension.OBJECT_SIGNING, + new Boolean(true)); + } + return true; + } else if (certType.equals(IRequest.SERVER_CERT)) { + // this bit must be true. + nsCertTypeExt.set(NSCertTypeExtension.SSL_SERVER_BIT, true); + return true; + } + } + return false; + } + + /** + * Gets ns cert type bits from request. + * If none set, use cert type to determine correct bits. + * If no cert type, use default. + */ + + protected boolean[] getBitsFromRequest(IRequest req, boolean setDefault) { + boolean[] bits = null; + + CMS.debug("NSCertTypeExt: ns cert type getting ns cert type vars"); + bits = getNSCertTypeBits(req); + if (bits == null && setDefault) { + // no ns cert type bits set in request. go with cert type. + CMS.debug("NSCertTypeExt: ns cert type getting cert type vars"); + bits = getCertTypeBits(req); + + if (bits == null && setDefault) { + CMS.debug("NSCertTypeExt: ns cert type getting def bits"); + bits = DEF_BITS; + } + } + return bits; + } + + /** + * get ns cert type bits from actual sets in the request + */ + protected boolean[] getNSCertTypeBits(IRequest req) { + boolean[] bits = new boolean[NSCertTypeExtension.NBITS]; + + bits[NSCertTypeExtension.SSL_CLIENT_BIT] = + // XXX should change this to is ns cert type ssl_client defn. + req.getExtDataInBoolean(IRequest.HTTP_PARAMS, + NSCertTypeExtension.SSL_CLIENT, false); + + bits[NSCertTypeExtension.SSL_SERVER_BIT] = + req.getExtDataInBoolean(IRequest.HTTP_PARAMS, + NSCertTypeExtension.SSL_SERVER, false); + + bits[NSCertTypeExtension.EMAIL_BIT] = + // XXX should change this to is ns cert type ssl_client defn. + req.getExtDataInBoolean(IRequest.HTTP_PARAMS, + NSCertTypeExtension.EMAIL, false); + + bits[NSCertTypeExtension.OBJECT_SIGNING_BIT] = + // XXX should change this to is ns cert type ssl_client defn. + req.getExtDataInBoolean(IRequest.HTTP_PARAMS, + NSCertTypeExtension.OBJECT_SIGNING, false); + + bits[NSCertTypeExtension.SSL_CA_BIT] = + req.getExtDataInBoolean(IRequest.HTTP_PARAMS, + NSCertTypeExtension.SSL_CA, false); + + bits[NSCertTypeExtension.EMAIL_CA_BIT] = + req.getExtDataInBoolean(IRequest.HTTP_PARAMS, + NSCertTypeExtension.EMAIL_CA, false); + + bits[NSCertTypeExtension.OBJECT_SIGNING_CA_BIT] = + req.getExtDataInBoolean(IRequest.HTTP_PARAMS, + NSCertTypeExtension.OBJECT_SIGNING_CA, false); + + // if nothing set, return null. + int i; + + for (i = bits.length - 1; i >= 0; i--) { + if (bits[i] == true) { + CMS.debug("NSCertTypeExt: bit " + i + " is set."); + break; + } + } + if (i < 0) { + // nothing was set. + CMS.debug("NSCertTypeExt: No bits were set."); + bits = null; + } + return bits; + } + + /** + * get cert type bits according to cert type. + */ + protected boolean[] getCertTypeBits(IRequest req) { + String certType = + req.getExtDataInString(IRequest.HTTP_PARAMS, IRequest.CERT_TYPE); + + if (certType == null || certType.length() == 0) + return null; + + boolean[] bits = new boolean[KeyUsageExtension.NBITS]; + + for (int i = bits.length - 1; i >= 0; i--) + bits[i] = false; + + if (certType.equals(IRequest.CLIENT_CERT)) { + CMS.debug("NSCertTypeExt: setting bits for client cert"); + // we can only guess here when it's client. + // sets all client bit for default. + bits[NSCertTypeExtension.SSL_CLIENT_BIT] = true; + bits[NSCertTypeExtension.EMAIL_BIT] = true; + //bits[NSCertTypeExtension.OBJECT_SIGNING_BIT] = true; + } else if (certType.equals(IRequest.SERVER_CERT)) { + CMS.debug("NSCertTypeExt: setting bits for server cert"); + bits[NSCertTypeExtension.SSL_SERVER_BIT] = true; + } else if (certType.equals(IRequest.CA_CERT)) { + CMS.debug("NSCertType: setting bits for ca cert"); + bits[NSCertTypeExtension.SSL_CA_BIT] = true; + bits[NSCertTypeExtension.EMAIL_CA_BIT] = true; + bits[NSCertTypeExtension.OBJECT_SIGNING_CA_BIT] = true; + } else if (certType.equals(IRequest.RA_CERT)) { + CMS.debug("NSCertType: setting bits for ra cert"); + bits[NSCertTypeExtension.SSL_CLIENT_BIT] = true; + } else { + CMS.debug("NSCertTypeExt: no other cert bits set"); + // return null to use default. + bits = DEF_BITS; + } + return bits; + } + + /** + * merge bits with those set from form. + * make sure required minimum is set. Agent or auth can set others. + * XXX form shouldn't set the extension + */ + public void mergeBits(NSCertTypeExtension nsCertTypeExt, boolean[] bits) { + for (int i = bits.length - 1; i >= 0; i--) { + if (bits[i] == true) { + CMS.debug("NSCertTypeExt: ns cert type merging bit " + i); + nsCertTypeExt.set(i, true); + } + } + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector params = new Vector(); + + params.addElement(PROP_CRITICAL + "=" + mCritical); + params.addElement(PROP_SET_DEFAULT_BITS + "=" + mSetDefaultBits); + //new Boolean(mSetDefaultBits).toString()); + return params; + } + + private static Vector mDefParams = new Vector(); + static { + mDefParams.addElement( + PROP_CRITICAL + "=false"); + mDefParams.addElement( + PROP_SET_DEFAULT_BITS + "=" + DEF_SET_DEFAULT_BITS); + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_CRITICAL + ";boolean;Netscape recommendation: non-critical.", + PROP_SET_DEFAULT_BITS + ";boolean;Specify whether to set the Netscape certificate " + + "type extension with default bits ('ssl client' and 'email') in certificates " + + "specified by the predicate " + + "expression.", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-nscerttype", + IExtendedPluginInfo.HELP_TEXT + + ";Adds Netscape Certificate Type extension." + }; + + return params; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return mDefParams; + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/NameConstraintsExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/NameConstraintsExt.java new file mode 100644 index 000000000..b204e57b2 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/NameConstraintsExt.java @@ -0,0 +1,468 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.ca.*; +import com.netscape.certsrv.logging.ILogger; +import netscape.security.x509.*; +import netscape.security.util.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Name Constraints Extension Policy + * Adds the name constraints extension to a (CA) certificate. + * Filtering of CA certificates is done through predicates. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class NameConstraintsExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + protected static final String PROP_CRITICAL = "critical"; + protected static final String PROP_NUM_PERMITTEDSUBTREES = "numPermittedSubtrees"; + protected static final String PROP_NUM_EXCLUDEDSUBTREES = "numExcludedSubtrees"; + + protected static final String PROP_PERMITTEDSUBTREES = "permittedSubtrees"; + protected static final String PROP_EXCLUDEDSUBTREES = "excludedSubtrees"; + + protected static final boolean DEF_CRITICAL = true; + protected static final int DEF_NUM_PERMITTEDSUBTREES = 8; + protected static final int DEF_NUM_EXCLUDEDSUBTREES = 8; + + protected boolean mEnabled = false; + protected IConfigStore mConfig = null; + + protected boolean mCritical = DEF_CRITICAL; + protected int mNumPermittedSubtrees = 0; + protected int mNumExcludedSubtrees = 0; + protected Subtree[] mPermittedSubtrees = null; + protected Subtree[] mExcludedSubtrees = null; + protected NameConstraintsExtension mNameConstraintsExtension = null; + + protected Vector mInstanceParams = new Vector(); + + public NameConstraintsExt() { + NAME = "NameConstraintsExt"; + DESC = "Sets Name Constraints Extension on subordinate CA certificates"; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries may be of the form: + * + * ca.Policy.rule..predicate=certType==ca + * ca.Policy.rule..implName= + * ca.Policy.rule..enable=true + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + + // XXX should do do this ? + // if CA does not allow subordinate CAs by way of basic constraints, + // this policy always rejects + /***** + ICertAuthority certAuthority = (ICertAuthority) + ((IPolicyProcessor)owner).getAuthority(); + if (certAuthority instanceof ICertificateAuthority) { + CertificateChain caChain = certAuthority.getCACertChain(); + X509Certificate caCert = null; + // Note that in RA the chain could be null if CA was not up when + // RA was started. In that case just set the length to -1 and let + // CA reject if it does not allow any subordinate CA certs. + if (caChain != null) { + caCert = caChain.getFirstCertificate(); + if (caCert != null) + mCAPathLen = caCert.getBasicConstraints(); + } + } + ****/ + + mEnabled = mConfig.getBoolean( + IPolicyProcessor.PROP_ENABLE, false); + mCritical = mConfig.getBoolean(PROP_CRITICAL, DEF_CRITICAL); + mNumPermittedSubtrees = mConfig.getInteger( + PROP_NUM_PERMITTEDSUBTREES, DEF_NUM_PERMITTEDSUBTREES); + mNumExcludedSubtrees = mConfig.getInteger( + PROP_NUM_EXCLUDEDSUBTREES, DEF_NUM_EXCLUDEDSUBTREES); + + if (mNumPermittedSubtrees < 0) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + PROP_NUM_PERMITTEDSUBTREES, + "value must be greater than or equal to 0")); + } + if (mNumExcludedSubtrees < 0) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + PROP_NUM_EXCLUDEDSUBTREES, + "value must be greater than or equal to 0")); + } + + // init permitted subtrees if any. + if (mNumPermittedSubtrees > 0) { + mPermittedSubtrees = + form_subtrees(PROP_PERMITTEDSUBTREES, mNumPermittedSubtrees); + CMS.debug("NameConstraintsExt: formed permitted subtrees"); + } + + // init excluded subtrees if any. + if (mNumExcludedSubtrees > 0) { + mExcludedSubtrees = + form_subtrees(PROP_EXCLUDEDSUBTREES, mNumExcludedSubtrees); + CMS.debug("NameConstraintsExt: formed excluded subtrees"); + } + + // create instance of name constraints extension if enabled. + if (mEnabled) { + try { + Vector permittedSubtrees = new Vector(); + + for (int i = 0; i < mNumPermittedSubtrees; i++) { + permittedSubtrees.addElement( + mPermittedSubtrees[i].mGeneralSubtree); + } + Vector excludedSubtrees = new Vector(); + + for (int j = 0; j < mNumExcludedSubtrees; j++) { + excludedSubtrees.addElement( + mExcludedSubtrees[j].mGeneralSubtree); + } + GeneralSubtrees psb = null; + + if (permittedSubtrees.size() > 0) { + psb = new GeneralSubtrees(permittedSubtrees); + } + GeneralSubtrees esb = null; + + if (excludedSubtrees.size() > 0) { + esb = new GeneralSubtrees(excludedSubtrees); + } + mNameConstraintsExtension = + new NameConstraintsExtension(mCritical, + psb, + esb); + CMS.debug("NameConstraintsExt: formed Name Constraints Extension " + + mNameConstraintsExtension); + } catch (IOException e) { + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", + "Error initializing Name Constraints Extension: " + e)); + } + } + + // form instance params + mInstanceParams.addElement(PROP_CRITICAL + "=" + mCritical); + mInstanceParams.addElement( + PROP_NUM_PERMITTEDSUBTREES + "=" + mNumPermittedSubtrees); + mInstanceParams.addElement( + PROP_NUM_EXCLUDEDSUBTREES + "=" + mNumExcludedSubtrees); + if (mNumPermittedSubtrees > 0) { + for (int i = 0; i < mPermittedSubtrees.length; i++) + mPermittedSubtrees[i].getInstanceParams(mInstanceParams); + } + if (mNumExcludedSubtrees > 0) { + for (int j = 0; j < mExcludedSubtrees.length; j++) + mExcludedSubtrees[j].getInstanceParams(mInstanceParams); + } + } + + Subtree[] form_subtrees(String subtreesName, int numSubtrees) + throws EBaseException { + Subtree[] subtrees = new Subtree[numSubtrees]; + + for (int i = 0; i < numSubtrees; i++) { + String subtreeName = subtreesName + i; + IConfigStore subtreeConfig = mConfig.getSubStore(subtreeName); + Subtree subtree = + new Subtree(subtreeName, subtreeConfig, mEnabled); + + subtrees[i] = subtree; + } + return subtrees; + } + + /** + * Adds Name Constraints Extension to a (CA) certificate. + * + * If a Name constraints Extension is already there, accept it if + * it's been approved by agent, else replace it. + * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + // if extension hasn't been properly configured reject requests until + // it has been resolved (or disabled). + if (mNameConstraintsExtension == null) { + //setError(req, PolicyResources.EXTENSION_NOT_INITED_1, NAME); + //return PolicyResult.REJECTED; + return PolicyResult.ACCEPTED; + } + + // get certInfo from request. + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult certRes = applyCert(req, ci[i]); + + if (certRes == PolicyResult.REJECTED) + return certRes; + } + return PolicyResult.ACCEPTED; + + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + // check if name constraints extension already exists. + // if not agent approved, replace name constraints extension with ours. + // else ignore. + try { + NameConstraintsExtension nameConstraintsExt = null; + CertificateExtensions extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + + try { + if (extensions != null) { + nameConstraintsExt = (NameConstraintsExtension) + extensions.get(NameConstraintsExtension.NAME); + } + } catch (IOException e) { + // extension isn't there. + } + + if (nameConstraintsExt != null) { + if (agentApproved(req)) { + CMS.debug( + "NameConstraintsExt: request id from agent " + req.getRequestId() + + " already has name constraints - accepted"); + return PolicyResult.ACCEPTED; + } else { + CMS.debug( + "NameConstraintsExt: request id " + req.getRequestId() + " from user " + + " already has name constraints - deleted"); + extensions.delete(NameConstraintsExtension.NAME); + } + } + + if (extensions == null) { + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } + extensions.set( + NameConstraintsExtension.NAME, mNameConstraintsExtension); + CMS.debug( + "NameConstraintsExt: added Name Constraints Extension to request " + + req.getRequestId()); + return PolicyResult.ACCEPTED; + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_NAME_CONST_EXTENSION", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, e.getMessage()); + return PolicyResult.REJECTED; + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CERT_INFO_ERROR", e.toString())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Certificate Info Error"); + return PolicyResult.REJECTED; + } + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + return mInstanceParams; + } + + /** + * Default config parameters. + * To add more permitted or excluded subtrees, + * increase the num to greater than 0 and more configuration params + * will show up in the console. + */ + private static Vector mDefParams = new Vector(); + static { + mDefParams.addElement(PROP_CRITICAL + "=" + DEF_CRITICAL); + mDefParams.addElement( + PROP_NUM_PERMITTEDSUBTREES + "=" + DEF_NUM_PERMITTEDSUBTREES); + mDefParams.addElement( + PROP_NUM_EXCLUDEDSUBTREES + "=" + DEF_NUM_EXCLUDEDSUBTREES); + for (int k = 0; k < DEF_NUM_PERMITTEDSUBTREES; k++) { + Subtree.getDefaultParams(PROP_PERMITTEDSUBTREES + k, mDefParams); + } + for (int l = 0; l < DEF_NUM_EXCLUDEDSUBTREES; l++) { + Subtree.getDefaultParams(PROP_EXCLUDEDSUBTREES + l, mDefParams); + } + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return mDefParams; + } + + public String[] getExtendedPluginInfo(Locale locale) { + Vector theparams = new Vector(); + + theparams.addElement(PROP_CRITICAL + ";boolean;RFC 2459 recommendation: MUST be critical."); + theparams.addElement( + PROP_NUM_PERMITTEDSUBTREES + ";number;See RFC 2459 sec 4.2.1.11"); + theparams.addElement( + PROP_NUM_EXCLUDEDSUBTREES + ";number;See RFC 2459 sec 4.2.1.11"); + + // now do the subtrees. + for (int k = 0; k < DEF_NUM_PERMITTEDSUBTREES; k++) { + Subtree.getExtendedPluginInfo(PROP_PERMITTEDSUBTREES + k, theparams); + } + for (int l = 0; l < DEF_NUM_EXCLUDEDSUBTREES; l++) { + Subtree.getExtendedPluginInfo(PROP_EXCLUDEDSUBTREES + l, theparams); + } + theparams.addElement(IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-nameconstraints"); + theparams.addElement(IExtendedPluginInfo.HELP_TEXT + + ";Adds Name Constraints Extension. See RFC 2459"); + + String[] info = new String[theparams.size()]; + + theparams.copyInto(info); + return info; + } +} + + +/** + * subtree configuration + */ +class Subtree { + + protected static final String PROP_BASE = "base"; + protected static final String PROP_MIN = "min"; + protected static final String PROP_MAX = "max"; + + protected static final int DEF_MIN = 0; + protected static final int DEF_MAX = -1; // -1 (less than 0) means not set. + + protected static final String + MINMAX_INFO = "number;See RFC 2459 section 4.2.1.11"; + + String mName = null; + IConfigStore mConfig = null; + int mMin = DEF_MIN, mMax = DEF_MAX; + IGeneralNameAsConstraintsConfig mBase = null; + GeneralSubtree mGeneralSubtree = null; + + String mNameDot = null; + String mNameDotMin = null; + String mNameDotMax = null; + + public Subtree( + String subtreeName, IConfigStore config, boolean policyEnabled) + throws EBaseException { + mName = subtreeName; + mConfig = config; + + if (mName != null) { + mNameDot = mName + "."; + mNameDotMin = mNameDot + PROP_MIN; + mNameDotMax = mNameDot + PROP_MAX; + } else { + mNameDot = ""; + mNameDotMin = PROP_MIN; + mNameDotMax = PROP_MAX; + } + + // necessary to expand/shrink # general names from console. + if (mConfig.size() == 0) { + mConfig.putInteger(mNameDotMin, mMin); + mConfig.putInteger(mNameDotMax, mMax); + // GeneralNameConfig will take care of stuff for generalname. + } + + // if policy enabled get values to form the general subtree. + mMin = mConfig.getInteger(PROP_MIN, DEF_MIN); + mMax = mConfig.getInteger(PROP_MAX, DEF_MAX); + if (mMax < -1) mMax = -1; + mBase = CMS.createGeneralNameAsConstraintsConfig( + mNameDot + PROP_BASE, mConfig.getSubStore(PROP_BASE), + true, policyEnabled); + + if (policyEnabled) { + mGeneralSubtree = + new GeneralSubtree(mBase.getGeneralName(), mMin, mMax); + } + } + + void getInstanceParams(Vector instanceParams) { + mBase.getInstanceParams(instanceParams); + instanceParams.addElement(mNameDotMin + "=" + mMin); + instanceParams.addElement(mNameDotMax + "=" + mMax); + } + + static void getDefaultParams(String name, Vector params) { + String nameDot = ""; + + if (name != null && name.length() >= 0) + nameDot = name + "."; + CMS.getGeneralNameConfigDefaultParams(nameDot + PROP_BASE, true, params); + params.addElement(nameDot + PROP_MIN + "=" + DEF_MIN); + params.addElement(nameDot + PROP_MAX + "=" + DEF_MAX); + } + + static void getExtendedPluginInfo(String name, Vector info) { + String nameDot = ""; + + if (name != null && name.length() > 0) + nameDot = name + "."; + CMS.getGeneralNameConfigExtendedPluginInfo(nameDot + PROP_BASE, true, info); + info.addElement(nameDot + PROP_MIN + ";" + MINMAX_INFO); + info.addElement(nameDot + PROP_MAX + ";" + MINMAX_INFO); + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/OCSPNoCheckExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/OCSPNoCheckExt.java new file mode 100644 index 000000000..289e2d297 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/OCSPNoCheckExt.java @@ -0,0 +1,183 @@ +// --- 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.cms.policy.extensions; + + +import com.netscape.certsrv.request.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.apps.*; +import netscape.security.x509.*; +import netscape.security.extensions.*; +import netscape.security.util.*; +import java.security.cert.*; +import java.io.*; +import java.util.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * This implements an OCSP Signing policy, it + * adds the OCSP Signing extension to the certificate. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$ $Date$ + */ +public class OCSPNoCheckExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + + public static final String PROP_CRITICAL = "critical"; + private boolean mCritical = false; + + // PKIX specifies the that the extension SHOULD NOT be critical + public static final boolean DEFAULT_CRITICALITY = false; + + private OCSPNoCheckExtension mOCSPNoCheck = null; + + /** + * Constructs an OCSP No check extension. + */ + public OCSPNoCheckExt() { + NAME = "OCSPNoCheckExt"; + DESC = "Sets OCSPNoCheck extension for certificates"; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_CRITICAL + ";boolean;RFC 2560 recommendation: SHOULD be non-critical.", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-ocspnocheck", + IExtendedPluginInfo.HELP_TEXT + + ";Adds OCSP signing extension to certificate" + }; + + return params; + + } + + /** + * Performs one-time initialization of the policy. + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mOCSPNoCheck = new OCSPNoCheckExtension(); + + if (mOCSPNoCheck != null) { + // configure the extension itself + mCritical = config.getBoolean(PROP_CRITICAL, + DEFAULT_CRITICALITY); + mOCSPNoCheck.setCritical(mCritical); + } + } + + /** + * Applies the policy to the given request. + */ + public PolicyResult apply(IRequest req) { + + // if the extension was not configured correctly, just skip it + if (mOCSPNoCheck == null) { + return PolicyResult.ACCEPTED; + } + + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult certRes = applyCert(req, ci[i]); + + if (certRes == PolicyResult.REJECTED) + return certRes; + } + return PolicyResult.ACCEPTED; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + try { + + // find the extensions in the certInfo + CertificateExtensions extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + + // prepare the extensions data structure + if (extensions == null) { + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } else { + try { + extensions.delete(OCSPNoCheckExtension.NAME); + } catch (IOException ex) { + // OCSPNoCheck extension is not already there + // log(ILogger.LL_FAILURE, "No previous extension: "+OCSPNoCheckExtension.NAME+" "+ex.getMessage()); + } + } + + extensions.set(OCSPNoCheckExtension.NAME, mOCSPNoCheck); + + return PolicyResult.ACCEPTED; + + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("BASE_IO_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), NAME, + e.getMessage()); + return PolicyResult.REJECTED; + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CERT_INFO_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), NAME, + e.getMessage()); + return PolicyResult.REJECTED; + } + } + + /** + * Returns instance parameters. + */ + public Vector getInstanceParams() { + Vector params = new Vector(); + + params.addElement(PROP_CRITICAL + "=" + mCritical); + return params; + + } + + /** + * Returns default parameters. + */ + public Vector getDefaultParams() { + Vector defParams = new Vector(); + + defParams.addElement(PROP_CRITICAL + "=false"); + return defParams; + + } +} diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/PolicyConstraintsExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/PolicyConstraintsExt.java new file mode 100644 index 000000000..4396a09dd --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/PolicyConstraintsExt.java @@ -0,0 +1,282 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.ca.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.logging.ILogger; +import netscape.security.x509.*; +import netscape.security.util.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Policy Constraints Extension Policy + * Adds the policy constraints extension to (CA) certificates. + * Filtering of CA certificates is done through predicates. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class PolicyConstraintsExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + protected static final String PROP_CRITICAL = "critical"; + protected static final String + PROP_REQ_EXPLICIT_POLICY = "reqExplicitPolicy"; + protected static final String + PROP_INHIBIT_POLICY_MAPPING = "inhibitPolicyMapping"; + + protected static final boolean DEF_CRITICAL = false; + protected static final int DEF_REQ_EXPLICIT_POLICY = -1; // not set + protected static final int DEF_INHIBIT_POLICY_MAPPING = -1; // not set + + protected boolean mEnabled = false; + protected IConfigStore mConfig = null; + + protected boolean mCritical = DEF_CRITICAL; + protected int mReqExplicitPolicy = DEF_REQ_EXPLICIT_POLICY; + protected int mInhibitPolicyMapping = DEF_INHIBIT_POLICY_MAPPING; + protected PolicyConstraintsExtension mPolicyConstraintsExtension = null; + + protected Vector mInstanceParams = new Vector(); + + protected static Vector mDefaultParams = new Vector(); + static { + mDefaultParams.addElement(PROP_CRITICAL + "=" + DEF_CRITICAL); + mDefaultParams.addElement( + PROP_REQ_EXPLICIT_POLICY + "=" + DEF_REQ_EXPLICIT_POLICY); + mDefaultParams.addElement( + PROP_INHIBIT_POLICY_MAPPING + "=" + DEF_INHIBIT_POLICY_MAPPING); + } + + public PolicyConstraintsExt() { + NAME = "PolicyConstriantsExt"; + DESC = "Sets Policy Constraints Extension on subordinate CA certs"; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries may be of the form: + * + * ca.Policy.rule..predicate=certType==ca + * ca.Policy.rule..implName= + * ca.Policy.rule..enable=true + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + + // XXX should do do this ? + // if CA does not allow subordinate CAs by way of basic constraints, + // this policy always rejects + /***** + ICertAuthority certAuthority = (ICertAuthority) + ((GenericPolicyProcessor)owner).mAuthority; + if (certAuthority instanceof ICertificateAuthority) { + CertificateChain caChain = certAuthority.getCACertChain(); + X509Certificate caCert = null; + // Note that in RA the chain could be null if CA was not up when + // RA was started. In that case just set the length to -1 and let + // CA reject if it does not allow any subordinate CA certs. + if (caChain != null) { + caCert = caChain.getFirstCertificate(); + if (caCert != null) + mCAPathLen = caCert.getBasicConstraints(); + } + } + ****/ + + mEnabled = mConfig.getBoolean( + IPolicyProcessor.PROP_ENABLE, false); + mCritical = mConfig.getBoolean(PROP_CRITICAL, DEF_CRITICAL); + + mReqExplicitPolicy = mConfig.getInteger( + PROP_REQ_EXPLICIT_POLICY, DEF_REQ_EXPLICIT_POLICY); + mInhibitPolicyMapping = mConfig.getInteger( + PROP_INHIBIT_POLICY_MAPPING, DEF_INHIBIT_POLICY_MAPPING); + + if (mReqExplicitPolicy < -1) + mReqExplicitPolicy = -1; + if (mInhibitPolicyMapping < -1) + mInhibitPolicyMapping = -1; + + // create instance of policy constraings extension + try { + mPolicyConstraintsExtension = + new PolicyConstraintsExtension(mCritical, + mReqExplicitPolicy, mInhibitPolicyMapping); + CMS.debug( + "PolicyConstraintsExt: Created Policy Constraints Extension: " + + mPolicyConstraintsExtension); + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_CANT_INIT_POLICY_CONST_EXT", e.toString())); + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", + "Could not init Policy Constraints Extension. Error: " + e)); + } + + // form instance params + mInstanceParams.addElement(PROP_CRITICAL + "=" + mCritical); + mInstanceParams.addElement( + PROP_REQ_EXPLICIT_POLICY + "=" + mReqExplicitPolicy); + mInstanceParams.addElement( + PROP_INHIBIT_POLICY_MAPPING + "=" + mInhibitPolicyMapping); + } + + /** + * Adds Policy Constraints Extension to a (CA) certificate. + * + * If a Policy constraints Extension is already there, accept it if + * it's been approved by agent, else replace it. + * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + // if extension hasn't been properly configured reject requests until + // it has been resolved (or disabled). + if (mPolicyConstraintsExtension == null) { + return PolicyResult.ACCEPTED; + } + + // get certInfo from request. + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult certRes = applyCert(req, ci[i]); + + if (certRes == PolicyResult.REJECTED) + return certRes; + } + return PolicyResult.ACCEPTED; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + + // check if name constraints extension already exists. + // if not agent approved, replace name constraints extension with ours. + // else ignore. + try { + PolicyConstraintsExtension policyConstraintsExt = null; + CertificateExtensions extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + + try { + if (extensions != null) { + policyConstraintsExt = (PolicyConstraintsExtension) + extensions.get(PolicyConstraintsExtension.NAME); + } + } catch (IOException e) { + // extension isn't there. + } + + if (policyConstraintsExt != null) { + if (agentApproved(req)) { + return PolicyResult.ACCEPTED; + } else { + extensions.delete(PolicyConstraintsExtension.NAME); + } + } + + if (extensions == null) { + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } + extensions.set( + "PolicyConstriantsExt", mPolicyConstraintsExtension); + CMS.debug("PolicyConstraintsExt: added our policy constraints extension"); + return PolicyResult.ACCEPTED; + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_CANT_PROCESS_POLICY_CONST_EXT", e.toString())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, e.getMessage()); + return PolicyResult.REJECTED; + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CERT_INFO_ERROR", e.toString())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Certificate Info Error"); + return PolicyResult.REJECTED; + } + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + return mInstanceParams; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return mDefaultParams; + } + + /** + * gets plugin info for pretty console edit displays. + */ + public String[] getExtendedPluginInfo(Locale locale) { + mInstanceParams.addElement(PROP_CRITICAL + "=" + mCritical); + mInstanceParams.addElement( + PROP_REQ_EXPLICIT_POLICY + "=" + mReqExplicitPolicy); + mInstanceParams.addElement( + PROP_INHIBIT_POLICY_MAPPING + "=" + mInhibitPolicyMapping); + + String[] params = { + PROP_CRITICAL + ";boolean;RFC 2459 recommendation: may be critical or non-critical.", + PROP_REQ_EXPLICIT_POLICY + ";integer;Number of addional certificates that may appear in the path before an explicit policy is required. If less than 0 this field is unset in the extension.", + PROP_INHIBIT_POLICY_MAPPING + ";integer;Number of addional certificates that may appear in the path before policy mapping is no longer permitted. If less than 0 this field is unset in the extension.", + IExtendedPluginInfo.HELP_TOKEN + ";configuration-policyrules-policyconstraints" + }; + + return params; + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/PolicyMappingsExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/PolicyMappingsExt.java new file mode 100644 index 000000000..aafecb17a --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/PolicyMappingsExt.java @@ -0,0 +1,417 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.ca.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.logging.ILogger; +import netscape.security.x509.*; +import netscape.security.util.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Policy Mappings Extension Policy + * Adds the Policy Mappings extension to a (CA) certificate. + * Filtering of CA certificates is done through predicates. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class PolicyMappingsExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + protected static final String PROP_CRITICAL = "critical"; + protected static final String PROP_NUM_POLICYMAPPINGS = "numPolicyMappings"; + + protected static final String PROP_POLICYMAP = "policyMap"; + + protected static final boolean DEF_CRITICAL = false; + protected static final int DEF_NUM_POLICYMAPPINGS = 1; + + protected boolean mEnabled = false; + protected IConfigStore mConfig = null; + + protected boolean mCritical = DEF_CRITICAL; + protected int mNumPolicyMappings = DEF_NUM_POLICYMAPPINGS; + protected PolicyMap[] mPolicyMaps = null; + protected PolicyMappingsExtension mPolicyMappingsExtension = null; + + protected Vector mInstanceParams = new Vector(); + + public PolicyMappingsExt() { + NAME = "PolicyMappingsExt"; + DESC = "Sets Policy Mappings Extension on subordinate CA certificates"; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries may be of the form: + * + * ca.Policy.rule..predicate=certType==ca + * ca.Policy.rule..implName= + * ca.Policy.rule..enable=true + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + + // XXX should do do this ? + // if CA does not allow subordinate CAs by way of basic constraints, + // this policy always rejects + /***** + ICertAuthority certAuthority = (ICertAuthority) + ((IPolicyProcessor)owner).getAuthority(); + if (certAuthority instanceof ICertificateAuthority) { + CertificateChain caChain = certAuthority.getCACertChain(); + X509Certificate caCert = null; + // Note that in RA the chain could be null if CA was not up when + // RA was started. In that case just set the length to -1 and let + // CA reject if it does not allow any subordinate CA certs. + if (caChain != null) { + caCert = caChain.getFirstCertificate(); + if (caCert != null) + mCAPathLen = caCert.getBasicConstraints(); + } + } + ****/ + + mEnabled = mConfig.getBoolean( + IPolicyProcessor.PROP_ENABLE, false); + mCritical = mConfig.getBoolean(PROP_CRITICAL, DEF_CRITICAL); + + mNumPolicyMappings = mConfig.getInteger( + PROP_NUM_POLICYMAPPINGS, DEF_NUM_POLICYMAPPINGS); + if (mNumPolicyMappings < 1) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("BASE_INVALID_ATTR_VALUE_2", NAME, "")); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + PROP_NUM_POLICYMAPPINGS, + "value must be greater than or equal to 1")); + } + + // init Policy Mappings, check values if enabled. + mPolicyMaps = new PolicyMap[mNumPolicyMappings]; + for (int i = 0; i < mNumPolicyMappings; i++) { + String subtreeName = PROP_POLICYMAP + i; + + try { + mPolicyMaps[i] = new PolicyMap(subtreeName, mConfig, mEnabled); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, NAME + ": " + + CMS.getLogMessage("POLICY_ERROR_CREATE_MAP", e.toString())); + throw e; + } + } + + // create instance of policy mappings extension if enabled. + if (mEnabled) { + try { + Vector certPolicyMaps = new Vector(); + + for (int j = 0; j < mNumPolicyMappings; j++) { + certPolicyMaps.addElement( + mPolicyMaps[j].mCertificatePolicyMap); + } + mPolicyMappingsExtension = + new PolicyMappingsExtension(mCritical, certPolicyMaps); + } catch (IOException e) { + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", + "Error initializing " + NAME + " Error: " + e)); + } + } + + // form instance params + mInstanceParams.addElement(PROP_CRITICAL + "=" + mCritical); + mInstanceParams.addElement( + PROP_NUM_POLICYMAPPINGS + "=" + mNumPolicyMappings); + for (int i = 0; i < mNumPolicyMappings; i++) { + mPolicyMaps[i].getInstanceParams(mInstanceParams); + } + } + + /** + * Adds policy mappings Extension to a (CA) certificate. + * + * If a policy mappings Extension is already there, accept it if + * it's been approved by agent, else replace it. + * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + // if extension hasn't been properly configured reject requests until + // it has been resolved (or disabled). + if (mPolicyMappingsExtension == null) { + //setError(req, PolicyResources.EXTENSION_NOT_INITED_1, NAME); + //return PolicyResult.REJECTED; + return PolicyResult.ACCEPTED; + } + + // get certInfo from request. + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult certRes = applyCert(req, ci[i]); + + if (certRes == PolicyResult.REJECTED) + return certRes; + } + return PolicyResult.ACCEPTED; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + // check if policy mappings extension already exists. + // if not agent approved, replace policy mappings extension with ours. + // else ignore. + try { + PolicyMappingsExtension policyMappingsExt = null; + CertificateExtensions extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + + try { + if (extensions != null) { + policyMappingsExt = (PolicyMappingsExtension) + extensions.get(PolicyMappingsExtension.NAME); + } + } catch (IOException e) { + // extension isn't there. + } + + if (policyMappingsExt != null) { + if (agentApproved(req)) { + return PolicyResult.ACCEPTED; + } else { + extensions.delete(PolicyMappingsExtension.NAME); + } + } + + if (extensions == null) { + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } + extensions.set( + PolicyMappingsExtension.NAME, mPolicyMappingsExtension); + return PolicyResult.ACCEPTED; + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_PROCESS_POLICYMAP_EXT", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, e.getMessage()); + return PolicyResult.REJECTED; + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CERT_INFO_ERROR", e.toString())); + + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Certificate Info Error"); + return PolicyResult.REJECTED; + } + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + return mInstanceParams; + } + + /** + * Default config parameters. + * To add more permitted or excluded subtrees, + * increase the num to greater than 0 and more configuration params + * will show up in the console. + */ + private static Vector mDefParams = new Vector(); + static { + mDefParams.addElement(PROP_CRITICAL + "=" + DEF_CRITICAL); + mDefParams.addElement( + PROP_NUM_POLICYMAPPINGS + "=" + DEF_NUM_POLICYMAPPINGS); + String policyMap0Dot = PROP_POLICYMAP + "0."; + + mDefParams.addElement( + policyMap0Dot + PolicyMap.PROP_ISSUER_DOMAIN_POLICY + "=" + ""); + mDefParams.addElement( + policyMap0Dot + PolicyMap.PROP_SUBJECT_DOMAIN_POLICY + "=" + ""); + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return mDefParams; + } + + public String[] getExtendedPluginInfo(Locale locale) { + Vector theparams = new Vector(); + + theparams.addElement(PROP_CRITICAL + ";boolean;RFC 2459 recommendation: MUST be non-critical."); + theparams.addElement(PROP_NUM_POLICYMAPPINGS + ";number; Number of policy mappings. The value must be greater than or equal to 1"); + + String policyInfo = + ";string;An object identifier in the form n.n.n.n"; + + for (int k = 0; k < 5; k++) { + String policyMapkDot = PROP_POLICYMAP + k + "."; + + theparams.addElement(policyMapkDot + + PolicyMap.PROP_ISSUER_DOMAIN_POLICY + policyInfo); + theparams.addElement(policyMapkDot + + PolicyMap.PROP_SUBJECT_DOMAIN_POLICY + policyInfo); + } + + theparams.addElement(IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-policymappings"); + theparams.addElement(IExtendedPluginInfo.HELP_TEXT + + ";Adds Policy Mappings Extension. See RFC 2459 (4.2.1.6)"); + + String[] params = new String[theparams.size()]; + + theparams.copyInto(params); + return params; + } +} + + +class PolicyMap { + + protected static String PROP_ISSUER_DOMAIN_POLICY = "issuerDomainPolicy"; + protected static String PROP_SUBJECT_DOMAIN_POLICY = "subjectDomainPolicy"; + + protected String mName = null; + protected String mNameDot = null; + protected IConfigStore mConfig = null; + protected String mIssuerDomainPolicy = null; + protected String mSubjectDomainPolicy = null; + protected CertificatePolicyMap mCertificatePolicyMap = null; + + /** + * forms policy map parameters. + * @param name name of this policy map, for example policyMap0 + * @param config parent's config from where we find this configuration. + * @param enabled whether policy was enabled. + */ + protected PolicyMap(String name, IConfigStore config, boolean enabled) + throws EBaseException { + mName = name; + mConfig = config.getSubStore(mName); + mNameDot = mName + "."; + + if( mConfig == null ) { + CMS.debug( "PolicyMappingsExt::PolicyMap - mConfig is null!" ); + return; + } + + // if there's no configuration for this map put it there. + if (mConfig.size() == 0) { + config.putString(mNameDot + PROP_ISSUER_DOMAIN_POLICY, ""); + config.putString(mNameDot + PROP_SUBJECT_DOMAIN_POLICY, ""); + mConfig = config.getSubStore(mName); + if (mConfig == null || mConfig.size() == 0) { + CMS.debug( "PolicyMappingsExt::PolicyMap - mConfig " + + "is null or empty!" ); + return; + } + } + + // get policy ids from configuration. + mIssuerDomainPolicy = + mConfig.getString(PROP_ISSUER_DOMAIN_POLICY, null); + mSubjectDomainPolicy = + mConfig.getString(PROP_SUBJECT_DOMAIN_POLICY, null); + + // adjust for "" and console returning "null" + if (mIssuerDomainPolicy != null && + (mIssuerDomainPolicy.length() == 0 || + mIssuerDomainPolicy.equals("null"))) { + mIssuerDomainPolicy = null; + } + if (mSubjectDomainPolicy != null && + (mSubjectDomainPolicy.length() == 0 || + mSubjectDomainPolicy.equals("null"))) { + mSubjectDomainPolicy = null; + } + + // policy ids cannot be null if policy is enabled. + String msg = "value cannot be null."; + + if (mIssuerDomainPolicy == null && enabled) + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + mNameDot + PROP_ISSUER_DOMAIN_POLICY, msg)); + if (mSubjectDomainPolicy == null && enabled) + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + mNameDot + PROP_SUBJECT_DOMAIN_POLICY, msg)); + + // if a policy id is not null check that it is a valid OID. + ObjectIdentifier issuerPolicyId = null; + ObjectIdentifier subjectPolicyId = null; + + if (mIssuerDomainPolicy != null) + issuerPolicyId = CMS.checkOID( + mNameDot + PROP_ISSUER_DOMAIN_POLICY, mIssuerDomainPolicy); + if (mSubjectDomainPolicy != null) + subjectPolicyId = CMS.checkOID( + mNameDot + PROP_SUBJECT_DOMAIN_POLICY, mSubjectDomainPolicy); + + // if enabled, form CertificatePolicyMap to be encoded in extension. + // policy ids should be all set. + if (enabled) { + mCertificatePolicyMap = new CertificatePolicyMap( + new CertificatePolicyId(issuerPolicyId), + new CertificatePolicyId(subjectPolicyId)); + } + } + + protected void getInstanceParams(Vector instanceParams) { + instanceParams.addElement( + mNameDot + PROP_ISSUER_DOMAIN_POLICY + "=" + (mIssuerDomainPolicy == null ? "" : + mIssuerDomainPolicy)); + instanceParams.addElement( + mNameDot + PROP_SUBJECT_DOMAIN_POLICY + "=" + (mSubjectDomainPolicy == null ? "" : + mSubjectDomainPolicy)); + } + +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/PresenceExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/PresenceExt.java new file mode 100644 index 000000000..60da8f9a3 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/PresenceExt.java @@ -0,0 +1,164 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.ca.*; +import com.netscape.certsrv.authority.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.extensions.*; +import com.netscape.certsrv.ca.*; +import netscape.ldap.*; +import netscape.security.extensions.*; +import com.netscape.cms.policy.APolicyRule; + +/** + * Checks extension presence. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class PresenceExt extends APolicyRule { + private static Vector mDefParams = new Vector(); + private IConfigStore mConfig = null; + private String mOID = null; + private boolean mCritical; + private int mVersion = 0; + private String mStreetAddress; + private String mTelephoneNumber; + private String mRFC822Name; + private String mID; + private String mHostName; + private int mPortNumber = 0; + private int mMaxUsers = 0; + private int mServiceLevel = 0; + + public static final String PROP_IS_CRITICAL = "critical"; + public static final String PROP_OID = "oid"; + public static final String PROP_VERSION = "version"; + public static final String PROP_STREET_ADDRESS = "streetAddress"; + public static final String PROP_TELEPHONE_NUMBER = "telephoneNumber"; + public static final String PROP_RFC822_NAME = "rfc822Name"; + public static final String PROP_ID = "id"; + public static final String PROP_HOSTNAME = "hostName"; + public static final String PROP_PORT_NUMBER = "portNumber"; + public static final String PROP_MAX_USERS = "maxUsers"; + public static final String PROP_SERVICE_LEVEL = "serviceLevel"; + + static { + mDefParams.addElement(PROP_IS_CRITICAL + "=false"); + } + + public PresenceExt() { + NAME = "PresenceExtPolicy"; + DESC = "Sets Presence Server Extension in certificates."; + } + + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + + mCritical = config.getBoolean(PROP_IS_CRITICAL, false); + mOID = config.getString(PROP_OID, ""); + mVersion = config.getInteger(PROP_VERSION, 0); + mStreetAddress = config.getString(PROP_STREET_ADDRESS, ""); + mTelephoneNumber = config.getString(PROP_TELEPHONE_NUMBER, ""); + mRFC822Name = config.getString(PROP_RFC822_NAME, ""); + mID = config.getString(PROP_ID, ""); + mHostName = config.getString(PROP_HOSTNAME, ""); + mPortNumber = config.getInteger(PROP_PORT_NUMBER, 0); + mMaxUsers = config.getInteger(PROP_MAX_USERS, 0); + mServiceLevel = config.getInteger(PROP_SERVICE_LEVEL, 0); + } + + public PolicyResult apply(IRequest req) { + PolicyResult res = PolicyResult.ACCEPTED; + + /* + PresenceServerExtension ext = new PresenceServerExtension(mCritical, + mOID, mVersion, mStreetAddress, + mTelephoneNumber, mRFC822Name, mID, + mHostName, mPortNumber, mMaxUsers, mServiceLevel); + */ + + return res; + } + + public Vector getInstanceParams() { + Vector params = new Vector(); + + params.addElement(PROP_IS_CRITICAL + "=" + mCritical); + params.addElement(PROP_OID + "=" + mOID); + params.addElement(PROP_VERSION + "=" + mVersion); + params.addElement(PROP_STREET_ADDRESS + "=" + mStreetAddress); + params.addElement(PROP_TELEPHONE_NUMBER + "=" + mTelephoneNumber); + params.addElement(PROP_RFC822_NAME + "=" + mRFC822Name); + params.addElement(PROP_ID + "=" + mID); + params.addElement(PROP_HOSTNAME + "=" + mHostName); + params.addElement(PROP_PORT_NUMBER + "=" + mPortNumber); + params.addElement(PROP_MAX_USERS + "=" + mMaxUsers); + params.addElement(PROP_SERVICE_LEVEL + "=" + mServiceLevel); + return params; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_IS_CRITICAL + ";boolean;Criticality", + PROP_OID + ";string; Object identifier of this extension", + PROP_VERSION + ";string; version", + PROP_STREET_ADDRESS + ";string; street address", + PROP_TELEPHONE_NUMBER + ";string; telephone number", + PROP_RFC822_NAME + ";string; rfc822 name", + PROP_ID + ";string; identifier", + PROP_HOSTNAME + ";string; host name", + PROP_PORT_NUMBER + ";string; port number", + PROP_MAX_USERS + ";string; max users", + PROP_SERVICE_LEVEL + ";string; service level", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-presenceext", + IExtendedPluginInfo.HELP_TEXT + + ";Adds Presence Server Extension;" + + }; + + return params; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return mDefParams; + } +} diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/PrivateKeyUsagePeriodExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/PrivateKeyUsagePeriodExt.java new file mode 100644 index 000000000..468abdf7b --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/PrivateKeyUsagePeriodExt.java @@ -0,0 +1,250 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.text.SimpleDateFormat; +import java.security.cert.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.logging.ILogger; +import netscape.security.x509.*; +import netscape.ldap.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * PrivateKeyUsagePeriod Identifier Extension policy. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class PrivateKeyUsagePeriodExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + + private final static String PROP_NOT_BEFORE = "notBefore"; + private final static String PROP_NOT_AFTER = "notAfter"; + protected static final String PROP_IS_CRITICAL = "critical"; + + // 6 months roughly + private final static long defDuration = 60L * 60 * 24 * 180 * 1000; + + private static final String DATE_PATTERN = "MM/dd/yyyy"; + static SimpleDateFormat formatter = new SimpleDateFormat(DATE_PATTERN); + private static Date now = CMS.getCurrentDate(); + private static Date six_months = new Date(now.getTime() + defDuration); + + public static final String DEFAULT_NOT_BEFORE = formatter.format(now); + public static final String DEFAULT_NOT_AFTER = formatter.format(six_months); + + // PKIX specifies the that the extension SHOULD NOT be critical + public static final boolean DEFAULT_CRITICALITY = false; + + protected String mNotBefore; + protected String mNotAfter; + protected boolean mCritical; + + private static Vector defaultParams; + + static { + + formatter.setLenient(false); + + defaultParams = new Vector(); + defaultParams.addElement(PROP_IS_CRITICAL + "=" + DEFAULT_CRITICALITY); + defaultParams.addElement(PROP_NOT_BEFORE + "=" + DEFAULT_NOT_BEFORE); + defaultParams.addElement(PROP_NOT_AFTER + "=" + DEFAULT_NOT_AFTER); + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_IS_CRITICAL + ";boolean;RFC 2459 recommendation: The profile " + + "recommends against the use of this extension. CAs " + + "conforming to the profile MUST NOT generate certs with " + + "critical private key usage period extensions.", + PROP_NOT_BEFORE + ";string; Date before which the Private Key is invalid.", + PROP_NOT_AFTER + ";string; Date after which the Private Key is invalid.", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-privatekeyusageperiod", + IExtendedPluginInfo.HELP_TEXT + + ";Adds (deprecated) Private Key Usage Period Extension. " + + "Defined in RFC 2459 (4.2.1.4)" + }; + + return params; + } + + /** + * Adds the private key usage extension to all certs. + */ + public PrivateKeyUsagePeriodExt() { + NAME = "PrivateKeyUsagePeriodExt"; + DESC = "Sets Private Key Usage Extension for a certificate"; + } + + /** + * Initializes this policy rule. + * ra.Policy.rule..implName=PrivateKeyUsageExtension + * ra.Policy.rule..enable=true + * ra.Policy.rule..notBefore=30 + * ra.Policy.rule..notAfter=180 + * ra.Policy.rule..critical=false + * ra.Policy.rule..predicate=ou==Sales + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + + try { + // Get params. + mNotBefore = config.getString(PROP_NOT_BEFORE, null); + mNotAfter = config.getString(PROP_NOT_AFTER, null); + mCritical = config.getBoolean(PROP_IS_CRITICAL, false); + + // Check the parameter formats + String notBefore; + String notAfter; + + notBefore = formatter.format(formatter.parse(mNotBefore.trim())); + notAfter = formatter.format(formatter.parse(mNotAfter.trim())); + } catch (Exception e) { + // e.printStackTrace(); + Object[] params = {getInstanceName(), e}; + + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_INVALID_POLICY_CONFIG"), params); + } + + } + + /** + * Adds a private key usage extension if none exists. + * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + PolicyResult res = PolicyResult.ACCEPTED; + + // get cert info. + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; // unrecoverable error. + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult certRes = applyCert(req, ci[i]); + + if (certRes == PolicyResult.REJECTED) + return certRes; + } + return PolicyResult.ACCEPTED; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + // get private key usage extension from cert info if any. + CertificateExtensions extensions = null; + PrivateKeyUsageExtension ext = null; + + try { + // get subject key id extension if any. + extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + } catch (IOException e) { + // no extensions or subject key identifier extension. + } catch (CertificateException e) { + // no extensions or subject key identifier extension. + } + + if (extensions == null) { + extensions = new CertificateExtensions(); + } else { + // remove any previously computed version of the extension + try { + extensions.delete(PrivateKeyUsageExtension.NAME); + + } catch (IOException e) { + } + + } + + try { + ext = new PrivateKeyUsageExtension( + formatter.parse(mNotBefore), + formatter.parse(mNotAfter)); + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + extensions.set(PrivateKeyUsageExtension.NAME, ext); + } catch (Exception e) { + if (e instanceof RuntimeException) + throw (RuntimeException) e; + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_CREATE_PRIVATE_KEY_EXT", e.toString())); + setError(req, CMS.getUserMessage("CMS_POLICY_SUBJECT_KEY_ID_ERROR"), NAME); + return PolicyResult.REJECTED; + } + return PolicyResult.ACCEPTED; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return Empty Vector since this policy has no configuration parameters. + * for this policy instance. + */ + public Vector getInstanceParams() { + Vector params = new Vector(); + + params.addElement(PROP_IS_CRITICAL + "=" + mCritical); + params.addElement(PROP_NOT_BEFORE + "=" + mNotBefore); + params.addElement(PROP_NOT_AFTER + "=" + mNotAfter); + return params; + } + + /** + * Return default parameters for a policy implementation. + * + * @return Empty Vector since this policy implementation has no + * configuration parameters. + */ + public Vector getDefaultParams() { + Vector defParams = new Vector(); + + defParams.addElement(PROP_IS_CRITICAL + "=" + DEFAULT_CRITICALITY); + defParams.addElement(PROP_NOT_BEFORE + "=" + DEFAULT_NOT_BEFORE); + defParams.addElement(PROP_NOT_AFTER + "=" + DEFAULT_NOT_AFTER); + return defParams; + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/RemoveBasicConstraintsExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/RemoveBasicConstraintsExt.java new file mode 100644 index 000000000..b8dba995e --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/RemoveBasicConstraintsExt.java @@ -0,0 +1,141 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.logging.ILogger; +import netscape.security.x509.*; +import netscape.ldap.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Remove Basic Constraints policy. + * Adds the Basic constraints extension. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class RemoveBasicConstraintsExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + public RemoveBasicConstraintsExt() { + NAME = "RemoveBasicConstraintsExt"; + DESC = "Remove Basic Constraints extension"; + } + + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + } + + public PolicyResult apply(IRequest req) { + PolicyResult res = PolicyResult.ACCEPTED; + + // get cert info. + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + X509CertInfo certInfo = null; + + if (ci == null || (certInfo = ci[0]) == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; // unrecoverable error. + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult certResult = applyCert(req, certInfo); + + if (certResult == PolicyResult.REJECTED) + return certResult; + } + return PolicyResult.ACCEPTED; + } + + public PolicyResult applyCert( + IRequest req, X509CertInfo certInfo) { + // get basic constraints extension from cert info if any. + CertificateExtensions extensions = null; + + try { + // get basic constraints extension if any. + extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + if (extensions != null) { + try { + extensions.delete(BasicConstraintsExtension.NAME); + CMS.debug("PolicyRule RemoveBasicConstraintsExt: removed the extension from request " + req.getRequestId().toString()); + } catch (IOException e) { + } + } + } catch (IOException e) { + // no extensions or basic constraints extension. + } catch (CertificateException e) { + // no extensions or basic constraints extension. + } + return PolicyResult.ACCEPTED; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector params = new Vector(); + + return params; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + Vector defParams = new Vector(); + + return defParams; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-removebasicconstraints", + IExtendedPluginInfo.HELP_TEXT + + ";Removes the Basic Constraints extension." + }; + + return params; + } + +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/SubjAltNameExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/SubjAltNameExt.java new file mode 100644 index 000000000..32e2c48fb --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/SubjAltNameExt.java @@ -0,0 +1,350 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.logging.ILogger; +import netscape.security.x509.*; +import netscape.ldap.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * + * THIS POLICY HAS BEEN DEPRECATED SINCE CMS 4.2. + * New Policy is com.netscape.certsrv.policy.SubjectAltNameExt. + *

+ * + * Subject Alternative Name extension policy in CMS 4.1. + * + * Adds the subject alternative name extension depending on the + * certificate type requested. + * + * Two forms are supported. 1) For S/MIME certificates, email + * addresses are copied from data stored in the request by the + * authentication component. Both 'e' and 'altEmail' are supported + * so that both the primary address and alternative forms may be + * certified. Only the primary goes in the subjectName position (which + * should be phased out). + * + * e + * mailAlternateAddress + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class SubjAltNameExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + // for future use. currently always allow. + protected static final String PROP_AGENT_OVERR = "allowAgentOverride"; + protected static final String PROP_EE_OVERR = "AllowEEOverride"; + protected static final String PROP_ENABLE_MANUAL_VALUES = + "enableManualValues"; + + // for future use. currently always non-critical + // (standard says SHOULD be marked critical if included.) + protected static final String PROP_CRITICAL = "critical"; + + // for future use to allow overrides from forms. + // request must be agent approved or authenticated. + protected boolean mAllowAgentOverride = false; + protected boolean mAllowEEOverride = false; + protected boolean mEnableManualValues = false; + + // for future use. currently always critical + // (standard says SHOULD be marked critical if included.) + protected boolean mCritical = false; + + public SubjAltNameExt() { + NAME = "SubjAltNameExt"; + DESC = "Sets alternative subject names for certificates"; + } + + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_CRITICAL + ";boolean;RFC 2459 recommendation: If the certificate subject field contains an empty sequence, the subjectAltName extension MUST be marked critical.", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-subjaltname", + IExtendedPluginInfo.HELP_TEXT + + ";This policy inserts the Subject Alternative Name " + + "Extension into the certificate. See RFC 2459 (4.2.1.7). " + + "* Note: you probably want to use this policy in " + + "conjunction with an authentication manager which sets " + + "the 'mail' or 'mailalternateaddress' values in the authToken. " + + "See the 'ldapStringAttrs' parameter in the Directory-based " + + "authentication plugin" + }; + + return params; + + } + + /** + * Initializes this policy rule. + *

+ * + * The entries may be of the form: + * + * ra.Policy.rule..implName=SubjAltNameExt + * ra.Policy.rule..enable=true + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + // future use. + mAllowAgentOverride = config.getBoolean(PROP_AGENT_OVERR, false); + mAllowEEOverride = config.getBoolean(PROP_EE_OVERR, false); + mCritical = config.getBoolean(PROP_CRITICAL, false); + // mEnableManualValues = config.getBoolean(PROP_ENABLE_MANUAL_VALUES, false); + } + + /** + * Adds the subject alternative names extension if not set already. + * + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + PolicyResult res = PolicyResult.ACCEPTED; + + // Find the X509CertInfo object in the request + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + + return PolicyResult.REJECTED; // unrecoverable error. + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult certRes = applyCert(req, ci[i]); + + if (certRes == PolicyResult.REJECTED) + return certRes; + } + return res; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + PolicyResult res = PolicyResult.ACCEPTED; + + // + // General error handling block + // + apply: + try { + + // Find the extensions in the certInfo + CertificateExtensions extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + + if (extensions != null) { + // + // Remove any previously computed version of the extension + // + try { + extensions.delete(SubjectAlternativeNameExtension.NAME); + } catch (IOException e) { + // extension isn't there + } + } + + // + // Determine the type of the request. For future expansion + // this test should dispatch to a specialized object to + // handle each particular type. For now just return for + // non-client certs, and implement client certs directly here. + // + String certType = + req.getExtDataInString(IRequest.HTTP_PARAMS, IRequest.CERT_TYPE); + + if (certType == null || + !certType.equals(IRequest.CLIENT_CERT) || + !req.getExtDataInBoolean(IRequest.SMIME, false)) { + break apply; + } + + // Create a list of email addresses that should be added + // to the certificate + + IAuthToken tok = findAuthToken(req, null); + + if (tok == null) break apply; + + Vector emails = getEmailList(tok); + + if (emails == null) break apply; + + // Create the extension + SubjectAlternativeNameExtension subjAltNameExt = mkExt(emails); + + if (extensions == null) + extensions = createCertificateExtensions(certInfo); + + extensions.set(SubjectAlternativeNameExtension.NAME, + subjAltNameExt); + + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("BASE_IO_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, e.getMessage()); + return PolicyResult.REJECTED; // unrecoverable error. + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CERT_INFO_ERROR", e.toString())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Certificate Info Error"); + return PolicyResult.REJECTED; // unrecoverable error. + } + + return res; + } + + /** + * Find a particular authentication token by manager name. + * If the token is not present return null + */ + protected IAuthToken + findAuthToken(IRequest req, String authMgrName) { + + return req.getExtDataInAuthToken(IRequest.AUTH_TOKEN); + } + + /** + * Generate a String Vector containing all the email addresses + * found in this Authentication token + */ + protected Vector /* of String */ + getEmailList(IAuthToken tok) { + + Vector v = new Vector(); + + addValues(tok, "mail", v); + addValues(tok, "mailalternateaddress", v); + + if (v.size() == 0) return null; + + return v; + } + + /** + * Add attribute values from an LDAP attribute to a vector + */ + protected void + addValues(IAuthToken tok, String attrName, Vector v) { + String attr[] = tok.getInStringArray(attrName); + + if (attr == null) return; + + for (int i = 0; i < attr.length; i++) { + v.addElement(attr[i]); + } + } + + /** + * Make a Subject name extension given a list of email addresses + */ + protected SubjectAlternativeNameExtension + mkExt(Vector emails) + throws IOException { + SubjectAlternativeNameExtension sa; + GeneralNames gns = new GeneralNames(); + + for (int i = 0; i < emails.size(); i++) { + String email = (String) emails.elementAt(i); + + gns.addElement(new RFC822Name(email)); + } + + sa = new SubjectAlternativeNameExtension(gns); + + return sa; + } + + /** + * Create a new SET of extensions in the certificate info + * object. + * + * This should be a method in the X509CertInfo object + */ + protected CertificateExtensions + createCertificateExtensions(X509CertInfo certInfo) + throws IOException, CertificateException { + CertificateExtensions extensions; + + // Force version to V3 + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + + return extensions; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + Vector params = new Vector(); + + //params.addElement("PROP_AGENT_OVERR = " + mAllowAgentOverride); + //params.addElement("PROP_EE_OVERR = " + mAllowEEOverride); + params.addElement(PROP_CRITICAL + "=" + mCritical); + // params.addElement(PROP_ENABLE_MANUAL_VALUES + " = " + + // mEnableManualValues); + return params; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + Vector defParams = new Vector(); + + //defParams.addElement("PROP_AGENT_OVERR = " + DEF_AGENT_OVERR); + //defParams.addElement("PROP_EE_OVERR = " + DEF_EE_OVERR); + defParams.addElement(PROP_CRITICAL + "=false"); + // defParams.addElement(PROP_ENABLE_MANUAL_VALUES + "= false"); + + return defParams; + } +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/SubjectAltNameExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/SubjectAltNameExt.java new file mode 100644 index 000000000..eb7dba173 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/SubjectAltNameExt.java @@ -0,0 +1,322 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.logging.ILogger; +import netscape.security.x509.*; +import netscape.ldap.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Subject Alternative Name extension policy. + * + * Adds the subject alternative name extension as configured. + * + * Two forms are supported. 1) For S/MIME certificates, email + * addresses are copied from data stored in the request by the + * authentication component. Both 'e' and 'altEmail' are supported + * so that both the primary address and alternative forms may be + * certified. Only the primary goes in the subjectName position (which + * should be phased out). + * + * e + * mailAlternateAddress + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class SubjectAltNameExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + // (standard says SHOULD be marked critical if included.) + protected static final String PROP_CRITICAL = "critical"; + protected static final boolean DEF_CRITICAL = false; + + protected IConfigStore mConfig = null; + protected boolean mEnabled = false; + protected boolean mCritical = DEF_CRITICAL; + protected int mNumGNs = 0; + protected ISubjAltNameConfig[] mGNs = null; + + Vector mInstanceParams = new Vector(); + + // init default params and extended plugin info. + private static Vector mDefParams = new Vector(); + static { + // default params. + mDefParams.addElement(PROP_CRITICAL + "=" + DEF_CRITICAL); + mDefParams.addElement( + IGeneralNameUtil.PROP_NUM_GENERALNAMES + "=" + + IGeneralNameUtil.DEF_NUM_GENERALNAMES); + for (int i = 0; i < IGeneralNameUtil.DEF_NUM_GENERALNAMES; i++) { + CMS.getSubjAltNameConfigDefaultParams( + IGeneralNameUtil.PROP_GENERALNAME + i, mDefParams); + } + } + + private String[] mExtendedPluginInfo = null; + + public SubjectAltNameExt() { + NAME = "SubjectAltNameExt"; + DESC = "Sets alternative subject names for certificates"; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries may be of the form: + * + * ra.Policy.rule..implName=SubjectAltNameExt + * ra.Policy.rule..enable=true + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + + // get criticality + mCritical = mConfig.getBoolean(PROP_CRITICAL, DEF_CRITICAL); + + // get enabled + mEnabled = mConfig.getBoolean( + IPolicyProcessor.PROP_ENABLE, false); + + // get general names configuration. + mNumGNs = mConfig.getInteger(IGeneralNameUtil.PROP_NUM_GENERALNAMES); + if (mNumGNs <= 0) { + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_MUST_BE_POSITIVE_NUMBER", + IGeneralNameUtil.PROP_NUM_GENERALNAMES)); + } + mGNs = new ISubjAltNameConfig[mNumGNs]; + for (int i = 0; i < mNumGNs; i++) { + String name = IGeneralNameUtil.PROP_GENERALNAME + i; + IConfigStore substore = mConfig.getSubStore(name); + + mGNs[i] = CMS.createSubjAltNameConfig(name, substore, mEnabled); + } + + // init instance params. + mInstanceParams.addElement(PROP_CRITICAL + "=" + mCritical); + mInstanceParams.addElement( + IGeneralNameUtil.PROP_NUM_GENERALNAMES + "=" + mNumGNs); + for (int j = 0; j < mGNs.length; j++) { + mGNs[j].getInstanceParams(mInstanceParams); + } + } + + /** + * Adds the subject alternative names extension if not set already. + * + *

+ * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + PolicyResult res = PolicyResult.ACCEPTED; + + // Find the X509CertInfo object in the request + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + + return PolicyResult.REJECTED; // unrecoverable error. + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult certRes = applyCert(req, ci[i]); + + if (certRes == PolicyResult.REJECTED) + return certRes; + } + return res; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + PolicyResult res = PolicyResult.ACCEPTED; + + try { + // Find the extensions in the certInfo + CertificateExtensions extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + + // Remove any previously computed version of the extension + // unless it is from RA. If from RA, accept what RA put in + // request and don't add our own. + if (extensions != null) { + String sourceId = req.getSourceId(); + + if (sourceId != null && sourceId.length() > 0) + return res; // accepted + try { + extensions.delete(SubjectAlternativeNameExtension.NAME); + } catch (IOException e) { + // extension isn't there + } + } + + // form list of general names for the extension. + GeneralNames gns = new GeneralNames(); + + for (int i = 0; i < mNumGNs; i++) { + Object value = null; + + value = req.getExtDataInString(mGNs[i].getPfx(), mGNs[i].getAttr()); + if (value == null) { + continue; + } + Vector gn = mGNs[i].formGeneralNames(value); + + if (gn.size() == 0) + continue; + for (Enumeration n = gn.elements(); n.hasMoreElements();) { + gns.addElement((GeneralName) n.nextElement()); + } + } + + // nothing was found in request to put into extension + if (gns.size() == 0) + return res; // accepted + + String subject = certInfo.get(X509CertInfo.SUBJECT).toString(); + + boolean curCritical = mCritical; + + if (subject.equals("")) { + curCritical = true; + } + + // make the extension + SubjectAlternativeNameExtension + sa = new SubjectAlternativeNameExtension(curCritical, gns); + + // add it to certInfo. + if (extensions == null) + extensions = createCertificateExtensions(certInfo); + + extensions.set(SubjectAlternativeNameExtension.NAME, sa); + + return res; // accepted. + + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("BASE_IO_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, e.getMessage()); + return PolicyResult.REJECTED; // unrecoverable error. + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CERT_INFO_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Certificate Info Error"); + return PolicyResult.REJECTED; // unrecoverable error. + } catch (Exception e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("BASE_INTERNAL_ERROR_1", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Internal Error"); + return PolicyResult.REJECTED; // unrecoverable error. + } + } + + /** + * Create a new SET of extensions in the certificate info + * object. + * + * This should be a method in the X509CertInfo object + */ + protected CertificateExtensions + createCertificateExtensions(X509CertInfo certInfo) + throws IOException, CertificateException { + CertificateExtensions extensions; + + // Force version to V3 + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + + return extensions; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + return mInstanceParams; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return mDefParams; + } + + public String[] getExtendedPluginInfo(Locale locale) { + + // extended plugin info. + Vector info = new Vector(); + + info.addElement(PROP_CRITICAL + ";boolean;RFC2459 recommendation: If the certificate subject field contains an empty sequence, the extension MUST be marked critical."); + info.addElement(IGeneralNameUtil.PROP_NUM_GENERALNAMES_INFO); + for (int i = 0; i < IGeneralNameUtil.DEF_NUM_GENERALNAMES; i++) { + CMS.getSubjAltNameConfigExtendedPluginInfo( + IGeneralNameUtil.PROP_GENERALNAME + i, info); + } + info.addElement(IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-subjaltname"); + info.addElement(IExtendedPluginInfo.HELP_TEXT + + ";This policy inserts the Subject Alternative Name " + + "Extension into the certificate. See RFC 2459 (4.2.1.7). " + + "* Note: you probably want to use this policy in " + + "conjunction with an authentication manager which sets " + + "the 'mail' or 'mailalternateaddress' values in the authToken. " + + "See the 'ldapStringAttrs' parameter in the Directory-based " + + "authentication plugin"); + mExtendedPluginInfo = new String[info.size()]; + info.copyInto(mExtendedPluginInfo); + return mExtendedPluginInfo; + } + +} + diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/SubjectDirectoryAttributesExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/SubjectDirectoryAttributesExt.java new file mode 100644 index 000000000..be065245a --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/SubjectDirectoryAttributesExt.java @@ -0,0 +1,434 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.extensions.*; +import com.netscape.certsrv.apps.*; +import netscape.security.x509.*; +import netscape.security.util.*; +import netscape.ldap.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Policy to add the subject directory attributes extension. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class SubjectDirectoryAttributesExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + protected static final String PROP_CRITICAL = "critical"; + protected static final String PROP_ATTRIBUTE = "attribute"; + protected static final String PROP_NUM_ATTRIBUTES = "numAttributes"; + + protected static final boolean DEF_CRITICAL = false; + protected static final int DEF_NUM_ATTRIBUTES = 3; + protected static final int MAX_NUM_ATTRIBUTES = 10; + + protected boolean mCritical; + protected int mNumAttributes; + protected AttributeConfig[] mAttributes = null; + + protected IConfigStore mConfig; + protected SubjectDirAttributesExtension mExt = null; + + protected Vector mParams = new Vector(); + private String[] mEPI = null; // extended plugin info + protected static Vector mDefParams = new Vector(); + + static { + setDefaultParams(); + } + + public SubjectDirectoryAttributesExt() { + NAME = "SubjectDirectoryAttributesExtPolicy"; + DESC = "Sets Subject Directory Attributes Extension in certificates."; + setExtendedPluginInfo(); + } + + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + boolean enabled = config.getBoolean("enabled", false); + + mConfig = config; + + mCritical = mConfig.getBoolean(PROP_CRITICAL, false); + mNumAttributes = mConfig.getInteger(PROP_NUM_ATTRIBUTES, DEF_NUM_ATTRIBUTES); + if (mNumAttributes < 1) { + EBaseException ex = new EBaseException( + CMS.getUserMessage("CMS_BASE_MUST_BE_POSITIVE_NUMBER", PROP_NUM_ATTRIBUTES)); + + log(ILogger.LL_FAILURE, NAME + " Error: " + ex.toString()); + throw ex; + } + mAttributes = new AttributeConfig[mNumAttributes]; + for (int i = 0; i < mNumAttributes; i++) { + String name = PROP_ATTRIBUTE + i; + IConfigStore c = mConfig.getSubStore(name); + + mAttributes[i] = new AttributeConfig(name, c, enabled); + } + if (enabled) { + try { + mExt = formExt(null); + } catch (IOException e) { + log(ILogger.LL_FAILURE, NAME + " Error: " + e.getMessage()); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", + "Error forming Subject Directory Attributes Extension. " + + "See log file for details.")); + } + } + setInstanceParams(); + } + + public PolicyResult apply(IRequest req) { + PolicyResult res = PolicyResult.ACCEPTED; + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; // unrecoverable error. + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult r = applyCert(req, ci[i]); + + if (r == PolicyResult.REJECTED) + return r; + } + return PolicyResult.ACCEPTED; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + CertificateExtensions extensions = null; + SubjectDirAttributesExtension subjDirExt = null; + + try { + // get extension and remove if exists. + extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + if (extensions == null) { + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } else { + try { + extensions.delete(SubjectDirAttributesExtension.NAME); + } catch (IOException ee) { + // if name is not found, try deleting the extension using the OID + try { + extensions.delete("2.5.29.9"); + } catch (IOException eee) { + } + } + } + + // form extension and set. + if (mExt != null) { + extensions.set(SubjectDirAttributesExtension.NAME, mExt); + } else { + SubjectDirAttributesExtension ext = formExt(req); + + if (ext != null) + extensions.set(SubjectDirAttributesExtension.NAME, formExt(req)); + } + return PolicyResult.ACCEPTED; + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CERT_INFO_ERROR", e.getMessage())); + + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Certificate Info Error"); + return PolicyResult.REJECTED; // unrecoverable error. + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("BASE_IO_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "IOException Error"); + return PolicyResult.REJECTED; + } + } + + private Vector formValues(String val) { + StringTokenizer tokenizer = new StringTokenizer(val, "+"); + Vector v = new Vector(); + + while (tokenizer.hasMoreElements()) { + String s = (String) tokenizer.nextElement(); + + v.addElement(s); + } + return v; + } + + public Vector getInstanceParams() { + return mParams; // inited in init() + } + + public Vector getDefaultParams() { + return mDefParams; + } + + public String[] getExtendedPluginInfo(Locale locale) { + return mEPI; // inited in the constructor. + } + + private void setInstanceParams() { + mParams.addElement(PROP_CRITICAL + "=" + mCritical); + mParams.addElement(PROP_NUM_ATTRIBUTES + "=" + mNumAttributes); + for (int i = 0; i < mNumAttributes; i++) { + mAttributes[i].getInstanceParams(mParams); + } + // clean up others if exists. expensive. + for (int j = mNumAttributes; j < MAX_NUM_ATTRIBUTES; j++) { + mConfig.removeSubStore(PROP_ATTRIBUTE + j); + } + } + + private static void setDefaultParams() { + mDefParams.addElement(PROP_CRITICAL + "=" + DEF_CRITICAL); + mDefParams.addElement(PROP_NUM_ATTRIBUTES + "=" + DEF_NUM_ATTRIBUTES); + for (int i = 0; i < DEF_NUM_ATTRIBUTES; i++) { + AttributeConfig.getDefaultParams(PROP_ATTRIBUTE + i, mDefParams); + } + } + + private void setExtendedPluginInfo() { + Vector v = new Vector(); + + v.addElement(PROP_CRITICAL + ";boolean;" + + "RFC 2459 recommendation: MUST be non-critical."); + v.addElement(PROP_NUM_ATTRIBUTES + ";number;" + + "Number of Attributes in the extension."); + + for (int i = 0; i < MAX_NUM_ATTRIBUTES; i++) { + AttributeConfig.getExtendedPluginInfo(PROP_ATTRIBUTE + i, v); + } + + v.addElement(IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-subjectdirectoryattributes"); + v.addElement(IExtendedPluginInfo.HELP_TEXT + + ";Adds Subject Directory Attributes extension. See RFC 2459 (4.2.1.9). It's not recommended as an essential part of the profile, but may be used in local environments."); + + mEPI = com.netscape.cmsutil.util.Utils.getStringArrayFromVector(v); + } + + private SubjectDirAttributesExtension formExt(IRequest req) + throws IOException { + Vector attrs = new Vector(); + + // if we're called from init and one attribute is from request attribute + // the ext can't be formed yet. + if (req == null) { + for (int i = 0; i < mNumAttributes; i++) { + if (mAttributes[i].mWhereToGetValue == + AttributeConfig.USE_REQUEST_ATTR) + return null; + } + } + // either we're called from apply or all values are fixed. + for (int i = 0; i < mNumAttributes; i++) { + if (mAttributes[i].mAttribute != null) { + attrs.addElement(mAttributes[i].mAttribute); + } else { + // skip attribute if request attribute doesn't exist. + Attribute a = mAttributes[i].formAttr(req); + + if (a == null) + continue; + attrs.addElement(a); + } + } + if (attrs.size() == 0) + return null; + Attribute[] attrList = new Attribute[attrs.size()]; + + attrs.copyInto(attrList); + SubjectDirAttributesExtension ext = + new SubjectDirAttributesExtension(attrList); + + return ext; + } +} + + +class AttributeConfig { + + protected static final String PROP_ATTRIBUTE_NAME = "attributeName"; + protected static final String PROP_WTG_VALUE = "whereToGetValue"; + protected static final String PROP_VALUE = "value"; + + protected static final String USE_REQUEST_ATTR = "Request Attribute"; + protected static final String USE_FIXED = "Fixed Value"; + + protected String mAttributeName = null; + protected String mWhereToGetValue = null; + protected String mValue = null; + + protected String mPrefix = null; + protected String mReqAttr = null; + protected ObjectIdentifier mAttributeOID = null; + + protected String mName = null; + protected IConfigStore mConfig = null; + protected Attribute mAttribute = null; + + protected static final String ATTRIBUTE_NAME_INFO = "Attribute name."; + protected static final String WTG_VALUE_INFO = + PROP_WTG_VALUE + ";choice(" + USE_REQUEST_ATTR + "," + USE_FIXED + ");" + + "Get value from a request attribute or use a fixed value specified below."; + protected static final String VALUE_INFO = + PROP_VALUE + ";string;" + + "Request attribute name or a fixed value to put into the extension."; + + public AttributeConfig(String name, IConfigStore config, boolean enabled) + throws EBaseException { + X500NameAttrMap map = X500NameAttrMap.getDefault(); + + mName = name; + mConfig = config; + if (enabled) { + mAttributeName = mConfig.getString(PROP_ATTRIBUTE_NAME); + mWhereToGetValue = mConfig.getString(PROP_WTG_VALUE); + mValue = mConfig.getString(PROP_VALUE); + } else { + mAttributeName = mConfig.getString(PROP_ATTRIBUTE_NAME, ""); + mWhereToGetValue = mConfig.getString(PROP_WTG_VALUE, USE_REQUEST_ATTR); + mValue = mConfig.getString(PROP_VALUE, ""); + } + + if (mAttributeName.length() > 0) { + mAttributeOID = map.getOid(mAttributeName); + if (mAttributeOID == null) + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", mAttributeName)); + } + + if (mWhereToGetValue.equalsIgnoreCase(USE_REQUEST_ATTR)) { + mWhereToGetValue = USE_REQUEST_ATTR; + if (enabled && mValue.length() == 0) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_GET_PROPERTY_FAILED", PROP_VALUE)); + } + int dot = mValue.indexOf('.'); + + if (dot != -1) { + mPrefix = mValue.substring(0, dot); + mReqAttr = mValue.substring(dot + 1); + if (mPrefix == null || mPrefix.length() == 0 || + mReqAttr == null || mReqAttr.length() == 0) { + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", mValue)); + } + } else { + mPrefix = null; + mReqAttr = mValue; + } + } else if (mWhereToGetValue.equalsIgnoreCase(USE_FIXED)) { + mWhereToGetValue = USE_FIXED; + if (mAttributeOID != null) { + try { + checkValue(mAttributeOID, mValue); + mAttribute = new Attribute(mAttributeOID, mValue); + } catch (Exception e) { + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + mAttributeName, e.getMessage())); + } + } + } else if (enabled || mWhereToGetValue.length() > 0) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_VALUE_FOR_TYPE", PROP_WTG_VALUE, + "Must be either '" + USE_REQUEST_ATTR + "' or '" + USE_FIXED + "'.")); + } + } + + public static void getDefaultParams(String name, Vector v) { + String nameDot = name + "."; + + v.addElement(nameDot + PROP_ATTRIBUTE_NAME + "="); + v.addElement(nameDot + PROP_WTG_VALUE + "=" + USE_REQUEST_ATTR); + v.addElement(nameDot + PROP_VALUE + "="); + } + + public static void getExtendedPluginInfo(String name, Vector v) { + String nameDot = name + "."; + String attrChoices = getAllNames(); + + v.addElement(nameDot + PROP_ATTRIBUTE_NAME + ";choice(" + attrChoices + ");" + + ATTRIBUTE_NAME_INFO); + v.addElement(nameDot + WTG_VALUE_INFO); + v.addElement(nameDot + VALUE_INFO); + } + + public void getInstanceParams(Vector v) { + String nameDot = mName + "."; + + v.addElement(nameDot + PROP_ATTRIBUTE_NAME + "=" + mAttributeName); + v.addElement(nameDot + PROP_WTG_VALUE + "=" + mWhereToGetValue); + v.addElement(nameDot + PROP_VALUE + "=" + mValue); + } + + public Attribute formAttr(IRequest req) + throws IOException { + String val = req.getExtDataInString(mPrefix, mReqAttr); + + if (val == null || val.length() == 0) { + return null; + } + checkValue(mAttributeOID, val); + return new Attribute(mAttributeOID, val); + } + + static private String getAllNames() { + Enumeration n = X500NameAttrMap.getDefault().getAllNames(); + StringBuffer sb = new StringBuffer(); + sb.append((String) n.nextElement()); + + while (n.hasMoreElements()) { + sb.append(","); + sb.append((String) n.nextElement()); + } + return sb.toString(); + } + + private static void checkValue(ObjectIdentifier oid, String val) + throws IOException { + AVAValueConverter c = X500NameAttrMap.getDefault().getValueConverter(oid); + DerValue derval; + + derval = c.getValue(val); // errs encountered will get thrown. + return; + } + +} diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/SubjectKeyIdentifierExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/SubjectKeyIdentifierExt.java new file mode 100644 index 000000000..a8069be29 --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/SubjectKeyIdentifierExt.java @@ -0,0 +1,368 @@ +// --- 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.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.ca.*; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.apps.*; +import netscape.security.x509.*; +import netscape.security.util.*; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.InvalidKeyException; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Subject Public Key Extension Policy + * Adds the subject public key id extension to certificates. + *

+ *

+ * NOTE:  The Policy Framework has been replaced by the Profile Framework.
+ * 
+ *

+ * + * @deprecated + * @version $Revision$, $Date$ + */ +public class SubjectKeyIdentifierExt extends APolicyRule + implements IEnrollmentPolicy, IExtendedPluginInfo { + protected static final String PROP_CRITICAL = "critical"; + protected static final String PROP_KEYID_TYPE = "keyIdentifierType"; + protected static final String PROP_REQATTR_NAME = "requestAttrName"; + + protected static final String KEYID_TYPE_SHA1 = "SHA1"; + protected static final String KEYID_TYPE_TYPEFIELD = "TypeField"; + protected static final String KEYID_TYPE_SPKISHA1 = "SpkiSHA1"; + protected static final String KEYID_TYPE_REQATTR = "RequestAttribute"; + + protected static final boolean DEF_CRITICAL = false; + protected static final String DEF_KEYID_TYPE = KEYID_TYPE_SHA1; + protected static final String DEF_REQATTR_NAME = "KeyIdentifier"; + + protected boolean mEnabled = false; + protected IConfigStore mConfig = null; + + protected boolean mCritical = DEF_CRITICAL; + protected String mKeyIdType = DEF_KEYID_TYPE;; + protected String mReqAttrName = DEF_REQATTR_NAME; + + protected Vector mInstanceParams = new Vector(); + + protected static Vector mDefaultParams = new Vector(); + static { + // form static default params. + mDefaultParams.addElement(PROP_CRITICAL + "=" + DEF_CRITICAL); + mDefaultParams.addElement(PROP_KEYID_TYPE + "=" + DEF_KEYID_TYPE); + + /* + mDefaultParams.addElement(PROP_REQATTR_NAME+"="+DEF_REQATTR_NAME); + */ + } + + public SubjectKeyIdentifierExt() { + NAME = "SubjectKeyIdentifierExt"; + DESC = "Adds Subject Key Idenifier Extension to certs"; + } + + /** + * Initializes this policy rule. + *

+ * + * The entries may be of the form: + * + * ca.Policy.rule..predicate= + * ca.Policy.rule..implName= + * ca.Policy.rule..enable=true + * + * @param config The config store reference + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + + mEnabled = mConfig.getBoolean( + IPolicyProcessor.PROP_ENABLE, false); + mCritical = mConfig.getBoolean(PROP_CRITICAL, DEF_CRITICAL); + + mKeyIdType = mConfig.getString(PROP_KEYID_TYPE, DEF_KEYID_TYPE); + + /* + mReqAttrName = mConfig.getString(PROP_REQATTR_NAME, DEF_REQATTR_NAME); + */ + + // parse key id type + if (mKeyIdType.equalsIgnoreCase(KEYID_TYPE_SHA1)) + mKeyIdType = KEYID_TYPE_SHA1; + else if (mKeyIdType.equalsIgnoreCase(KEYID_TYPE_TYPEFIELD)) + mKeyIdType = KEYID_TYPE_TYPEFIELD; + + /* + else if (mKeyIdType.equalsIgnoreCase(KEYID_TYPE_REQATTR) + mKeyIdType = KEYID_TYPE_REQATTR; + */ + else if (mKeyIdType.equalsIgnoreCase(KEYID_TYPE_SPKISHA1)) + mKeyIdType = KEYID_TYPE_SPKISHA1; + else { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("KRA_UNKNOWN_KEY_ID_TYPE", mKeyIdType)); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + PROP_KEYID_TYPE, + "value must be one of " + + KEYID_TYPE_SHA1 + ", " + + KEYID_TYPE_TYPEFIELD + ", " + + KEYID_TYPE_SPKISHA1)); + } + + // form instance params + mInstanceParams.addElement(PROP_CRITICAL + "=" + mCritical); + mInstanceParams.addElement(PROP_KEYID_TYPE + "=" + mKeyIdType); + + /* + mInstanceParams.addElement(PROP_REQATTR_NAME+"="+mReqAttrName); + */ + } + + /** + * Adds Subject Key identifier Extension to a certificate. + * If the extension is already there, accept it. + * + * @param req The request on which to apply policy. + * @return The policy result object. + */ + public PolicyResult apply(IRequest req) { + // get certInfo from request. + X509CertInfo[] ci = + req.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (ci == null || ci[0] == null) { + setError(req, CMS.getUserMessage("CMS_POLICY_NO_CERT_INFO"), NAME); + return PolicyResult.REJECTED; + } + + for (int i = 0; i < ci.length; i++) { + PolicyResult certRes = applyCert(req, ci[i]); + + if (certRes == PolicyResult.REJECTED) + return certRes; + } + return PolicyResult.ACCEPTED; + } + + public PolicyResult applyCert(IRequest req, X509CertInfo certInfo) { + + try { + // if subject key id extension already exists, leave it if approved. + SubjectKeyIdentifierExtension subjectKeyIdExt = null; + CertificateExtensions extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + + try { + if (extensions != null) { + subjectKeyIdExt = (SubjectKeyIdentifierExtension) + extensions.get(SubjectKeyIdentifierExtension.NAME); + } + } catch (IOException e) { + // extension isn't there. + } + if (subjectKeyIdExt != null) { + if (agentApproved(req)) { + CMS.debug( + "SubjectKeyIdentifierExt: agent approved request id " + req.getRequestId() + + " already has subject key id extension with value " + + subjectKeyIdExt); + return PolicyResult.ACCEPTED; + } else { + CMS.debug( + "SubjectKeyIdentifierExt: request id from user " + req.getRequestId() + + " had subject key identifier - deleted to be replaced"); + extensions.delete(SubjectKeyIdentifierExtension.NAME); + } + } + + // create subject key id extension. + KeyIdentifier keyId = null; + + try { + keyId = formKeyIdentifier(certInfo, req); + } catch (EBaseException e) { + setPolicyException(req, e); + return PolicyResult.REJECTED; + } + subjectKeyIdExt = + new SubjectKeyIdentifierExtension( + mCritical, keyId.getIdentifier()); + + // add subject key id extension. + if (extensions == null) { + certInfo.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + extensions = new CertificateExtensions(); + certInfo.set(X509CertInfo.EXTENSIONS, extensions); + } + extensions.set( + SubjectKeyIdentifierExtension.NAME, subjectKeyIdExt); + CMS.debug( + "SubjectKeyIdentifierExt: added subject key id ext to request " + req.getRequestId()); + return PolicyResult.ACCEPTED; + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_UNEXPECTED_POLICY_ERROR,NAME", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, e.getMessage()); + return PolicyResult.REJECTED; + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CA_CERT_INFO_ERROR", e.getMessage())); + setError(req, CMS.getUserMessage("CMS_POLICY_UNEXPECTED_POLICY_ERROR"), + NAME, "Certificate Info Error"); + return PolicyResult.REJECTED; + } + } + + /** + * Form the Key Identifier in the Subject Key Identifier extension. + *

+ * @param certInfo Certificate Info + * @param req request + * @return A Key Identifier. + */ + protected KeyIdentifier formKeyIdentifier( + X509CertInfo certInfo, IRequest req) throws EBaseException { + KeyIdentifier keyId = null; + + if (mKeyIdType == KEYID_TYPE_SHA1) { + keyId = formSHA1KeyId(certInfo); + } else if (mKeyIdType == KEYID_TYPE_TYPEFIELD) { + keyId = formTypeFieldKeyId(certInfo); + } /* + else if (mKeyIdType == KEYID_TYPE_REQATTR) { + keyId = formReqAttrKeyId(certInfo, req); + } + */ else if (mKeyIdType == KEYID_TYPE_SPKISHA1) { + keyId = formSpkiSHA1KeyId(certInfo); + } else { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + mKeyIdType, "Unknown Key Identifier type.")); + } + return keyId; + } + + /** + * Form key identifier from a type field value of 0100 followed by + * the least significate 60 bits of the sha-1 hash of the subject + * public key BIT STRING in accordance with RFC 2459. + *

+ * @param certInfo - certificate info + * @return A Key Identifier with value formulatd as described. + */ + + protected KeyIdentifier formTypeFieldKeyId(X509CertInfo certInfo) + throws EBaseException { + KeyIdentifier keyId = null; + X509Key key = null; + + try { + CertificateX509Key certKey = + (CertificateX509Key) certInfo.get(X509CertInfo.KEY); + + if (certKey == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_MISSING_KEY_1", NAME)); + throw new EPolicyException(CMS.getUserMessage("CMS_POLICY_MISSING_KEY", NAME)); + } + key = (X509Key) certKey.get(CertificateX509Key.KEY); + if (key == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("POLICY_MISSING_KEY_1", NAME)); + throw new EPolicyException(CMS.getUserMessage("CMS_POLICY_MISSING_KEY", NAME)); + } + } catch (IOException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_GET_KEY_FROM_CERT", e.toString())); + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_SUBJECT_KEY_ID_ERROR", NAME)); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_GET_KEY_FROM_CERT", e.toString())); + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_SUBJECT_KEY_ID_ERROR", NAME)); + } + try { + byte[] octetString = new byte[8]; + MessageDigest md = MessageDigest.getInstance("SHA-1"); + + md.update(key.getKey()); + byte[] hash = md.digest(); + + System.arraycopy(hash, hash.length - 8, octetString, 0, 8); + octetString[0] &= (0x08f & octetString[0]); + keyId = new KeyIdentifier(octetString); + } catch (NoSuchAlgorithmException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("POLICY_ERROR_SUBJECT_KEY_ID_1", NAME)); + throw new EPolicyException( + CMS.getUserMessage("CMS_POLICY_SUBJECT_KEY_ID_ERROR", NAME)); + } + return keyId; + } + + /** + * Return configured parameters for a policy rule instance. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getInstanceParams() { + return mInstanceParams; + } + + /** + * Return default parameters for a policy implementation. + * + * @return nvPairs A Vector of name/value pairs. + */ + public Vector getDefaultParams() { + return mDefaultParams; + } + + /** + * Gets extended plugin info for pretty Console displays. + */ + public String[] getExtendedPluginInfo(Locale locale) { + String[] params = { + PROP_CRITICAL + ";boolean;RFC 2459 recommendation: MUST NOT be marked critical.", + PROP_KEYID_TYPE + ";" + + "choice(" + KEYID_TYPE_SHA1 + "," + + KEYID_TYPE_TYPEFIELD + "," + + KEYID_TYPE_SPKISHA1 + ");" + + "Method to derive the Key Identifier.", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-policyrules-subjectkeyidentifier", + IExtendedPluginInfo.HELP_TEXT + + ";Adds the Subject Key Identifier extension. See RFC 2459 (4.2.1.2)" + }; + + return params; + } +} + -- cgit