From 621d9e5c413e561293d7484b93882d985b3fe15f Mon Sep 17 00:00:00 2001 From: Endi Sukma Dewata Date: Sat, 24 Mar 2012 02:27:47 -0500 Subject: Removed unnecessary pki folder. Previously the source code was located inside a pki folder. This folder was created during svn migration and is no longer needed. This folder has now been removed and the contents have been moved up one level. Ticket #131 --- .../cms/policy/extensions/AuthInfoAccessExt.java | 394 +++++++++++++++ .../extensions/AuthorityKeyIdentifierExt.java | 425 ++++++++++++++++ .../cms/policy/extensions/BasicConstraintsExt.java | 508 +++++++++++++++++++ .../extensions/CRLDistributionPointsExt.java | 484 +++++++++++++++++++ .../policy/extensions/CertificatePoliciesExt.java | 534 ++++++++++++++++++++ .../extensions/CertificateRenewalWindowExt.java | 254 ++++++++++ .../extensions/CertificateScopeOfUseExt.java | 326 +++++++++++++ .../cms/policy/extensions/ExtendedKeyUsageExt.java | 285 +++++++++++ .../cms/policy/extensions/GenericASN1Ext.java | 509 ++++++++++++++++++++ .../cms/policy/extensions/IssuerAltNameExt.java | 249 ++++++++++ .../cms/policy/extensions/KeyUsageExt.java | 362 ++++++++++++++ .../cms/policy/extensions/NSCCommentExt.java | 293 +++++++++++ .../cms/policy/extensions/NSCertTypeExt.java | 535 +++++++++++++++++++++ .../cms/policy/extensions/NameConstraintsExt.java | 475 ++++++++++++++++++ .../cms/policy/extensions/OCSPNoCheckExt.java | 190 ++++++++ .../policy/extensions/PolicyConstraintsExt.java | 287 +++++++++++ .../cms/policy/extensions/PolicyMappingsExt.java | 426 ++++++++++++++++ .../cms/policy/extensions/PresenceExt.java | 157 ++++++ .../extensions/PrivateKeyUsagePeriodExt.java | 252 ++++++++++ .../extensions/RemoveBasicConstraintsExt.java | 143 ++++++ .../cms/policy/extensions/SubjAltNameExt.java | 355 ++++++++++++++ .../cms/policy/extensions/SubjectAltNameExt.java | 331 +++++++++++++ .../extensions/SubjectDirectoryAttributesExt.java | 428 +++++++++++++++++ .../policy/extensions/SubjectKeyIdentifierExt.java | 377 +++++++++++++++ 24 files changed, 8579 insertions(+) create mode 100644 base/common/src/com/netscape/cms/policy/extensions/AuthInfoAccessExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/AuthorityKeyIdentifierExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/BasicConstraintsExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/CRLDistributionPointsExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/CertificatePoliciesExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/CertificateRenewalWindowExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/CertificateScopeOfUseExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/ExtendedKeyUsageExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/GenericASN1Ext.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/IssuerAltNameExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/KeyUsageExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/NSCCommentExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/NSCertTypeExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/NameConstraintsExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/OCSPNoCheckExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/PolicyConstraintsExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/PolicyMappingsExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/PresenceExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/PrivateKeyUsagePeriodExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/RemoveBasicConstraintsExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/SubjAltNameExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/SubjectAltNameExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/SubjectDirectoryAttributesExt.java create mode 100644 base/common/src/com/netscape/cms/policy/extensions/SubjectKeyIdentifierExt.java (limited to 'base/common/src/com/netscape/cms/policy/extensions') diff --git a/base/common/src/com/netscape/cms/policy/extensions/AuthInfoAccessExt.java b/base/common/src/com/netscape/cms/policy/extensions/AuthInfoAccessExt.java new file mode 100644 index 000000000..fea126567 --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/AuthInfoAccessExt.java @@ -0,0 +1,394 @@ +// --- 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.io.Serializable; +import java.security.cert.CertificateException; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Vector; + +import netscape.security.extensions.AuthInfoAccessExtension; +import netscape.security.util.ObjectIdentifier; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.GeneralName; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.policy.IGeneralNameUtil; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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 = 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/base/common/src/com/netscape/cms/policy/extensions/AuthorityKeyIdentifierExt.java b/base/common/src/com/netscape/cms/policy/extensions/AuthorityKeyIdentifierExt.java new file mode 100644 index 000000000..971379a46 --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/AuthorityKeyIdentifierExt.java @@ -0,0 +1,425 @@ +// --- 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.util.Locale; +import java.util.Vector; + +import netscape.security.x509.AuthorityKeyIdentifierExtension; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.KeyIdentifier; +import netscape.security.x509.SubjectKeyIdentifierExtension; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +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; + +/** + * 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/base/common/src/com/netscape/cms/policy/extensions/BasicConstraintsExt.java b/base/common/src/com/netscape/cms/policy/extensions/BasicConstraintsExt.java new file mode 100644 index 000000000..f830b7e3d --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/BasicConstraintsExt.java @@ -0,0 +1,508 @@ +// --- 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.x509.BasicConstraintsExtension; +import netscape.security.x509.CertificateChain; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authority.ICertAuthority; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.EPropertyNotDefined; +import com.netscape.certsrv.base.EPropertyNotFound; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.EPolicyException; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.policy.IPolicyProcessor; +import com.netscape.certsrv.ra.IRegistrationAuthority; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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) { + + // 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/base/common/src/com/netscape/cms/policy/extensions/CRLDistributionPointsExt.java b/base/common/src/com/netscape/cms/policy/extensions/CRLDistributionPointsExt.java new file mode 100644 index 000000000..1ede3d5d0 --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/CRLDistributionPointsExt.java @@ -0,0 +1,484 @@ +// --- 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.util.Hashtable; +import java.util.Locale; +import java.util.StringTokenizer; +import java.util.Vector; + +import netscape.security.util.BitArray; +import netscape.security.x509.CRLDistributionPoint; +import netscape.security.x509.CRLDistributionPointsExtension; +import netscape.security.x509.CRLDistributionPointsExtension.Reason; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.GeneralName; +import netscape.security.x509.GeneralNames; +import netscape.security.x509.GeneralNamesException; +import netscape.security.x509.RDN; +import netscape.security.x509.URIName; +import netscape.security.x509.X500Name; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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 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/base/common/src/com/netscape/cms/policy/extensions/CertificatePoliciesExt.java b/base/common/src/com/netscape/cms/policy/extensions/CertificatePoliciesExt.java new file mode 100644 index 000000000..597357318 --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/CertificatePoliciesExt.java @@ -0,0 +1,534 @@ +// --- 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.util.Locale; +import java.util.StringTokenizer; +import java.util.Vector; + +import netscape.security.util.ObjectIdentifier; +import netscape.security.x509.CPSuri; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificatePoliciesExtension; +import netscape.security.x509.CertificatePolicyId; +import netscape.security.x509.CertificatePolicyInfo; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.DisplayText; +import netscape.security.x509.NoticeReference; +import netscape.security.x509.PolicyQualifierInfo; +import netscape.security.x509.PolicyQualifiers; +import netscape.security.x509.UserNotice; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +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; + +/** + * 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. + + if (mPolicyId != null) + 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(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/base/common/src/com/netscape/cms/policy/extensions/CertificateRenewalWindowExt.java b/base/common/src/com/netscape/cms/policy/extensions/CertificateRenewalWindowExt.java new file mode 100644 index 000000000..28366ade8 --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/CertificateRenewalWindowExt.java @@ -0,0 +1,254 @@ +// --- 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.util.Date; +import java.util.Locale; +import java.util.Vector; + +import netscape.security.extensions.CertificateRenewalWindowExtension; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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/base/common/src/com/netscape/cms/policy/extensions/CertificateScopeOfUseExt.java b/base/common/src/com/netscape/cms/policy/extensions/CertificateScopeOfUseExt.java new file mode 100644 index 000000000..b385923af --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/CertificateScopeOfUseExt.java @@ -0,0 +1,326 @@ +// --- 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.util.Locale; +import java.util.Vector; + +import netscape.security.extensions.CertificateScopeEntry; +import netscape.security.extensions.CertificateScopeOfUseExtension; +import netscape.security.util.BigInt; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.GeneralName; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.policy.IGeneralNameUtil; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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/base/common/src/com/netscape/cms/policy/extensions/ExtendedKeyUsageExt.java b/base/common/src/com/netscape/cms/policy/extensions/ExtendedKeyUsageExt.java new file mode 100644 index 000000000..65ef6b937 --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/ExtendedKeyUsageExt.java @@ -0,0 +1,285 @@ +// --- 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.util.Locale; +import java.util.Vector; + +import netscape.security.extensions.ExtendedKeyUsageExtension; +import netscape.security.util.ObjectIdentifier; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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/base/common/src/com/netscape/cms/policy/extensions/GenericASN1Ext.java b/base/common/src/com/netscape/cms/policy/extensions/GenericASN1Ext.java new file mode 100644 index 000000000..0202ee784 --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/GenericASN1Ext.java @@ -0,0 +1,509 @@ +// --- 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.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.cert.CertificateException; +import java.text.ParseException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Locale; +import java.util.Vector; + +import netscape.security.extensions.GenericASN1Extension; +import netscape.security.util.ObjectIdentifier; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.OIDMap; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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(priExt.getName(), 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/base/common/src/com/netscape/cms/policy/extensions/IssuerAltNameExt.java b/base/common/src/com/netscape/cms/policy/extensions/IssuerAltNameExt.java new file mode 100644 index 000000000..bb9abd9cf --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/IssuerAltNameExt.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.extensions; + +import java.io.IOException; +import java.security.cert.CertificateException; +import java.util.Locale; +import java.util.Vector; + +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.IssuerAlternativeNameExtension; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.policy.IGeneralNamesConfig; +import com.netscape.certsrv.policy.IPolicyProcessor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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); + + 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 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/base/common/src/com/netscape/cms/policy/extensions/KeyUsageExt.java b/base/common/src/com/netscape/cms/policy/extensions/KeyUsageExt.java new file mode 100644 index 000000000..6594cc4a2 --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/KeyUsageExt.java @@ -0,0 +1,362 @@ +// --- 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.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.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; + +/** + * 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) { + + 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/base/common/src/com/netscape/cms/policy/extensions/NSCCommentExt.java b/base/common/src/com/netscape/cms/policy/extensions/NSCCommentExt.java new file mode 100644 index 000000000..ecc084d29 --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/NSCCommentExt.java @@ -0,0 +1,293 @@ +// --- 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.BufferedReader; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.security.cert.CertificateException; +import java.util.Locale; +import java.util.Vector; + +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.NSCCommentExtension; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.EPolicyException; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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; + + 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/base/common/src/com/netscape/cms/policy/extensions/NSCertTypeExt.java b/base/common/src/com/netscape/cms/policy/extensions/NSCertTypeExt.java new file mode 100644 index 000000000..2fb09b2b7 --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/NSCertTypeExt.java @@ -0,0 +1,535 @@ +// --- 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.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()"); + + 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 { + 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/base/common/src/com/netscape/cms/policy/extensions/NameConstraintsExt.java b/base/common/src/com/netscape/cms/policy/extensions/NameConstraintsExt.java new file mode 100644 index 000000000..f010bf3f1 --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/NameConstraintsExt.java @@ -0,0 +1,475 @@ +// --- 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.util.Locale; +import java.util.Vector; + +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.GeneralSubtree; +import netscape.security.x509.GeneralSubtrees; +import netscape.security.x509.NameConstraintsExtension; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.policy.IGeneralNameAsConstraintsConfig; +import com.netscape.certsrv.policy.IPolicyProcessor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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/base/common/src/com/netscape/cms/policy/extensions/OCSPNoCheckExt.java b/base/common/src/com/netscape/cms/policy/extensions/OCSPNoCheckExt.java new file mode 100644 index 000000000..33f2f85e0 --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/OCSPNoCheckExt.java @@ -0,0 +1,190 @@ +// --- 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.util.Locale; +import java.util.Vector; + +import netscape.security.extensions.OCSPNoCheckExtension; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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/base/common/src/com/netscape/cms/policy/extensions/PolicyConstraintsExt.java b/base/common/src/com/netscape/cms/policy/extensions/PolicyConstraintsExt.java new file mode 100644 index 000000000..861107b8e --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/PolicyConstraintsExt.java @@ -0,0 +1,287 @@ +// --- 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.util.Locale; +import java.util.Vector; + +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.PolicyConstraintsExtension; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +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; + +/** + * 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/base/common/src/com/netscape/cms/policy/extensions/PolicyMappingsExt.java b/base/common/src/com/netscape/cms/policy/extensions/PolicyMappingsExt.java new file mode 100644 index 000000000..7623f455f --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/PolicyMappingsExt.java @@ -0,0 +1,426 @@ +// --- 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.util.Locale; +import java.util.Vector; + +import netscape.security.util.ObjectIdentifier; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificatePolicyId; +import netscape.security.x509.CertificatePolicyMap; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.PolicyMappingsExtension; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +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; + +/** + * 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/base/common/src/com/netscape/cms/policy/extensions/PresenceExt.java b/base/common/src/com/netscape/cms/policy/extensions/PresenceExt.java new file mode 100644 index 000000000..e13a7a84c --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/PresenceExt.java @@ -0,0 +1,157 @@ +// --- 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.Locale; +import java.util.Vector; + +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.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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/base/common/src/com/netscape/cms/policy/extensions/PrivateKeyUsagePeriodExt.java b/base/common/src/com/netscape/cms/policy/extensions/PrivateKeyUsagePeriodExt.java new file mode 100644 index 000000000..3b80246a9 --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/PrivateKeyUsagePeriodExt.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.io.IOException; +import java.security.cert.CertificateException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.Vector; + +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.PrivateKeyUsageExtension; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.EPolicyException; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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 for errors + formatter.format(formatter.parse(mNotBefore.trim())); + 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) { + + // 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/base/common/src/com/netscape/cms/policy/extensions/RemoveBasicConstraintsExt.java b/base/common/src/com/netscape/cms/policy/extensions/RemoveBasicConstraintsExt.java new file mode 100644 index 000000000..2a5af4240 --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/RemoveBasicConstraintsExt.java @@ -0,0 +1,143 @@ +// --- 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.util.Locale; +import java.util.Vector; + +import netscape.security.x509.BasicConstraintsExtension; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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) { + + // 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/base/common/src/com/netscape/cms/policy/extensions/SubjAltNameExt.java b/base/common/src/com/netscape/cms/policy/extensions/SubjAltNameExt.java new file mode 100644 index 000000000..63bd8804c --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/SubjAltNameExt.java @@ -0,0 +1,355 @@ +// --- 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.util.Locale; +import java.util.Vector; + +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.GeneralNames; +import netscape.security.x509.RFC822Name; +import netscape.security.x509.SubjectAlternativeNameExtension; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthToken; +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.logging.ILogger; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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 = 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/base/common/src/com/netscape/cms/policy/extensions/SubjectAltNameExt.java b/base/common/src/com/netscape/cms/policy/extensions/SubjectAltNameExt.java new file mode 100644 index 000000000..62f0b21da --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/SubjectAltNameExt.java @@ -0,0 +1,331 @@ +// --- 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.util.Enumeration; +import java.util.Locale; +import java.util.Vector; + +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.GeneralName; +import netscape.security.x509.GeneralNames; +import netscape.security.x509.SubjectAlternativeNameExtension; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.policy.IGeneralNameUtil; +import com.netscape.certsrv.policy.IPolicyProcessor; +import com.netscape.certsrv.policy.ISubjAltNameConfig; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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(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/base/common/src/com/netscape/cms/policy/extensions/SubjectDirectoryAttributesExt.java b/base/common/src/com/netscape/cms/policy/extensions/SubjectDirectoryAttributesExt.java new file mode 100644 index 000000000..6b4e7ead9 --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/SubjectDirectoryAttributesExt.java @@ -0,0 +1,428 @@ +// --- 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.util.Enumeration; +import java.util.Locale; +import java.util.Vector; + +import netscape.security.util.DerValue; +import netscape.security.util.ObjectIdentifier; +import netscape.security.x509.AVAValueConverter; +import netscape.security.x509.Attribute; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.SubjectDirAttributesExtension; +import netscape.security.x509.X500NameAttrMap; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.policy.IEnrollmentPolicy; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +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) { + 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; + + 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; + } + } + + 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(n.nextElement()); + + while (n.hasMoreElements()) { + sb.append(","); + sb.append(n.nextElement()); + } + return sb.toString(); + } + + private static void checkValue(ObjectIdentifier oid, String val) + throws IOException { + AVAValueConverter c = X500NameAttrMap.getDefault().getValueConverter(oid); + + @SuppressWarnings("unused") + DerValue derval = c.getValue(val); // check for errors + return; + } + +} diff --git a/base/common/src/com/netscape/cms/policy/extensions/SubjectKeyIdentifierExt.java b/base/common/src/com/netscape/cms/policy/extensions/SubjectKeyIdentifierExt.java new file mode 100644 index 000000000..32d254c40 --- /dev/null +++ b/base/common/src/com/netscape/cms/policy/extensions/SubjectKeyIdentifierExt.java @@ -0,0 +1,377 @@ +// --- 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.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.util.Locale; +import java.util.Vector; + +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.CertificateX509Key; +import netscape.security.x509.KeyIdentifier; +import netscape.security.x509.SubjectKeyIdentifierExtension; +import netscape.security.x509.X509CertInfo; +import netscape.security.x509.X509Key; + +import com.netscape.certsrv.apps.CMS; +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.logging.ILogger; +import com.netscape.certsrv.policy.EPolicyException; +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; + +/** + * 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