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 --- .../constraint/BasicConstraintsExtConstraint.java | 224 +++++++ .../cms/profile/constraint/CAEnrollConstraint.java | 48 ++ .../profile/constraint/CAValidityConstraint.java | 139 +++++ .../cms/profile/constraint/EnrollConstraint.java | 214 +++++++ .../constraint/ExtendedKeyUsageExtConstraint.java | 156 +++++ .../profile/constraint/ExtensionConstraint.java | 146 +++++ .../cms/profile/constraint/KeyConstraint.java | 644 +++++++++++++++++++++ .../profile/constraint/KeyUsageExtConstraint.java | 291 ++++++++++ .../constraint/NSCertTypeExtConstraint.java | 243 ++++++++ .../cms/profile/constraint/NoConstraint.java | 101 ++++ .../constraint/RenewGracePeriodConstraint.java | 165 ++++++ .../profile/constraint/SigningAlgConstraint.java | 160 +++++ .../profile/constraint/SubjectNameConstraint.java | 136 +++++ .../profile/constraint/UniqueKeyConstraint.java | 295 ++++++++++ .../constraint/UniqueSubjectNameConstraint.java | 251 ++++++++ .../cms/profile/constraint/ValidityConstraint.java | 218 +++++++ 16 files changed, 3431 insertions(+) create mode 100644 base/common/src/com/netscape/cms/profile/constraint/BasicConstraintsExtConstraint.java create mode 100644 base/common/src/com/netscape/cms/profile/constraint/CAEnrollConstraint.java create mode 100644 base/common/src/com/netscape/cms/profile/constraint/CAValidityConstraint.java create mode 100644 base/common/src/com/netscape/cms/profile/constraint/EnrollConstraint.java create mode 100644 base/common/src/com/netscape/cms/profile/constraint/ExtendedKeyUsageExtConstraint.java create mode 100644 base/common/src/com/netscape/cms/profile/constraint/ExtensionConstraint.java create mode 100644 base/common/src/com/netscape/cms/profile/constraint/KeyConstraint.java create mode 100644 base/common/src/com/netscape/cms/profile/constraint/KeyUsageExtConstraint.java create mode 100644 base/common/src/com/netscape/cms/profile/constraint/NSCertTypeExtConstraint.java create mode 100644 base/common/src/com/netscape/cms/profile/constraint/NoConstraint.java create mode 100644 base/common/src/com/netscape/cms/profile/constraint/RenewGracePeriodConstraint.java create mode 100644 base/common/src/com/netscape/cms/profile/constraint/SigningAlgConstraint.java create mode 100644 base/common/src/com/netscape/cms/profile/constraint/SubjectNameConstraint.java create mode 100644 base/common/src/com/netscape/cms/profile/constraint/UniqueKeyConstraint.java create mode 100644 base/common/src/com/netscape/cms/profile/constraint/UniqueSubjectNameConstraint.java create mode 100644 base/common/src/com/netscape/cms/profile/constraint/ValidityConstraint.java (limited to 'base/common/src/com/netscape/cms/profile/constraint') diff --git a/base/common/src/com/netscape/cms/profile/constraint/BasicConstraintsExtConstraint.java b/base/common/src/com/netscape/cms/profile/constraint/BasicConstraintsExtConstraint.java new file mode 100644 index 000000000..f924c587f --- /dev/null +++ b/base/common/src/com/netscape/cms/profile/constraint/BasicConstraintsExtConstraint.java @@ -0,0 +1,224 @@ +// --- 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.profile.constraint; + +import java.io.IOException; +import java.util.Locale; + +import netscape.security.x509.BasicConstraintsExtension; +import netscape.security.x509.PKIXExtensions; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.profile.IPolicyDefault; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.property.Descriptor; +import com.netscape.certsrv.property.EPropertyException; +import com.netscape.certsrv.property.IDescriptor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.profile.def.BasicConstraintsExtDefault; +import com.netscape.cms.profile.def.NoDefault; +import com.netscape.cms.profile.def.UserExtensionDefault; + +/** + * This class implements the basic constraints extension constraint. + * It checks if the basic constraint in the certificate + * template satisfies the criteria. + * + * @version $Revision$, $Date$ + */ +public class BasicConstraintsExtConstraint extends EnrollConstraint { + + public static final String CONFIG_CRITICAL = + "basicConstraintsCritical"; + public static final String CONFIG_IS_CA = + "basicConstraintsIsCA"; + public static final String CONFIG_MIN_PATH_LEN = + "basicConstraintsMinPathLen"; + public static final String CONFIG_MAX_PATH_LEN = + "basicConstraintsMaxPathLen"; + + public BasicConstraintsExtConstraint() { + super(); + addConfigName(CONFIG_CRITICAL); + addConfigName(CONFIG_IS_CA); + addConfigName(CONFIG_MIN_PATH_LEN); + addConfigName(CONFIG_MAX_PATH_LEN); + } + + /** + * Initializes this constraint plugin. + */ + public void init(IProfile profile, IConfigStore config) + throws EProfileException { + super.init(profile, config); + } + + public IDescriptor getConfigDescriptor(Locale locale, String name) { + if (name.equals(CONFIG_CRITICAL)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_CRITICAL")); + } else if (name.equals(CONFIG_IS_CA)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_IS_CA")); + } else if (name.equals(CONFIG_MIN_PATH_LEN)) { + return new Descriptor(IDescriptor.INTEGER, null, + "-1", + CMS.getUserMessage(locale, "CMS_PROFILE_MIN_PATH_LEN")); + } else if (name.equals(CONFIG_MAX_PATH_LEN)) { + return new Descriptor(IDescriptor.INTEGER, null, + "100", + CMS.getUserMessage(locale, "CMS_PROFILE_MAX_PATH_LEN")); + } + return null; + } + + /** + * Validates the request. The request is not modified + * during the validation. + */ + public void validate(IRequest request, X509CertInfo info) + throws ERejectException { + + try { + BasicConstraintsExtension ext = (BasicConstraintsExtension) + getExtension(PKIXExtensions.BasicConstraints_Id.toString(), + info); + + if (ext == null) { + throw new ERejectException( + CMS.getUserMessage( + getLocale(request), + "CMS_PROFILE_EXTENSION_NOT_FOUND", + PKIXExtensions.BasicConstraints_Id.toString())); + } + + // check criticality + String value = getConfig(CONFIG_CRITICAL); + + if (!isOptional(value)) { + boolean critical = getBoolean(value); + + if (critical != ext.isCritical()) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_CRITICAL_NOT_MATCHED")); + } + } + value = getConfig(CONFIG_IS_CA); + if (!isOptional(value)) { + boolean isCA = getBoolean(value); + Boolean extIsCA = (Boolean) ext.get(BasicConstraintsExtension.IS_CA); + + if (isCA != extIsCA.booleanValue()) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_CONSTRAINT_BASIC_CONSTRAINTS_EXT_IS_CA")); + } + } + value = getConfig(CONFIG_MIN_PATH_LEN); + if (!isOptional(value)) { + int pathLen = getInt(value); + Integer extPathLen = (Integer) ext.get(BasicConstraintsExtension.PATH_LEN); + + if (pathLen > extPathLen.intValue()) { + CMS.debug("BasicCOnstraintsExtConstraint: pathLen=" + pathLen + " > extPathLen=" + extPathLen); + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_CONSTRAINT_BASIC_CONSTRAINTS_EXT_MIN_PATH")); + } + } + value = getConfig(CONFIG_MAX_PATH_LEN); + if (!isOptional(value)) { + int pathLen = getInt(value); + Integer extPathLen = (Integer) ext.get(BasicConstraintsExtension.PATH_LEN); + + if (pathLen < extPathLen.intValue()) { + CMS.debug("BasicCOnstraintsExtConstraint: pathLen=" + pathLen + " < extPathLen=" + extPathLen); + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_CONSTRAINT_BASIC_CONSTRAINTS_EXT_MAX_PATH")); + } + } + } catch (IOException e) { + CMS.debug("BasicConstraintsExt: validate " + e.toString()); + throw new ERejectException( + CMS.getUserMessage( + getLocale(request), + "CMS_PROFILE_EXTENSION_NOT_FOUND", + PKIXExtensions.BasicConstraints_Id.toString())); + } + } + + public String getText(Locale locale) { + String params[] = { + getConfig(CONFIG_CRITICAL), + getConfig(CONFIG_IS_CA), + getConfig(CONFIG_MIN_PATH_LEN), + getConfig(CONFIG_MAX_PATH_LEN) + }; + + return CMS.getUserMessage(locale, + "CMS_PROFILE_CONSTRAINT_BASIC_CONSTRAINTS_EXT_TEXT", + params); + } + + public boolean isApplicable(IPolicyDefault def) { + if (def instanceof NoDefault) + return true; + if (def instanceof BasicConstraintsExtDefault) + return true; + if (def instanceof UserExtensionDefault) + return true; + return false; + } + + public void setConfig(String name, String value) + throws EPropertyException { + + if (mConfig.getSubStore("params") == null) { + CMS.debug("BasicConstraintsExt: mConfig.getSubStore is null"); + // + } else { + + CMS.debug("BasicConstraintsExt: setConfig name " + name + " value " + value); + + if (name.equals(CONFIG_MAX_PATH_LEN)) { + + String minPathLen = getConfig(CONFIG_MIN_PATH_LEN); + + int minLen = getInt(minPathLen); + + int maxLen = getInt(value); + + if (minLen >= maxLen) { + CMS.debug("BasicConstraintExt: minPathLen >= maxPathLen!"); + + throw new EPropertyException("bad value"); + } + + } + mConfig.getSubStore("params").putString(name, value); + } + } +} diff --git a/base/common/src/com/netscape/cms/profile/constraint/CAEnrollConstraint.java b/base/common/src/com/netscape/cms/profile/constraint/CAEnrollConstraint.java new file mode 100644 index 000000000..c0a9758da --- /dev/null +++ b/base/common/src/com/netscape/cms/profile/constraint/CAEnrollConstraint.java @@ -0,0 +1,48 @@ +// --- 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.profile.constraint; + +import netscape.security.x509.X509CertImpl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.ca.ICertificateAuthority; + +/** + * This class represents an abstract class for CA enrollment + * constraint. + */ +public abstract class CAEnrollConstraint extends EnrollConstraint { + + /** + * Constructs a CA enrollment constraint. + */ + public CAEnrollConstraint() { + super(); + } + + /** + * Retrieves the CA certificate. + */ + public X509CertImpl getCACert() { + ICertificateAuthority ca = (ICertificateAuthority) + CMS.getSubsystem(CMS.SUBSYSTEM_CA); + X509CertImpl caCert = ca.getCACert(); + + return caCert; + } +} diff --git a/base/common/src/com/netscape/cms/profile/constraint/CAValidityConstraint.java b/base/common/src/com/netscape/cms/profile/constraint/CAValidityConstraint.java new file mode 100644 index 000000000..e118fa215 --- /dev/null +++ b/base/common/src/com/netscape/cms/profile/constraint/CAValidityConstraint.java @@ -0,0 +1,139 @@ +// --- 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.profile.constraint; + +import java.io.IOException; +import java.util.Date; +import java.util.Locale; + +import netscape.security.x509.CertificateValidity; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.profile.IPolicyDefault; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.profile.def.CAValidityDefault; +import com.netscape.cms.profile.def.NoDefault; +import com.netscape.cms.profile.def.UserValidityDefault; +import com.netscape.cms.profile.def.ValidityDefault; + +/** + * This class implements the validity constraint. + * It checks if the validity in the certificate + * template is within the CA's validity. + * + * @version $Revision$, $Date$ + */ +public class CAValidityConstraint extends CAEnrollConstraint { + + private Date mDefNotBefore = null; + private Date mDefNotAfter = null; + + public CAValidityConstraint() { + super(); + } + + public void init(IProfile profile, IConfigStore config) + throws EProfileException { + super.init(profile, config); + X509CertImpl caCert = getCACert(); + + mDefNotBefore = caCert.getNotBefore(); + mDefNotAfter = caCert.getNotAfter(); + } + + /** + * Validates the request. The request is not modified + * during the validation. + */ + public void validate(IRequest request, X509CertInfo info) + throws ERejectException { + CMS.debug("CAValidityConstraint: validate start"); + CertificateValidity v = null; + + try { + v = (CertificateValidity) info.get(X509CertInfo.VALIDITY); + } catch (Exception e) { + throw new ERejectException(CMS.getUserMessage( + getLocale(request), "CMS_PROFILE_VALIDITY_NOT_FOUND")); + } + Date notBefore = null; + + try { + notBefore = (Date) v.get(CertificateValidity.NOT_BEFORE); + } catch (IOException e) { + CMS.debug("CAValidity: not before " + e.toString()); + throw new ERejectException(CMS.getUserMessage( + getLocale(request), "CMS_PROFILE_INVALID_NOT_BEFORE")); + } + Date notAfter = null; + + try { + notAfter = (Date) v.get(CertificateValidity.NOT_AFTER); + } catch (IOException e) { + CMS.debug("CAValidity: not after " + e.toString()); + throw new ERejectException(CMS.getUserMessage( + getLocale(request), "CMS_PROFILE_INVALID_NOT_AFTER")); + } + + if (mDefNotBefore != null) { + CMS.debug("ValidtyConstraint: notBefore=" + notBefore + + " defNotBefore=" + mDefNotBefore); + if (notBefore.before(mDefNotBefore)) { + throw new ERejectException(CMS.getUserMessage( + getLocale(request), "CMS_PROFILE_INVALID_NOT_BEFORE")); + } + } + CMS.debug("ValidtyConstraint: notAfter=" + notAfter + + " defNotAfter=" + mDefNotAfter); + if (notAfter.after(mDefNotAfter)) { + throw new ERejectException(CMS.getUserMessage( + getLocale(request), "CMS_PROFILE_INVALID_NOT_AFTER")); + } + + CMS.debug("CAValidtyConstraint: validate end"); + } + + public String getText(Locale locale) { + String params[] = { + mDefNotBefore.toString(), + mDefNotAfter.toString() + }; + + return CMS.getUserMessage(locale, + "CMS_PROFILE_CONSTRAINT_CA_VALIDITY_CONSTRAINT_TEXT", + params); + } + + public boolean isApplicable(IPolicyDefault def) { + if (def instanceof NoDefault) + return true; + if (def instanceof UserValidityDefault) + return true; + if (def instanceof ValidityDefault) + return true; + if (def instanceof CAValidityDefault) + return true; + return false; + } +} diff --git a/base/common/src/com/netscape/cms/profile/constraint/EnrollConstraint.java b/base/common/src/com/netscape/cms/profile/constraint/EnrollConstraint.java new file mode 100644 index 000000000..40c2153a8 --- /dev/null +++ b/base/common/src/com/netscape/cms/profile/constraint/EnrollConstraint.java @@ -0,0 +1,214 @@ +// --- 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.profile.constraint; + +import java.util.Enumeration; +import java.util.Locale; +import java.util.Vector; + +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.Extension; +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.profile.EProfileException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.profile.IPolicyConstraint; +import com.netscape.certsrv.profile.IPolicyDefault; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.property.EPropertyException; +import com.netscape.certsrv.property.IDescriptor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.profile.common.EnrollProfile; + +/** + * This class implements the generic enrollment constraint. + * + * @version $Revision$, $Date$ + */ +public abstract class EnrollConstraint implements IPolicyConstraint { + public static final String CONFIG_NAME = "name"; + + protected IConfigStore mConfig = null; + protected Vector mConfigNames = new Vector(); + + public EnrollConstraint() { + } + + public Enumeration getConfigNames() { + return mConfigNames.elements(); + } + + public void addConfigName(String name) { + mConfigNames.addElement(name); + } + + public IDescriptor getConfigDescriptor(Locale locale, String name) { + return null; + } + + public IDescriptor getValueDescriptor(Locale locale, String name) { + return null; + } + + public Locale getLocale(IRequest request) { + Locale locale = null; + String language = request.getExtDataInString( + EnrollProfile.REQUEST_LOCALE); + if (language != null) { + locale = new Locale(language); + } + return locale; + } + + public void setConfig(String name, String value) + throws EPropertyException { + if (mConfig.getSubStore("params") == null) { + // + } else { + mConfig.getSubStore("params").putString(name, value); + } + } + + public String getConfig(String name) { + try { + if (mConfig == null) + return null; + if (mConfig.getSubStore("params") != null) { + String val = mConfig.getSubStore("params").getString(name); + + return val; + } + } catch (EBaseException e) { + CMS.debug(e.toString()); + } + return ""; + } + + public void init(IProfile profile, IConfigStore config) + throws EProfileException { + mConfig = config; + } + + public IConfigStore getConfigStore() { + return mConfig; + } + + /** + * Validates the request. The request is not modified + * during the validation. + * + * @param request enrollment request + * @param info certificate template + * @exception ERejectException request is rejected due + * to violation of constraint + */ + public abstract void validate(IRequest request, X509CertInfo info) + throws ERejectException; + + /** + * Validates the request. The request is not modified + * during the validation. + * + * The current implementation of this method calls + * into the subclass's validate(request, info) + * method for validation checking. + * + * @param request request + * @exception ERejectException request is rejected due + * to violation of constraint + */ + public void validate(IRequest request) + throws ERejectException { + String name = getClass().getName(); + + name = name.substring(name.lastIndexOf('.') + 1); + CMS.debug(name + ": validate start"); + X509CertInfo info = + request.getExtDataInCertInfo(EnrollProfile.REQUEST_CERTINFO); + + validate(request, info); + + request.setExtData(EnrollProfile.REQUEST_CERTINFO, info); + CMS.debug(name + ": validate end"); + } + + public String getText(Locale locale) { + return "Enroll Constraint"; + } + + public String getName(Locale locale) { + try { + return mConfig.getString(CONFIG_NAME); + } catch (EBaseException e) { + return null; + } + } + + protected Extension getExtension(String name, X509CertInfo info) { + CertificateExtensions exts = null; + + try { + exts = (CertificateExtensions) + info.get(X509CertInfo.EXTENSIONS); + } catch (Exception e) { + CMS.debug("EnrollConstraint: getExtension " + e.toString()); + } + if (exts == null) + return null; + Enumeration e = exts.getAttributes(); + + while (e.hasMoreElements()) { + Extension ext = e.nextElement(); + + if (ext.getExtensionId().toString().equals(name)) { + return ext; + } + } + return null; + } + + protected boolean isOptional(String value) { + if (value.equals("") || value.equals("-")) + return true; + else + return false; + } + + protected boolean getBoolean(String value) { + return Boolean.valueOf(value).booleanValue(); + } + + protected int getInt(String value) { + return Integer.valueOf(value).intValue(); + } + + protected boolean getConfigBoolean(String value) { + return getBoolean(getConfig(value)); + } + + protected int getConfigInt(String value) { + return getInt(getConfig(value)); + } + + public boolean isApplicable(IPolicyDefault def) { + return true; + } +} diff --git a/base/common/src/com/netscape/cms/profile/constraint/ExtendedKeyUsageExtConstraint.java b/base/common/src/com/netscape/cms/profile/constraint/ExtendedKeyUsageExtConstraint.java new file mode 100644 index 000000000..3c737e8a5 --- /dev/null +++ b/base/common/src/com/netscape/cms/profile/constraint/ExtendedKeyUsageExtConstraint.java @@ -0,0 +1,156 @@ +// --- 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.profile.constraint; + +import java.util.Enumeration; +import java.util.Locale; +import java.util.StringTokenizer; +import java.util.Vector; + +import netscape.security.extensions.ExtendedKeyUsageExtension; +import netscape.security.util.ObjectIdentifier; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.profile.IPolicyDefault; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.property.Descriptor; +import com.netscape.certsrv.property.IDescriptor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.profile.def.ExtendedKeyUsageExtDefault; +import com.netscape.cms.profile.def.NoDefault; +import com.netscape.cms.profile.def.UserExtensionDefault; + +/** + * This class implements the extended key usage extension constraint. + * It checks if the extended key usage extension in the certificate + * template satisfies the criteria. + * + * @version $Revision$, $Date$ + */ +public class ExtendedKeyUsageExtConstraint extends EnrollConstraint { + + public static final String CONFIG_CRITICAL = "exKeyUsageCritical"; + public static final String CONFIG_OIDS = + "exKeyUsageOIDs"; + + public ExtendedKeyUsageExtConstraint() { + super(); + addConfigName(CONFIG_CRITICAL); + addConfigName(CONFIG_OIDS); + } + + public void init(IProfile profile, IConfigStore config) + throws EProfileException { + super.init(profile, config); + } + + public IDescriptor getConfigDescriptor(Locale locale, String name) { + if (name.equals(CONFIG_CRITICAL)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_CRITICAL")); + } else if (name.equals(CONFIG_OIDS)) { + return new Descriptor(IDescriptor.STRING, null, + null, + CMS.getUserMessage(locale, "CMS_PROFILE_OIDS")); + } + return null; + } + + /** + * Validates the request. The request is not modified + * during the validation. + */ + public void validate(IRequest request, X509CertInfo info) + throws ERejectException { + ExtendedKeyUsageExtension ext = (ExtendedKeyUsageExtension) + getExtension(ExtendedKeyUsageExtension.OID, info); + + if (ext == null) { + throw new ERejectException( + CMS.getUserMessage( + getLocale(request), + "CMS_PROFILE_EXTENSION_NOT_FOUND", + ExtendedKeyUsageExtension.OID)); + } + + // check criticality + String value = getConfig(CONFIG_CRITICAL); + + if (!isOptional(value)) { + boolean critical = getBoolean(value); + + if (critical != ext.isCritical()) { + throw new ERejectException( + CMS.getUserMessage( + getLocale(request), + "CMS_PROFILE_CRITICAL_NOT_MATCHED")); + } + } + + // Build local cache of configured OIDs + Vector mCache = new Vector(); + StringTokenizer st = new StringTokenizer(getConfig(CONFIG_OIDS), ","); + + while (st.hasMoreTokens()) { + String oid = st.nextToken(); + + mCache.addElement(oid); + } + + // check OIDs + Enumeration e = ext.getOIDs(); + + while (e.hasMoreElements()) { + ObjectIdentifier oid = e.nextElement(); + + if (!mCache.contains(oid.toString())) { + throw new ERejectException( + CMS.getUserMessage( + getLocale(request), + "CMS_PROFILE_OID_NOT_MATCHED", + oid.toString())); + } + } + } + + public String getText(Locale locale) { + String params[] = { + getConfig(CONFIG_CRITICAL), + getConfig(CONFIG_OIDS) + }; + + return CMS.getUserMessage(locale, + "CMS_PROFILE_CONSTRAINT_EXTENDED_KEY_EXT_TEXT", + params); + } + + public boolean isApplicable(IPolicyDefault def) { + if (def instanceof NoDefault) + return true; + if (def instanceof ExtendedKeyUsageExtDefault) + return true; + if (def instanceof UserExtensionDefault) + return true; + return false; + } +} diff --git a/base/common/src/com/netscape/cms/profile/constraint/ExtensionConstraint.java b/base/common/src/com/netscape/cms/profile/constraint/ExtensionConstraint.java new file mode 100644 index 000000000..1562fddb8 --- /dev/null +++ b/base/common/src/com/netscape/cms/profile/constraint/ExtensionConstraint.java @@ -0,0 +1,146 @@ +// --- 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.profile.constraint; + +import java.util.Locale; + +import netscape.security.x509.Extension; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.profile.IPolicyDefault; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.property.Descriptor; +import com.netscape.certsrv.property.EPropertyException; +import com.netscape.certsrv.property.IDescriptor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.profile.def.EnrollExtDefault; +import com.netscape.cms.profile.def.NoDefault; +import com.netscape.cms.profile.def.UserExtensionDefault; + +/** + * This class implements the general extension constraint. + * It checks if the extension in the certificate + * template satisfies the criteria. + * + * @version $Revision$, $Date$ + */ +public class ExtensionConstraint extends EnrollConstraint { + + public static final String CONFIG_CRITICAL = "extCritical"; + public static final String CONFIG_OID = "extOID"; + + public ExtensionConstraint() { + super(); + addConfigName(CONFIG_CRITICAL); + addConfigName(CONFIG_OID); + } + + public void init(IProfile profile, IConfigStore config) + throws EProfileException { + super.init(profile, config); + } + + public void setConfig(String name, String value) + throws EPropertyException { + + if (mConfig.getSubStore("params") == null) { + CMS.debug("ExtensionConstraint: mConfig.getSubStore is null"); + } else { + CMS.debug("ExtensionConstraint: setConfig name=" + name + + " value=" + value); + + if (name.equals(CONFIG_OID)) { + try { + CMS.checkOID("", value); + } catch (Exception e) { + throw new EPropertyException( + CMS.getUserMessage("CMS_PROFILE_PROPERTY_ERROR", value)); + } + } + mConfig.getSubStore("params").putString(name, value); + } + } + + public IDescriptor getConfigDescriptor(Locale locale, String name) { + if (name.equals(CONFIG_CRITICAL)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_CRITICAL")); + } else if (name.equals(CONFIG_OID)) { + return new Descriptor(IDescriptor.STRING, null, + null, + CMS.getUserMessage(locale, "CMS_PROFILE_OID")); + } + return null; + } + + /** + * Validates the request. The request is not modified + * during the validation. + */ + public void validate(IRequest request, X509CertInfo info) + throws ERejectException { + + Extension ext = getExtension(getConfig(CONFIG_OID), info); + + if (ext == null) { + throw new ERejectException( + CMS.getUserMessage( + getLocale(request), + "CMS_PROFILE_EXTENSION_NOT_FOUND", + getConfig(CONFIG_OID))); + } + + // check criticality + String value = getConfig(CONFIG_CRITICAL); + + if (!isOptional(value)) { + boolean critical = getBoolean(value); + + if (critical != ext.isCritical()) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_CRITICAL_NOT_MATCHED")); + } + } + } + + public String getText(Locale locale) { + String params[] = { + getConfig(CONFIG_CRITICAL), + getConfig(CONFIG_OID) + }; + + return CMS.getUserMessage(locale, + "CMS_PROFILE_CONSTRAINT_EXTENSION_TEXT", params); + } + + public boolean isApplicable(IPolicyDefault def) { + if (def instanceof NoDefault) + return true; + if (def instanceof UserExtensionDefault) + return true; + if (def instanceof EnrollExtDefault) + return true; + return false; + } +} diff --git a/base/common/src/com/netscape/cms/profile/constraint/KeyConstraint.java b/base/common/src/com/netscape/cms/profile/constraint/KeyConstraint.java new file mode 100644 index 000000000..e6f5019a0 --- /dev/null +++ b/base/common/src/com/netscape/cms/profile/constraint/KeyConstraint.java @@ -0,0 +1,644 @@ +// --- 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.profile.constraint; + +import java.math.BigInteger; +import java.security.interfaces.DSAParams; +import java.util.HashMap; +import java.util.Locale; +import java.util.Vector; + +import netscape.security.provider.DSAPublicKey; +import netscape.security.provider.RSAPublicKey; +import netscape.security.x509.AlgorithmId; +import netscape.security.x509.CertificateX509Key; +import netscape.security.x509.X509CertInfo; +import netscape.security.x509.X509Key; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.profile.IPolicyDefault; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.property.Descriptor; +import com.netscape.certsrv.property.EPropertyException; +import com.netscape.certsrv.property.IDescriptor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.profile.def.NoDefault; +import com.netscape.cms.profile.def.UserKeyDefault; + +/** + * This constraint is to check the key type and + * key length. + * + * @version $Revision$, $Date$ + */ +@SuppressWarnings("serial") +public class KeyConstraint extends EnrollConstraint { + + public static final String CONFIG_KEY_TYPE = "keyType"; // (EC, RSA) + public static final String CONFIG_KEY_PARAMETERS = "keyParameters"; + + private static final String[] ecCurves = { + "nistp256", "nistp384", "nistp521", "sect163k1", "nistk163", "sect163r1", "sect163r2", + "nistb163", "sect193r1", "sect193r2", "sect233k1", "nistk233", "sect233r1", "nistb233", "sect239k1", + "sect283k1", "nistk283", + "sect283r1", "nistb283", "sect409k1", "nistk409", "sect409r1", "nistb409", "sect571k1", "nistk571", + "sect571r1", "nistb571", + "secp160k1", "secp160r1", "secp160r2", "secp192k1", "secp192r1", "nistp192", "secp224k1", "secp224r1", + "nistp224", "secp256k1", + "secp256r1", "secp384r1", "secp521r1", "prime192v1", "prime192v2", "prime192v3", "prime239v1", + "prime239v2", "prime239v3", "c2pnb163v1", + "c2pnb163v2", "c2pnb163v3", "c2pnb176v1", "c2tnb191v1", "c2tnb191v2", "c2tnb191v3", "c2pnb208w1", + "c2tnb239v1", "c2tnb239v2", "c2tnb239v3", + "c2pnb272w1", "c2pnb304w1", "c2tnb359w1", "c2pnb368w1", "c2tnb431r1", "secp112r1", "secp112r2", + "secp128r1", "secp128r2", "sect113r1", "sect113r2", + "sect131r1", "sect131r2" + }; + + private final static HashMap> ecOIDs = new HashMap>(); + static { + ecOIDs.put("1.2.840.10045.3.1.7", new Vector() { + { + add("nistp256"); + add("secp256r1"); + } + }); + ecOIDs.put("1.3.132.0.34", new Vector() { + { + add("nistp384"); + add("secp384r1"); + } + }); + ecOIDs.put("1.3.132.0.35", new Vector() { + { + add("nistp521"); + add("secp521r1"); + } + }); + ecOIDs.put("1.3.132.0.1", new Vector() { + { + add("sect163k1"); + add("nistk163"); + } + }); + ecOIDs.put("1.3.132.0.2", new Vector() { + { + add("sect163r1"); + } + }); + ecOIDs.put("1.3.132.0.15", new Vector() { + { + add("sect163r2"); + add("nistb163"); + } + }); + ecOIDs.put("1.3.132.0.24", new Vector() { + { + add("sect193r1"); + } + }); + ecOIDs.put("1.3.132.0.25", new Vector() { + { + add("sect193r2"); + } + }); + ecOIDs.put("1.3.132.0.26", new Vector() { + { + add("sect233k1"); + add("nistk233"); + } + }); + ecOIDs.put("1.3.132.0.27", new Vector() { + { + add("sect233r1"); + add("nistb233"); + } + }); + ecOIDs.put("1.3.132.0.3", new Vector() { + { + add("sect239k1"); + } + }); + ecOIDs.put("1.3.132.0.16", new Vector() { + { + add("sect283k1"); + add("nistk283"); + } + }); + ecOIDs.put("1.3.132.0.17", new Vector() { + { + add("sect283r1"); + add("nistb283"); + } + }); + ecOIDs.put("1.3.132.0.36", new Vector() { + { + add("sect409k1"); + add("nistk409"); + } + }); + ecOIDs.put("1.3.132.0.37", new Vector() { + { + add("sect409r1"); + add("nistb409"); + } + }); + ecOIDs.put("1.3.132.0.38", new Vector() { + { + add("sect571k1"); + add("nistk571"); + } + }); + ecOIDs.put("1.3.132.0.39", new Vector() { + { + add("sect571r1"); + add("nistb571"); + } + }); + ecOIDs.put("1.3.132.0.9", new Vector() { + { + add("secp160k1"); + } + }); + ecOIDs.put("1.3.132.0.8", new Vector() { + { + add("secp160r1"); + } + }); + ecOIDs.put("1.3.132.0.30", new Vector() { + { + add("secp160r2"); + } + }); + ecOIDs.put("1.3.132.0.31", new Vector() { + { + add("secp192k1"); + } + }); + ecOIDs.put("1.2.840.10045.3.1.1", new Vector() { + { + add("secp192r1"); + add("nistp192"); + add("prime192v1"); + } + }); + ecOIDs.put("1.3.132.0.32", new Vector() { + { + add("secp224k1"); + } + }); + ecOIDs.put("1.3.132.0.33", new Vector() { + { + add("secp224r1"); + add("nistp224"); + } + }); + ecOIDs.put("1.3.132.0.10", new Vector() { + { + add("secp256k1"); + } + }); + ecOIDs.put("1.2.840.10045.3.1.2", new Vector() { + { + add("prime192v2"); + } + }); + ecOIDs.put("1.2.840.10045.3.1.3", new Vector() { + { + add("prime192v3"); + } + }); + ecOIDs.put("1.2.840.10045.3.1.4", new Vector() { + { + add("prime239v1"); + } + }); + ecOIDs.put("1.2.840.10045.3.1.5", new Vector() { + { + add("prime239v2"); + } + }); + ecOIDs.put("1.2.840.10045.3.1.6", new Vector() { + { + add("prime239v3"); + } + }); + ecOIDs.put("1.2.840.10045.3.0.1", new Vector() { + { + add("c2pnb163v1"); + } + }); + ecOIDs.put("1.2.840.10045.3.0.2", new Vector() { + { + add("c2pnb163v2"); + } + }); + ecOIDs.put("1.2.840.10045.3.0.3", new Vector() { + { + add("c2pnb163v3"); + } + }); + ecOIDs.put("1.2.840.10045.3.0.4", new Vector() { + { + add("c2pnb176v1"); + } + }); + ecOIDs.put("1.2.840.10045.3.0.5", new Vector() { + { + add("c2tnb191v1"); + } + }); + ecOIDs.put("1.2.840.10045.3.0.6", new Vector() { + { + add("c2tnb191v2"); + } + }); + ecOIDs.put("1.2.840.10045.3.0.7", new Vector() { + { + add("c2tnb191v3"); + } + }); + ecOIDs.put("1.2.840.10045.3.0.10", new Vector() { + { + add("c2pnb208w1"); + } + }); + ecOIDs.put("1.2.840.10045.3.0.11", new Vector() { + { + add("c2tnb239v1"); + } + }); + ecOIDs.put("1.2.840.10045.3.0.12", new Vector() { + { + add("c2tnb239v2"); + } + }); + ecOIDs.put("1.2.840.10045.3.0.13", new Vector() { + { + add("c2tnb239v3"); + } + }); + ecOIDs.put("1.2.840.10045.3.0.16", new Vector() { + { + add("c2pnb272w1"); + } + }); + ecOIDs.put("1.2.840.10045.3.0.17", new Vector() { + { + add("c2pnb304w1"); + } + }); + ecOIDs.put("1.2.840.10045.3.0.19", new Vector() { + { + add("c2pnb368w1"); + } + }); + ecOIDs.put("1.2.840.10045.3.0.20", new Vector() { + { + add("c2tnb431r1"); + } + }); + ecOIDs.put("1.3.132.0.6", new Vector() { + { + add("secp112r1"); + } + }); + ecOIDs.put("1.3.132.0.7", new Vector() { + { + add("secp112r2"); + } + }); + ecOIDs.put("1.3.132.0.28", new Vector() { + { + add("secp128r1"); + } + }); + ecOIDs.put("1.3.132.0.29", new Vector() { + { + add("secp128r2"); + } + }); + ecOIDs.put("1.3.132.0.4", new Vector() { + { + add("sect113r1"); + } + }); + ecOIDs.put("1.3.132.0.5", new Vector() { + { + add("sect113r2"); + } + }); + ecOIDs.put("1.3.132.0.22", new Vector() { + { + add("sect131r1"); + } + }); + ecOIDs.put("1.3.132.0.23", new Vector() { + { + add("sect131r2"); + } + }); + } + + private static String[] cfgECCurves = null; + private static String keyType = ""; + private static String keyParams = ""; + + public KeyConstraint() { + super(); + addConfigName(CONFIG_KEY_TYPE); + addConfigName(CONFIG_KEY_PARAMETERS); + } + + public void init(IProfile profile, IConfigStore config) + throws EProfileException { + super.init(profile, config); + + String ecNames = ""; + try { + ecNames = CMS.getConfigStore().getString("keys.ecc.curve.list"); + } catch (Exception e) { + } + + CMS.debug("KeyConstraint.init ecNames: " + ecNames); + if (ecNames != null && ecNames.length() != 0) { + cfgECCurves = ecNames.split(","); + } + } + + public IDescriptor getConfigDescriptor(Locale locale, String name) { + if (name.equals(CONFIG_KEY_TYPE)) { + return new Descriptor(IDescriptor.CHOICE, "-,RSA,EC", + "RSA", + CMS.getUserMessage(locale, "CMS_PROFILE_KEY_TYPE")); + } else if (name.equals(CONFIG_KEY_PARAMETERS)) { + return new Descriptor(IDescriptor.STRING, null, "", + CMS.getUserMessage(locale, "CMS_PROFILE_KEY_PARAMETERS")); + } + + return null; + } + + /** + * Validates the request. The request is not modified + * during the validation. + */ + public void validate(IRequest request, X509CertInfo info) + throws ERejectException { + try { + CertificateX509Key infokey = (CertificateX509Key) + info.get(X509CertInfo.KEY); + X509Key key = (X509Key) infokey.get(CertificateX509Key.KEY); + + String alg = key.getAlgorithmId().getName().toUpperCase(); + String value = getConfig(CONFIG_KEY_TYPE); + String keyType = value; + + if (!isOptional(value)) { + if (!alg.equals(value)) { + throw new ERejectException( + CMS.getUserMessage( + getLocale(request), + "CMS_PROFILE_KEY_TYPE_NOT_MATCHED", + value)); + } + } + + int keySize = 0; + + if (alg.equals("RSA")) { + keySize = getRSAKeyLen(key); + } else if (alg.equals("DSA")) { + keySize = getDSAKeyLen(key); + } else if (alg.equals("EC")) { + //EC key case. + } else { + throw new ERejectException( + CMS.getUserMessage( + getLocale(request), + "CMS_PROFILE_INVALID_KEY_TYPE", + alg)); + } + + value = getConfig(CONFIG_KEY_PARAMETERS); + + String[] keyParams = value.split(","); + + if (alg.equals("EC")) { + if (!alg.equals(keyType) && !isOptional(keyType)) { + throw new ERejectException( + CMS.getUserMessage( + getLocale(request), + "CMS_PROFILE_KEY_PARAMS_NOT_MATCHED", + value)); + } + + AlgorithmId algid = key.getAlgorithmId(); + + CMS.debug("algId: " + algid); + + //Get raw string representation of alg parameters, will give + //us the curve OID. + + String params = null; + if (algid != null) { + params = algid.getParametersString(); + } + + if (params.startsWith("OID.")) { + params = params.substring(4); + } + + CMS.debug("EC key OID: " + params); + Vector vect = ecOIDs.get(params); + + boolean curveFound = false; + + if (vect != null) { + CMS.debug("vect: " + vect.toString()); + + if (!isOptional(keyType)) { + //Check the curve parameters only if explicit ECC or not optional + for (int i = 0; i < keyParams.length; i++) { + String ecParam = keyParams[i]; + CMS.debug("keyParams[i]: " + i + " param: " + ecParam); + if (vect.contains(ecParam)) { + curveFound = true; + CMS.debug("KeyConstraint.validate: EC key constrainst passed."); + break; + } + } + } else { + curveFound = true; + } + } + + if (!curveFound) { + CMS.debug("KeyConstraint.validate: EC key constrainst failed."); + throw new ERejectException( + CMS.getUserMessage( + getLocale(request), + "CMS_PROFILE_KEY_PARAMS_NOT_MATCHED", + value)); + } + + } else { + if (!arrayContainsString(keyParams, Integer.toString(keySize))) { + throw new ERejectException( + CMS.getUserMessage( + getLocale(request), + "CMS_PROFILE_KEY_PARAMS_NOT_MATCHED", + value)); + } + CMS.debug("KeyConstraint.validate: RSA key contraints passed."); + } + } catch (Exception e) { + if (e instanceof ERejectException) { + throw (ERejectException) e; + } + CMS.debug("KeyConstraint: " + e.toString()); + throw new ERejectException(CMS.getUserMessage( + getLocale(request), "CMS_PROFILE_KEY_NOT_FOUND")); + } + } + + public int getRSAKeyLen(X509Key key) throws Exception { + X509Key newkey = null; + + try { + newkey = new X509Key(AlgorithmId.get("RSA"), + key.getKey()); + } catch (Exception e) { + CMS.debug("KeyConstraint: getRSAKey Len " + e.toString()); + return -1; + } + RSAPublicKey rsaKey = new RSAPublicKey(newkey.getEncoded()); + + return rsaKey.getKeySize(); + } + + public int getDSAKeyLen(X509Key key) throws Exception { + // Check DSAKey parameters. + // size refers to the p parameter. + DSAPublicKey dsaKey = new DSAPublicKey(key.getEncoded()); + DSAParams keyParams = dsaKey.getParams(); + BigInteger p = keyParams.getP(); + int len = p.bitLength(); + + return len; + } + + public String getText(Locale locale) { + String params[] = { + getConfig(CONFIG_KEY_TYPE), + getConfig(CONFIG_KEY_PARAMETERS) + }; + + return CMS.getUserMessage(locale, + "CMS_PROFILE_CONSTRAINT_KEY_TEXT", params); + } + + public boolean isApplicable(IPolicyDefault def) { + if (def instanceof NoDefault) + return true; + if (def instanceof UserKeyDefault) + return true; + return false; + } + + public void setConfig(String name, String value) + throws EPropertyException { + + CMS.debug("KeyConstraint.setConfig name: " + name + " value: " + value); + //establish keyType, we don't know which order these params will arrive + if (name.equals(CONFIG_KEY_TYPE)) { + keyType = value; + if (keyParams.equals("")) + return; + } + + //establish keyParams + if (name.equals(CONFIG_KEY_PARAMETERS)) { + CMS.debug("establish keyParams: " + value); + keyParams = value; + + if (keyType.equals("")) + return; + } + // All the params we need for validation have been collected, + // we don't know which order they will show up + if (keyType.length() > 0 && keyParams.length() > 0) { + String[] params = keyParams.split(","); + boolean isECCurve = false; + int keySize = 0; + + for (int i = 0; i < params.length; i++) { + if (keyType.equals("EC")) { + if (cfgECCurves == null) { + //Use the static array as a backup if the config values are not present. + isECCurve = arrayContainsString(ecCurves, params[i]); + } else { + isECCurve = arrayContainsString(cfgECCurves, params[i]); + } + if (isECCurve == false) { //Not a valid EC curve throw exception. + keyType = ""; + keyParams = ""; + throw new EPropertyException(CMS.getUserMessage( + "CMS_INVALID_PROPERTY", name)); + } + } else { + try { + keySize = Integer.parseInt(params[i]); + } catch (Exception e) { + keySize = 0; + } + if (keySize <= 0) { + keyType = ""; + keyParams = ""; + throw new EPropertyException(CMS.getUserMessage( + "CMS_INVALID_PROPERTY", name)); + } + } + } + } + //Actually set the configuration in the profile + super.setConfig(CONFIG_KEY_TYPE, keyType); + super.setConfig(CONFIG_KEY_PARAMETERS, keyParams); + + //Reset the vars for next round. + keyType = ""; + keyParams = ""; + } + + private boolean arrayContainsString(String[] array, String value) { + + if (array == null || value == null) { + return false; + } + + for (int i = 0; i < array.length; i++) { + if (array[i].equals(value)) { + return true; + } + } + + return false; + } +} diff --git a/base/common/src/com/netscape/cms/profile/constraint/KeyUsageExtConstraint.java b/base/common/src/com/netscape/cms/profile/constraint/KeyUsageExtConstraint.java new file mode 100644 index 000000000..927c64ec2 --- /dev/null +++ b/base/common/src/com/netscape/cms/profile/constraint/KeyUsageExtConstraint.java @@ -0,0 +1,291 @@ +// --- 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.profile.constraint; + +import java.util.Locale; + +import netscape.security.x509.KeyUsageExtension; +import netscape.security.x509.PKIXExtensions; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.profile.IPolicyDefault; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.property.Descriptor; +import com.netscape.certsrv.property.IDescriptor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.profile.def.KeyUsageExtDefault; +import com.netscape.cms.profile.def.NoDefault; +import com.netscape.cms.profile.def.UserExtensionDefault; + +/** + * This class implements the key usage extension constraint. + * It checks if the key usage constraint in the certificate + * template satisfies the criteria. + * + * @version $Revision$, $Date$ + */ +public class KeyUsageExtConstraint extends EnrollConstraint { + + public static final String CONFIG_CRITICAL = "keyUsageCritical"; + public static final String CONFIG_DIGITAL_SIGNATURE = + "keyUsageDigitalSignature"; + public static final String CONFIG_NON_REPUDIATION = + "keyUsageNonRepudiation"; + public static final String CONFIG_KEY_ENCIPHERMENT = + "keyUsageKeyEncipherment"; + public static final String CONFIG_DATA_ENCIPHERMENT = + "keyUsageDataEncipherment"; + public static final String CONFIG_KEY_AGREEMENT = "keyUsageKeyAgreement"; + public static final String CONFIG_KEY_CERTSIGN = "keyUsageKeyCertSign"; + public static final String CONFIG_CRL_SIGN = "keyUsageCrlSign"; + public static final String CONFIG_ENCIPHER_ONLY = "keyUsageEncipherOnly"; + public static final String CONFIG_DECIPHER_ONLY = "keyUsageDecipherOnly"; + + public KeyUsageExtConstraint() { + super(); + addConfigName(CONFIG_CRITICAL); + addConfigName(CONFIG_DIGITAL_SIGNATURE); + addConfigName(CONFIG_NON_REPUDIATION); + addConfigName(CONFIG_KEY_ENCIPHERMENT); + addConfigName(CONFIG_DATA_ENCIPHERMENT); + addConfigName(CONFIG_KEY_AGREEMENT); + addConfigName(CONFIG_KEY_CERTSIGN); + addConfigName(CONFIG_CRL_SIGN); + addConfigName(CONFIG_ENCIPHER_ONLY); + addConfigName(CONFIG_DECIPHER_ONLY); + } + + public void init(IProfile profile, IConfigStore config) + throws EProfileException { + super.init(profile, config); + + } + + public IDescriptor getConfigDescriptor(Locale locale, String name) { + if (name.equals(CONFIG_CRITICAL)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_CRITICAL")); + } else if (name.equals(CONFIG_DIGITAL_SIGNATURE)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_DIGITAL_SIGNATURE")); + } else if (name.equals(CONFIG_NON_REPUDIATION)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_NON_REPUDIATION")); + } else if (name.equals(CONFIG_KEY_ENCIPHERMENT)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_KEY_ENCIPHERMENT")); + } else if (name.equals(CONFIG_DATA_ENCIPHERMENT)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_DATA_ENCIPHERMENT")); + } else if (name.equals(CONFIG_KEY_AGREEMENT)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_KEY_AGREEMENT")); + } else if (name.equals(CONFIG_KEY_CERTSIGN)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_KEY_CERTSIGN")); + } else if (name.equals(CONFIG_CRL_SIGN)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_CRL_SIGN")); + } else if (name.equals(CONFIG_ENCIPHER_ONLY)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_ENCIPHER_ONLY")); + } else if (name.equals(CONFIG_DECIPHER_ONLY)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_DECIPHER_ONLY")); + } + return null; + } + + public boolean isSet(boolean bits[], int position) { + if (bits.length <= position) + return false; + return bits[position]; + } + + /** + * Validates the request. The request is not modified + * during the validation. + */ + public void validate(IRequest request, X509CertInfo info) + throws ERejectException { + KeyUsageExtension ext = (KeyUsageExtension) + getExtension(PKIXExtensions.KeyUsage_Id.toString(), info); + + if (ext == null) { + throw new ERejectException( + CMS.getUserMessage( + getLocale(request), + "CMS_PROFILE_EXTENSION_NOT_FOUND", + PKIXExtensions.KeyUsage_Id.toString())); + } + + boolean[] bits = ext.getBits(); + String value = getConfig(CONFIG_CRITICAL); + + if (!isOptional(value)) { + boolean critical = getBoolean(value); + + if (critical != ext.isCritical()) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_CRITICAL_NOT_MATCHED")); + } + } + value = getConfig(CONFIG_DIGITAL_SIGNATURE); + if (!isOptional(value)) { + boolean bit = getBoolean(value); + + if (bit != isSet(bits, 0)) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_DIGITAL_SIGNATURE_NOT_MATCHED", + value)); + } + } + value = getConfig(CONFIG_NON_REPUDIATION); + if (!isOptional(value)) { + boolean bit = getBoolean(value); + + if (bit != isSet(bits, 1)) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_NON_REPUDIATION_NOT_MATCHED", + value)); + } + } + value = getConfig(CONFIG_KEY_ENCIPHERMENT); + if (!isOptional(value)) { + boolean bit = getBoolean(value); + + if (bit != isSet(bits, 2)) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_KEY_ENCIPHERMENT_NOT_MATCHED", + value)); + } + } + value = getConfig(CONFIG_DATA_ENCIPHERMENT); + if (!isOptional(value)) { + boolean bit = getBoolean(value); + + if (bit != isSet(bits, 3)) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_DATA_ENCIPHERMENT_NOT_MATCHED", + value)); + } + } + value = getConfig(CONFIG_KEY_AGREEMENT); + if (!isOptional(value)) { + boolean bit = getBoolean(value); + + if (bit != isSet(bits, 4)) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_KEY_AGREEMENT_NOT_MATCHED", + value)); + } + } + value = getConfig(CONFIG_KEY_CERTSIGN); + if (!isOptional(value)) { + boolean bit = getBoolean(value); + + if (bit != isSet(bits, 5)) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_KEY_CERTSIGN_NOT_MATCHED", + value)); + } + } + value = getConfig(CONFIG_CRL_SIGN); + if (!isOptional(value)) { + boolean bit = getBoolean(value); + + if (bit != isSet(bits, 6)) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_CRL_SIGN_NOT_MATCHED", + value)); + } + } + value = getConfig(CONFIG_ENCIPHER_ONLY); + if (!isOptional(value)) { + boolean bit = getBoolean(value); + + if (bit != isSet(bits, 7)) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_ENCIPHER_ONLY_NOT_MATCHED", + value)); + } + } + value = getConfig(CONFIG_DECIPHER_ONLY); + if (!isOptional(value)) { + boolean bit = getBoolean(value); + + if (bit != isSet(bits, 8)) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_DECIPHER_ONLY_NOT_MATCHED", + value)); + } + } + } + + public String getText(Locale locale) { + String params[] = { + getConfig(CONFIG_CRITICAL), + getConfig(CONFIG_DIGITAL_SIGNATURE), + getConfig(CONFIG_NON_REPUDIATION), + getConfig(CONFIG_KEY_ENCIPHERMENT), + getConfig(CONFIG_DATA_ENCIPHERMENT), + getConfig(CONFIG_KEY_AGREEMENT), + getConfig(CONFIG_KEY_CERTSIGN), + getConfig(CONFIG_CRL_SIGN), + getConfig(CONFIG_ENCIPHER_ONLY), + getConfig(CONFIG_DECIPHER_ONLY) + }; + + return CMS.getUserMessage(locale, + "CMS_PROFILE_CONSTRAINT_KEY_USAGE_EXT_TEXT", params); + } + + public boolean isApplicable(IPolicyDefault def) { + if (def instanceof NoDefault) + return true; + if (def instanceof KeyUsageExtDefault) + return true; + if (def instanceof UserExtensionDefault) + return true; + return false; + } +} diff --git a/base/common/src/com/netscape/cms/profile/constraint/NSCertTypeExtConstraint.java b/base/common/src/com/netscape/cms/profile/constraint/NSCertTypeExtConstraint.java new file mode 100644 index 000000000..843360542 --- /dev/null +++ b/base/common/src/com/netscape/cms/profile/constraint/NSCertTypeExtConstraint.java @@ -0,0 +1,243 @@ +// --- 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.profile.constraint; + +import java.util.Locale; + +import netscape.security.extensions.NSCertTypeExtension; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.profile.IPolicyDefault; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.property.Descriptor; +import com.netscape.certsrv.property.IDescriptor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.profile.def.NSCertTypeExtDefault; +import com.netscape.cms.profile.def.NoDefault; +import com.netscape.cms.profile.def.UserExtensionDefault; + +/** + * This class implements the Netscape certificate type extension constraint. + * It checks if the Netscape certificate type extension in the certificate + * template satisfies the criteria. + * + * @version $Revision$, $Date$ + */ +public class NSCertTypeExtConstraint extends EnrollConstraint { + + public static final String CONFIG_CRITICAL = "nsCertCritical"; + public static final String CONFIG_SSL_CLIENT = "nsCertSSLClient"; + public static final String CONFIG_SSL_SERVER = "nsCertSSLServer"; + public static final String CONFIG_EMAIL = "nsCertEmail"; + public static final String CONFIG_OBJECT_SIGNING = "nsCertObjectSigning"; + public static final String CONFIG_SSL_CA = "nsCertSSLCA"; + public static final String CONFIG_EMAIL_CA = "nsCertEmailCA"; + public static final String CONFIG_OBJECT_SIGNING_CA = "nsCertObjectSigningCA"; + + public NSCertTypeExtConstraint() { + super(); + addConfigName(CONFIG_CRITICAL); + addConfigName(CONFIG_SSL_CLIENT); + addConfigName(CONFIG_SSL_SERVER); + addConfigName(CONFIG_EMAIL); + addConfigName(CONFIG_OBJECT_SIGNING); + addConfigName(CONFIG_SSL_CA); + addConfigName(CONFIG_EMAIL_CA); + addConfigName(CONFIG_OBJECT_SIGNING_CA); + } + + public void init(IProfile profile, IConfigStore config) + throws EProfileException { + super.init(profile, config); + } + + public IDescriptor getConfigDescriptor(Locale locale, String name) { + if (name.equals(CONFIG_CRITICAL)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_CRITICAL")); + } else if (name.equals(CONFIG_SSL_CLIENT)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_SSL_CLIENT")); + } else if (name.equals(CONFIG_SSL_SERVER)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_SSL_SERVER")); + } else if (name.equals(CONFIG_EMAIL)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_EMAIL")); + } else if (name.equals(CONFIG_OBJECT_SIGNING)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_OBJECT_SIGNING")); + } else if (name.equals(CONFIG_SSL_CA)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_SSL_CA")); + } else if (name.equals(CONFIG_EMAIL_CA)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, "CMS_PROFILE_EMAIL_CA")); + } else if (name.equals(CONFIG_OBJECT_SIGNING_CA)) { + return new Descriptor(IDescriptor.CHOICE, "true,false,-", + "-", + CMS.getUserMessage(locale, + "CMS_PROFILE_OBJECT_SIGNING_CA")); + } + return null; + } + + /** + * Validates the request. The request is not modified + * during the validation. + */ + public void validate(IRequest request, X509CertInfo info) + throws ERejectException { + NSCertTypeExtension ext = (NSCertTypeExtension) + getExtension(NSCertTypeExtension.CertType_Id.toString(), info); + + if (ext == null) { + throw new ERejectException( + CMS.getUserMessage( + getLocale(request), + "CMS_PROFILE_EXTENSION_NOT_FOUND", + NSCertTypeExtension.CertType_Id.toString())); + } + + String value = getConfig(CONFIG_CRITICAL); + + if (!isOptional(value)) { + boolean critical = getBoolean(value); + + if (critical != ext.isCritical()) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_CRITICAL_NOT_MATCHED")); + } + } + value = getConfig(CONFIG_SSL_CLIENT); + if (!isOptional(value)) { + boolean bit = getBoolean(value); + + if (bit != ext.isSet(0)) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_SSL_CLIENT_NOT_MATCHED", + value)); + } + } + value = getConfig(CONFIG_SSL_SERVER); + if (!isOptional(value)) { + boolean bit = getBoolean(value); + + if (bit != ext.isSet(1)) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_SSL_SERVER_NOT_MATCHED", + value)); + } + } + value = getConfig(CONFIG_EMAIL); + if (!isOptional(value)) { + boolean bit = getBoolean(value); + + if (bit != ext.isSet(2)) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_EMAIL_NOT_MATCHED", + value)); + } + } + value = getConfig(CONFIG_OBJECT_SIGNING); + if (!isOptional(value)) { + boolean bit = getBoolean(value); + + if (bit != ext.isSet(3)) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_OBJECT_SIGNING_NOT_MATCHED", + value)); + } + } + value = getConfig(CONFIG_SSL_CA); + if (!isOptional(value)) { + boolean bit = getBoolean(value); + + if (bit != ext.isSet(4)) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_SSL_CA_NOT_MATCHED", + value)); + } + } + value = getConfig(CONFIG_EMAIL_CA); + if (!isOptional(value)) { + boolean bit = getBoolean(value); + + if (bit != ext.isSet(5)) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_EMAIL_CA_NOT_MATCHED", + value)); + } + } + value = getConfig(CONFIG_OBJECT_SIGNING_CA); + if (!isOptional(value)) { + boolean bit = getBoolean(value); + + if (bit != ext.isSet(6)) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_OBJECT_SIGNING_CA_NOT_MATCHED", + value)); + } + } + } + + public String getText(Locale locale) { + String params[] = { + getConfig(CONFIG_CRITICAL), + getConfig(CONFIG_SSL_CLIENT), + getConfig(CONFIG_SSL_SERVER), + getConfig(CONFIG_EMAIL), + getConfig(CONFIG_OBJECT_SIGNING), + getConfig(CONFIG_SSL_CA), + getConfig(CONFIG_EMAIL_CA), + getConfig(CONFIG_OBJECT_SIGNING_CA) + }; + + return CMS.getUserMessage(locale, + "CMS_PROFILE_CONSTRAINT_NS_CERT_EXT_TEXT", params); + } + + public boolean isApplicable(IPolicyDefault def) { + if (def instanceof NoDefault) + return true; + if (def instanceof NSCertTypeExtDefault) + return true; + if (def instanceof UserExtensionDefault) + return true; + return false; + } +} diff --git a/base/common/src/com/netscape/cms/profile/constraint/NoConstraint.java b/base/common/src/com/netscape/cms/profile/constraint/NoConstraint.java new file mode 100644 index 000000000..459e9f219 --- /dev/null +++ b/base/common/src/com/netscape/cms/profile/constraint/NoConstraint.java @@ -0,0 +1,101 @@ +// --- 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.profile.constraint; + +import java.util.Enumeration; +import java.util.Locale; +import java.util.Vector; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.profile.IPolicyConstraint; +import com.netscape.certsrv.profile.IPolicyDefault; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.property.EPropertyException; +import com.netscape.certsrv.property.IDescriptor; +import com.netscape.certsrv.request.IRequest; + +/** + * This class implements no constraint. + * + * @version $Revision$, $Date$ + */ +public class NoConstraint implements IPolicyConstraint { + + public static final String CONFIG_NAME = "name"; + + private IConfigStore mConfig = null; + private Vector mNames = new Vector(); + + public Enumeration getConfigNames() { + return mNames.elements(); + } + + public IDescriptor getConfigDescriptor(Locale locale, String name) { + return null; + } + + public void setConfig(String name, String value) + throws EPropertyException { + } + + public String getConfig(String name) { + return null; + } + + public String getDefaultConfig(String name) { + return null; + } + + public void init(IProfile profile, IConfigStore config) + throws EProfileException { + mConfig = config; + } + + public IConfigStore getConfigStore() { + return mConfig; + } + + /** + * Validates the request. The request is not modified + * during the validation. + */ + public void validate(IRequest request) + throws ERejectException { + } + + public String getText(Locale locale) { + return CMS.getUserMessage(locale, + "CMS_PROFILE_CONSTRAINT_NO_CONSTRAINT_TEXT"); + } + + public String getName(Locale locale) { + try { + return mConfig.getString(CONFIG_NAME); + } catch (EBaseException e) { + return null; + } + } + + public boolean isApplicable(IPolicyDefault def) { + return true; + } +} diff --git a/base/common/src/com/netscape/cms/profile/constraint/RenewGracePeriodConstraint.java b/base/common/src/com/netscape/cms/profile/constraint/RenewGracePeriodConstraint.java new file mode 100644 index 000000000..fb01d7d14 --- /dev/null +++ b/base/common/src/com/netscape/cms/profile/constraint/RenewGracePeriodConstraint.java @@ -0,0 +1,165 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cms.profile.constraint; + +import java.math.BigInteger; +import java.util.Date; +import java.util.Locale; + +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.profile.IPolicyDefault; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.property.Descriptor; +import com.netscape.certsrv.property.EPropertyException; +import com.netscape.certsrv.property.IDescriptor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.profile.def.NoDefault; + +/** + * This class supports renewal grace period, which has two + * parameters: graceBefore and graceAfter + * + * @author Christina Fu + * @version $Revision$, $Date$ + */ +public class RenewGracePeriodConstraint extends EnrollConstraint { + + // for renewal: # of days before the orig cert expiration date + public static final String CONFIG_RENEW_GRACE_BEFORE = "renewal.graceBefore"; + // for renewal: # of days after the orig cert expiration date + public static final String CONFIG_RENEW_GRACE_AFTER = "renewal.graceAfter"; + + public RenewGracePeriodConstraint() { + super(); + addConfigName(CONFIG_RENEW_GRACE_BEFORE); + addConfigName(CONFIG_RENEW_GRACE_AFTER); + } + + public void init(IProfile profile, IConfigStore config) + throws EProfileException { + super.init(profile, config); + } + + public void setConfig(String name, String value) + throws EPropertyException { + if (name.equals(CONFIG_RENEW_GRACE_BEFORE) || + name.equals(CONFIG_RENEW_GRACE_AFTER)) { + try { + Integer.parseInt(value); + } catch (Exception e) { + throw new EPropertyException(CMS.getUserMessage( + "CMS_INVALID_PROPERTY", CONFIG_RENEW_GRACE_BEFORE + " or " + CONFIG_RENEW_GRACE_AFTER)); + } + } + super.setConfig(name, value); + } + + public IDescriptor getConfigDescriptor(Locale locale, String name) { + if (name.equals(CONFIG_RENEW_GRACE_BEFORE)) { + return new Descriptor(IDescriptor.INTEGER, null, "30", + CMS.getUserMessage(locale, "CMS_PROFILE_RENEW_GRACE_BEFORE")); + } else if (name.equals(CONFIG_RENEW_GRACE_AFTER)) { + return new Descriptor(IDescriptor.INTEGER, null, "30", + CMS.getUserMessage(locale, "CMS_PROFILE_RENEW_GRACE_AFTER")); + } + return null; + } + + public void validate(IRequest req, X509CertInfo info) + throws ERejectException { + String origExpDate_s = req.getExtDataInString("origNotAfter"); + // probably not for renewal + if (origExpDate_s == null) { + return; + } else { + CMS.debug("validate RenewGracePeriod: original cert expiration date found... renewing"); + } + CMS.debug("ValidilityConstraint: validateRenewGraceperiod begins"); + BigInteger origExpDate_BI = new BigInteger(origExpDate_s); + Date origExpDate = new Date(origExpDate_BI.longValue()); + String renew_grace_before_s = getConfig(CONFIG_RENEW_GRACE_BEFORE); + String renew_grace_after_s = getConfig(CONFIG_RENEW_GRACE_AFTER); + int renew_grace_before = 0; + int renew_grace_after = 0; + BigInteger renew_grace_before_BI = new BigInteger(renew_grace_before_s); + BigInteger renew_grace_after_BI = new BigInteger(renew_grace_after_s); + + // -1 means no limit + if (renew_grace_before_s == "") + renew_grace_before = -1; + else + renew_grace_before = Integer.parseInt(renew_grace_before_s); + + if (renew_grace_after_s == "") + renew_grace_after = -1; + else + renew_grace_after = Integer.parseInt(renew_grace_after_s); + + if (renew_grace_before > 0) + renew_grace_before_BI = renew_grace_before_BI.multiply(BigInteger.valueOf(1000 * 86400)); + if (renew_grace_after > 0) + renew_grace_after_BI = renew_grace_after_BI.multiply(BigInteger.valueOf(1000 * 86400)); + + Date current = CMS.getCurrentDate(); + long millisDiff = origExpDate.getTime() - current.getTime(); + CMS.debug("validateRenewGracePeriod: millisDiff=" + + millisDiff + " origExpDate=" + origExpDate.getTime() + " current=" + current.getTime()); + + /* + * "days", if positive, has to be less than renew_grace_before + * "days", if negative, means already past expiration date, + * (abs value) has to be less than renew_grace_after + * if renew_grace_before or renew_grace_after are negative + * the one with negative value is ignored + */ + if (millisDiff >= 0) { + if ((renew_grace_before > 0) && (millisDiff > renew_grace_before_BI.longValue())) { + throw new ERejectException(CMS.getUserMessage(getLocale(req), + "CMS_PROFILE_RENEW_OUTSIDE_GRACE_PERIOD", + renew_grace_before + " days before and " + + renew_grace_after + " days after original cert expiration date")); + } + } else { + if ((renew_grace_after > 0) && ((0 - millisDiff) > renew_grace_after_BI.longValue())) { + throw new ERejectException(CMS.getUserMessage(getLocale(req), + "CMS_PROFILE_RENEW_OUTSIDE_GRACE_PERIOD", + renew_grace_before + " days before and " + + renew_grace_after + " days after original cert expiration date")); + } + } + } + + public String getText(Locale locale) { + String renew_grace_before_s = getConfig(CONFIG_RENEW_GRACE_BEFORE); + String renew_grace_after_s = getConfig(CONFIG_RENEW_GRACE_AFTER); + return CMS.getUserMessage(locale, "CMS_PROFILE_CONSTRAINT_VALIDITY_TEXT", + renew_grace_before_s + " days before and " + + renew_grace_after_s + " days after original cert expiration date"); + } + + public boolean isApplicable(IPolicyDefault def) { + if (def instanceof NoDefault) + return true; + return false; + } +} diff --git a/base/common/src/com/netscape/cms/profile/constraint/SigningAlgConstraint.java b/base/common/src/com/netscape/cms/profile/constraint/SigningAlgConstraint.java new file mode 100644 index 000000000..4dbe329b3 --- /dev/null +++ b/base/common/src/com/netscape/cms/profile/constraint/SigningAlgConstraint.java @@ -0,0 +1,160 @@ +// --- 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.profile.constraint; + +import java.util.Locale; +import java.util.StringTokenizer; +import java.util.Vector; + +import netscape.security.x509.AlgorithmId; +import netscape.security.x509.CertificateAlgorithmId; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.profile.IPolicyDefault; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.property.Descriptor; +import com.netscape.certsrv.property.EPropertyException; +import com.netscape.certsrv.property.IDescriptor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.profile.def.NoDefault; +import com.netscape.cms.profile.def.SigningAlgDefault; +import com.netscape.cms.profile.def.UserSigningAlgDefault; + +/** + * This class implements the signing algorithm constraint. + * It checks if the signing algorithm in the certificate + * template satisfies the criteria. + * + * @version $Revision$, $Date$ + */ +public class SigningAlgConstraint extends EnrollConstraint { + + public static final String CONFIG_ALGORITHMS_ALLOWED = "signingAlgsAllowed"; + + private static StringBuffer sb = new StringBuffer(""); + static { + for (int i = 0; i < AlgorithmId.ALL_SIGNING_ALGORITHMS.length; i++) { + if (i > 0) { + sb.append(","); + } + sb.append(AlgorithmId.ALL_SIGNING_ALGORITHMS[i]); + } + } + public static final String DEF_CONFIG_ALGORITHMS = new String(sb); + + public SigningAlgConstraint() { + super(); + addConfigName(CONFIG_ALGORITHMS_ALLOWED); + } + + public void init(IProfile profile, IConfigStore config) + throws EProfileException { + super.init(profile, config); + } + + public void setConfig(String name, String value) + throws EPropertyException { + + if (mConfig.getSubStore("params") == null) { + CMS.debug("SigningAlgConstraint: mConfig.getSubStore is null"); + } else { + CMS.debug("SigningAlgConstraint: setConfig name=" + name + + " value=" + value); + + if (name.equals(CONFIG_ALGORITHMS_ALLOWED)) { + StringTokenizer st = new StringTokenizer(value, ","); + while (st.hasMoreTokens()) { + String v = st.nextToken(); + if (DEF_CONFIG_ALGORITHMS.indexOf(v) == -1) { + throw new EPropertyException( + CMS.getUserMessage("CMS_PROFILE_PROPERTY_ERROR", v)); + } + } + } + mConfig.getSubStore("params").putString(name, value); + } + } + + public IDescriptor getConfigDescriptor(Locale locale, String name) { + if (name.equals(CONFIG_ALGORITHMS_ALLOWED)) { + return new Descriptor(IDescriptor.STRING, null, + DEF_CONFIG_ALGORITHMS, + CMS.getUserMessage(locale, + "CMS_PROFILE_SIGNING_ALGORITHMS_ALLOWED")); + } + return null; + } + + /** + * Validates the request. The request is not modified + * during the validation. + */ + public void validate(IRequest request, X509CertInfo info) + throws ERejectException { + CertificateAlgorithmId algId = null; + + try { + algId = (CertificateAlgorithmId) info.get(X509CertInfo.ALGORITHM_ID); + AlgorithmId id = (AlgorithmId) + algId.get(CertificateAlgorithmId.ALGORITHM); + + Vector mCache = new Vector(); + StringTokenizer st = new StringTokenizer( + getConfig(CONFIG_ALGORITHMS_ALLOWED), ","); + + while (st.hasMoreTokens()) { + String token = st.nextToken(); + + mCache.addElement(token); + } + + if (!mCache.contains(id.toString())) { + throw new ERejectException(CMS.getUserMessage( + getLocale(request), + "CMS_PROFILE_SIGNING_ALGORITHM_NOT_MATCHED", id.toString())); + } + } catch (Exception e) { + if (e instanceof ERejectException) { + throw (ERejectException) e; + } + CMS.debug("SigningAlgConstraint: " + e.toString()); + throw new ERejectException(CMS.getUserMessage( + getLocale(request), "CMS_PROFILE_SIGNING_ALGORITHM_NOT_FOUND")); + } + + } + + public String getText(Locale locale) { + return CMS.getUserMessage(locale, "CMS_PROFILE_CONSTRAINT_SIGNING_ALG_TEXT", + getConfig(CONFIG_ALGORITHMS_ALLOWED)); + } + + public boolean isApplicable(IPolicyDefault def) { + if (def instanceof NoDefault) + return true; + if (def instanceof UserSigningAlgDefault) + return true; + if (def instanceof SigningAlgDefault) + return true; + return false; + } +} diff --git a/base/common/src/com/netscape/cms/profile/constraint/SubjectNameConstraint.java b/base/common/src/com/netscape/cms/profile/constraint/SubjectNameConstraint.java new file mode 100644 index 000000000..477e99b98 --- /dev/null +++ b/base/common/src/com/netscape/cms/profile/constraint/SubjectNameConstraint.java @@ -0,0 +1,136 @@ +// --- 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.profile.constraint; + +import java.io.IOException; +import java.util.Locale; + +import netscape.security.x509.CertificateSubjectName; +import netscape.security.x509.X500Name; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.profile.IPolicyDefault; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.property.Descriptor; +import com.netscape.certsrv.property.IDescriptor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.profile.def.NoDefault; +import com.netscape.cms.profile.def.SubjectNameDefault; +import com.netscape.cms.profile.def.UserSubjectNameDefault; + +/** + * This class implements the subject name constraint. + * It checks if the subject name in the certificate + * template satisfies the criteria. + * + * @version $Revision$, $Date$ + */ +public class SubjectNameConstraint extends EnrollConstraint { + + public static final String CONFIG_PATTERN = "pattern"; + + public SubjectNameConstraint() { + // configuration names + addConfigName(CONFIG_PATTERN); + } + + public void init(IProfile profile, IConfigStore config) + throws EProfileException { + super.init(profile, config); + } + + public IDescriptor getConfigDescriptor(Locale locale, String name) { + if (name.equals(CONFIG_PATTERN)) { + return new Descriptor(IDescriptor.STRING, + null, null, + CMS.getUserMessage(locale, "CMS_PROFILE_SUBJECT_NAME_PATTERN")); + } else { + return null; + } + } + + public String getDefaultConfig(String name) { + return null; + } + + /** + * Validates the request. The request is not modified + * during the validation. + */ + public void validate(IRequest request, X509CertInfo info) + throws ERejectException { + CMS.debug("SubjectNameConstraint: validate start"); + CertificateSubjectName sn = null; + + try { + sn = (CertificateSubjectName) info.get(X509CertInfo.SUBJECT); + CMS.debug("SubjectNameConstraint: validate cert subject =" + + sn.toString()); + } catch (Exception e) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_SUBJECT_NAME_NOT_FOUND")); + } + X500Name sn500 = null; + + try { + sn500 = (X500Name) sn.get(CertificateSubjectName.DN_NAME); + } catch (IOException e) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_SUBJECT_NAME_NOT_FOUND")); + } + if (sn500 == null) { + CMS.debug("SubjectNameConstraint: validate() - sn500 is null"); + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_SUBJECT_NAME_NOT_FOUND")); + } else { + CMS.debug("SubjectNameConstraint: validate() - sn500 " + + CertificateSubjectName.DN_NAME + " = " + + sn500.toString()); + } + if (!sn500.toString().matches(getConfig(CONFIG_PATTERN))) { + CMS.debug("SubjectNameConstraint: validate() - sn500 not matching pattern " + getConfig(CONFIG_PATTERN)); + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_SUBJECT_NAME_NOT_MATCHED", + sn500.toString())); + } + } + + public String getText(Locale locale) { + return CMS.getUserMessage(locale, + "CMS_PROFILE_CONSTRAINT_SUBJECT_NAME_TEXT", + getConfig(CONFIG_PATTERN)); + } + + public boolean isApplicable(IPolicyDefault def) { + if (def instanceof NoDefault) + return true; + if (def instanceof SubjectNameDefault) + return true; + if (def instanceof UserSubjectNameDefault) + return true; + return false; + } +} diff --git a/base/common/src/com/netscape/cms/profile/constraint/UniqueKeyConstraint.java b/base/common/src/com/netscape/cms/profile/constraint/UniqueKeyConstraint.java new file mode 100644 index 000000000..f10130aa6 --- /dev/null +++ b/base/common/src/com/netscape/cms/profile/constraint/UniqueKeyConstraint.java @@ -0,0 +1,295 @@ +// --- 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.profile.constraint; + +import java.util.Enumeration; +import java.util.Locale; + +import netscape.security.x509.CertificateSubjectName; +import netscape.security.x509.CertificateX509Key; +import netscape.security.x509.X500Name; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; +import netscape.security.x509.X509Key; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertRecordList; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.profile.IPolicyDefault; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.property.Descriptor; +import com.netscape.certsrv.property.IDescriptor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.profile.def.NoDefault; + +/** + * This constraint is to check for publickey uniqueness. + * The config param "allowSameKeyRenewal" enables the + * situation where if the publickey is not unique, and if + * the subject DN is the same, that is a "renewal". + * + * Another "feature" that is quoted out of this code is the + * "revokeDupKeyCert" option, which enables the revocation + * of certs that bear the same publickey as the enrolling + * request. Since this can potentially be abused, it is taken + * out and preserved in comments to allow future refinement. + * + * @version $Revision$, $Date$ + */ +public class UniqueKeyConstraint extends EnrollConstraint { + /* + public static final String CONFIG_REVOKE_DUPKEY_CERT = + "revokeDupKeyCert"; + boolean mRevokeDupKeyCert = false; + */ + public static final String CONFIG_ALLOW_SAME_KEY_RENEWAL = + "allowSameKeyRenewal"; + boolean mAllowSameKeyRenewal = false; + public ICertificateAuthority mCA = null; + + public UniqueKeyConstraint() { + super(); + /* + addConfigName(CONFIG_REVOKE_DUPKEY_CERT); + */ + addConfigName(CONFIG_ALLOW_SAME_KEY_RENEWAL); + } + + public void init(IProfile profile, IConfigStore config) + throws EProfileException { + super.init(profile, config); + mCA = (ICertificateAuthority) + CMS.getSubsystem(CMS.SUBSYSTEM_CA); + } + + public IDescriptor getConfigDescriptor(Locale locale, String name) { + /* + if (name.equals(CONFIG_REVOKE_DUPKEY_CERT)) { + return new Descriptor(IDescriptor.BOOLEAN, null, "false", + CMS.getUserMessage(locale, "CMS_PROFILE_CONFIG_REVOKE_DUPKEY_CERT")); + } + */ + if (name.equals(CONFIG_ALLOW_SAME_KEY_RENEWAL)) { + return new Descriptor(IDescriptor.BOOLEAN, null, "false", + CMS.getUserMessage(locale, "CMS_PROFILE_CONFIG_ALLOW_SAME_KEY_RENEWAL")); + } + return null; + } + + public String getDefaultConfig(String name) { + return null; + } + + /** + * Validates the request. The request is not modified + * during the validation. + */ + public void validate(IRequest request, X509CertInfo info) + throws ERejectException { + boolean rejected = false; + int size = 0; + ICertRecordList list; + + /* + mRevokeDupKeyCert = + getConfigBoolean(CONFIG_REVOKE_DUPKEY_CERT); + */ + mAllowSameKeyRenewal = getConfigBoolean(CONFIG_ALLOW_SAME_KEY_RENEWAL); + + try { + CertificateX509Key infokey = (CertificateX509Key) + info.get(X509CertInfo.KEY); + X509Key key = (X509Key) + infokey.get(CertificateX509Key.KEY); + + // check for key uniqueness + byte pub[] = key.getEncoded(); + String pub_s = escapeBinaryData(pub); + String filter = "(" + ICertRecord.ATTR_X509CERT_PUBLIC_KEY_DATA + "=" + pub_s + ")"; + list = + (ICertRecordList) + mCA.getCertificateRepository().findCertRecordsInList(filter, null, 10); + size = list.getSize(); + + } catch (Exception e) { + throw new ERejectException( + CMS.getUserMessage( + getLocale(request), + "CMS_PROFILE_INTERNAL_ERROR", e.toString())); + } + + /* + * It does not matter if the corresponding cert's status + * is valid or not, we don't want a key that was once + * generated before + */ + if (size > 0) { + CMS.debug("UniqueKeyConstraint: found existing cert with duplicate key."); + + /* + The following code revokes the existing certs that have + the same public key as the one submitted for enrollment + request. However, it is not a good idea due to possible + abuse. It is therefore commented out. It is still + however still maintained for possible utilization at later + time + + // if configured to revoke duplicated key + // revoke cert + if (mRevokeDupKeyCert) { + try { + Enumeration e = list.getCertRecords(0, size-1); + while (e != null && e.hasMoreElements()) { + ICertRecord rec = (ICertRecord) e.nextElement(); + X509CertImpl cert = rec.getCertificate(); + + // revoke the cert + BigInteger serialNum = cert.getSerialNumber(); + ICAService service = (ICAService) mCA.getCAService(); + + RevokedCertImpl crlEntry = + formCRLEntry(serialNum, RevocationReason.KEY_COMPROMISE); + service.revokeCert(crlEntry); + CMS.debug("UniqueKeyConstraint: certificate with duplicate publickey revoked successfully"); + } + } catch (Exception ex) { + CMS.debug("UniqueKeyConstraint: error in revoke dupkey cert"); + } + } // revoke dupkey cert turned on + */ + + if (mAllowSameKeyRenewal == true) { + X500Name sjname_in_db = null; + X500Name sjname_in_req = null; + + try { + // get subject of request + CertificateSubjectName subName = + (CertificateSubjectName) info.get(X509CertInfo.SUBJECT); + + if (subName != null) { + + sjname_in_req = + (X500Name) subName.get(CertificateSubjectName.DN_NAME); + CMS.debug("UniqueKeyConstraint: cert request subject DN =" + sjname_in_req.toString()); + Enumeration e = list.getCertRecords(0, size - 1); + while (e != null && e.hasMoreElements()) { + ICertRecord rec = e.nextElement(); + X509CertImpl cert = rec.getCertificate(); + String certDN = + cert.getSubjectDN().toString(); + CMS.debug("UniqueKeyConstraint: cert retrieved from ldap has subject DN =" + certDN); + + sjname_in_db = new X500Name(certDN); + + if (sjname_in_db.equals(sjname_in_req) == false) { + rejected = true; + break; + } else { + rejected = false; + } + } // while + } else { //subName is null + rejected = true; + } + } catch (Exception ex1) { + CMS.debug("UniqueKeyConstraint: error in allowSameKeyRenewal: " + ex1.toString()); + rejected = true; + } // try + + } else { + rejected = true; + }// allowSameKeyRenewal + } // (size > 0) + + if (rejected == true) { + CMS.debug("UniqueKeyConstraint: rejected"); + throw new ERejectException( + CMS.getUserMessage( + getLocale(request), + "CMS_PROFILE_DUPLICATE_KEY")); + } else { + CMS.debug("UniqueKeyConstraint: approved"); + } + } + + /** + * make a CRL entry from a serial number and revocation reason. + * + * @return a RevokedCertImpl that can be entered in a CRL. + * + * protected RevokedCertImpl formCRLEntry( + * BigInteger serialNo, RevocationReason reason) + * throws EBaseException { + * CRLReasonExtension reasonExt = new CRLReasonExtension(reason); + * CRLExtensions crlentryexts = new CRLExtensions(); + * + * try { + * crlentryexts.set(CRLReasonExtension.NAME, reasonExt); + * } catch (IOException e) { + * CMS.debug("CMSGW_ERR_CRL_REASON "+e.toString()); + * + * // throw new ECMSGWException( + * // CMS.getLogMessage("CMSGW_ERROR_SETTING_CRLREASON")); + * + * } + * RevokedCertImpl crlentry = + * new RevokedCertImpl(serialNo, CMS.getCurrentDate(), + * crlentryexts); + * + * return crlentry; + * } + */ + + public String getText(Locale locale) { + String params[] = { + /* + getConfig(CONFIG_REVOKE_DUPKEY_CERT), + */ + }; + + return CMS.getUserMessage(locale, + "CMS_PROFILE_CONSTRAINT_ALLOW_SAME_KEY_RENEWAL_TEXT", params); + } + + public static String escapeBinaryData(byte data[]) { + StringBuffer sb = new StringBuffer(); + + for (int i = 0; i < data.length; i++) { + int v = 0xff & data[i]; + sb.append("\\"); + sb.append((v < 16 ? "0" : "")); + sb.append(Integer.toHexString(v)); + } + return sb.toString(); + } + + public boolean isApplicable(IPolicyDefault def) { + if (def instanceof NoDefault) + return true; + if (def instanceof UniqueKeyConstraint) + return true; + + return false; + } + +} diff --git a/base/common/src/com/netscape/cms/profile/constraint/UniqueSubjectNameConstraint.java b/base/common/src/com/netscape/cms/profile/constraint/UniqueSubjectNameConstraint.java new file mode 100644 index 000000000..7a985b631 --- /dev/null +++ b/base/common/src/com/netscape/cms/profile/constraint/UniqueSubjectNameConstraint.java @@ -0,0 +1,251 @@ +// --- 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.profile.constraint; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Locale; + +import netscape.security.x509.CRLExtensions; +import netscape.security.x509.CRLReasonExtension; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateSubjectName; +import netscape.security.x509.Extension; +import netscape.security.x509.KeyUsageExtension; +import netscape.security.x509.RevocationReason; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authority.IAuthority; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.dbs.certdb.IRevocationInfo; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.profile.IPolicyDefault; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.property.Descriptor; +import com.netscape.certsrv.property.IDescriptor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.profile.def.NoDefault; +import com.netscape.cms.profile.def.SubjectNameDefault; +import com.netscape.cms.profile.def.UserSubjectNameDefault; + +/** + * This class implements the unique subject name constraint. + * It checks if the subject name in the certificate is + * unique in the internal database, ie, no two certificates + * have the same subject name. + * + * @version $Revision$, $Date$ + */ +public class UniqueSubjectNameConstraint extends EnrollConstraint { + + public static final String CONFIG_KEY_USAGE_EXTENSION_CHECKING = + "enableKeyUsageExtensionChecking"; + private boolean mKeyUsageExtensionChecking = true; + + public UniqueSubjectNameConstraint() { + addConfigName(CONFIG_KEY_USAGE_EXTENSION_CHECKING); + } + + public void init(IProfile profile, IConfigStore config) + throws EProfileException { + super.init(profile, config); + } + + public IDescriptor getConfigDescriptor(Locale locale, String name) { + if (name.equals(CONFIG_KEY_USAGE_EXTENSION_CHECKING)) { + return new Descriptor(IDescriptor.BOOLEAN, null, "true", + CMS.getUserMessage(locale, "CMS_PROFILE_CONFIG_KEY_USAGE_EXTENSION_CHECKING")); + } + return null; + } + + public String getDefaultConfig(String name) { + return null; + } + + /** + * Checks if the key extension in the issued certificate + * is the same as the one in the certificate template. + */ + private boolean sameKeyUsageExtension(ICertRecord rec, + X509CertInfo certInfo) { + X509CertImpl impl = rec.getCertificate(); + boolean bits[] = impl.getKeyUsage(); + + CertificateExtensions extensions = null; + + try { + extensions = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + } catch (IOException e) { + } catch (java.security.cert.CertificateException e) { + } + KeyUsageExtension ext = null; + + if (extensions == null) { + if (bits != null) + return false; + } else { + try { + ext = (KeyUsageExtension) extensions.get( + KeyUsageExtension.NAME); + } catch (IOException e) { + // extension isn't there. + } + + if (ext == null) { + if (bits != null) + return false; + } else { + boolean[] InfoBits = ext.getBits(); + + if (InfoBits == null) { + if (bits != null) + return false; + } else { + if (bits == null) + return false; + if (InfoBits.length != bits.length) { + return false; + } + for (int i = 0; i < InfoBits.length; i++) { + if (InfoBits[i] != bits[i]) + return false; + } + } + } + } + return true; + } + + /** + * Validates the request. The request is not modified + * during the validation. + * + * Rules are as follows: + * If the subject name is not unique, then the request will be rejected unless: + * 1. the certificate is expired or expired_revoked + * 2. the certificate is revoked and the revocation reason is not "on hold" + * 3. the keyUsageExtension bits are different and enableKeyUsageExtensionChecking=true (default) + */ + public void validate(IRequest request, X509CertInfo info) + throws ERejectException { + CMS.debug("UniqueSubjectNameConstraint: validate start"); + CertificateSubjectName sn = null; + IAuthority authority = (IAuthority) CMS.getSubsystem("ca"); + + mKeyUsageExtensionChecking = getConfigBoolean(CONFIG_KEY_USAGE_EXTENSION_CHECKING); + ICertificateRepository certdb = null; + if (authority != null && authority instanceof ICertificateAuthority) { + ICertificateAuthority ca = (ICertificateAuthority) authority; + certdb = ca.getCertificateRepository(); + } + + try { + sn = (CertificateSubjectName) info.get(X509CertInfo.SUBJECT); + } catch (Exception e) { + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_SUBJECT_NAME_NOT_FOUND")); + } + + String certsubjectname = null; + if (sn == null) + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_SUBJECT_NAME_NOT_FOUND")); + else { + certsubjectname = sn.toString(); + String filter = "x509Cert.subject=" + certsubjectname; + Enumeration sameSubjRecords = null; + try { + sameSubjRecords = certdb.findCertRecords(filter); + } catch (EBaseException e) { + CMS.debug("UniqueSubjectNameConstraint exception: " + e.toString()); + } + while (sameSubjRecords != null && sameSubjRecords.hasMoreElements()) { + ICertRecord rec = sameSubjRecords.nextElement(); + String status = rec.getStatus(); + + IRevocationInfo revocationInfo = rec.getRevocationInfo(); + RevocationReason reason = null; + + if (revocationInfo != null) { + CRLExtensions crlExts = revocationInfo.getCRLEntryExtensions(); + + if (crlExts != null) { + Enumeration enumx = crlExts.getElements(); + + while (enumx.hasMoreElements()) { + Extension ext = enumx.nextElement(); + + if (ext instanceof CRLReasonExtension) { + reason = ((CRLReasonExtension) ext).getReason(); + } + } + } + } + + if (status.equals(ICertRecord.STATUS_EXPIRED) || status.equals(ICertRecord.STATUS_REVOKED_EXPIRED)) { + continue; + } + + if (status.equals(ICertRecord.STATUS_REVOKED) && reason != null && + (!reason.equals(RevocationReason.CERTIFICATE_HOLD))) { + continue; + } + + if (mKeyUsageExtensionChecking && !sameKeyUsageExtension(rec, info)) { + continue; + } + + throw new ERejectException( + CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_SUBJECT_NAME_NOT_UNIQUE", + certsubjectname)); + } + } + CMS.debug("UniqueSubjectNameConstraint: validate end"); + } + + public String getText(Locale locale) { + String params[] = { + getConfig(CONFIG_KEY_USAGE_EXTENSION_CHECKING) + }; + return CMS.getUserMessage(locale, + "CMS_PROFILE_CONSTRAINT_UNIQUE_SUBJECT_NAME_TEXT", + params); + } + + public boolean isApplicable(IPolicyDefault def) { + if (def instanceof NoDefault) + return true; + if (def instanceof SubjectNameDefault) + return true; + if (def instanceof UserSubjectNameDefault) + return true; + return false; + } +} diff --git a/base/common/src/com/netscape/cms/profile/constraint/ValidityConstraint.java b/base/common/src/com/netscape/cms/profile/constraint/ValidityConstraint.java new file mode 100644 index 000000000..98a7b4f96 --- /dev/null +++ b/base/common/src/com/netscape/cms/profile/constraint/ValidityConstraint.java @@ -0,0 +1,218 @@ +// --- 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.profile.constraint; + +import java.io.IOException; +import java.util.Date; +import java.util.Locale; + +import netscape.security.x509.CertificateValidity; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.profile.IPolicyDefault; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.property.Descriptor; +import com.netscape.certsrv.property.EPropertyException; +import com.netscape.certsrv.property.IDescriptor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.cms.profile.def.CAValidityDefault; +import com.netscape.cms.profile.def.NoDefault; +import com.netscape.cms.profile.def.UserValidityDefault; +import com.netscape.cms.profile.def.ValidityDefault; + +/** + * This class implements the validity constraint. + * It checks if the validity in the certificate + * template satisfies the criteria. + * + * @version $Revision$, $Date$ + */ +public class ValidityConstraint extends EnrollConstraint { + + public static final String CONFIG_RANGE = "range"; + public static final String CONFIG_NOT_BEFORE_GRACE_PERIOD = "notBeforeGracePeriod"; + public static final String CONFIG_CHECK_NOT_BEFORE = "notBeforeCheck"; + public static final String CONFIG_CHECK_NOT_AFTER = "notAfterCheck"; + public final static long SECS_IN_MS = 1000L; + + private Date mDefNotBefore = null; + private Date mDefNotAfter = null; + + public ValidityConstraint() { + super(); + addConfigName(CONFIG_RANGE); + addConfigName(CONFIG_NOT_BEFORE_GRACE_PERIOD); + addConfigName(CONFIG_CHECK_NOT_BEFORE); + addConfigName(CONFIG_CHECK_NOT_AFTER); + } + + public void init(IProfile profile, IConfigStore config) + throws EProfileException { + super.init(profile, config); + } + + public void setConfig(String name, String value) + throws EPropertyException { + if (name.equals(CONFIG_RANGE) || + name.equals(CONFIG_NOT_BEFORE_GRACE_PERIOD)) { + try { + Integer.parseInt(value); + } catch (Exception e) { + throw new EPropertyException(CMS.getUserMessage( + "CMS_INVALID_PROPERTY", name)); + } + } + super.setConfig(name, value); + } + + public IDescriptor getConfigDescriptor(Locale locale, String name) { + if (name.equals(CONFIG_RANGE)) { + return new Descriptor(IDescriptor.INTEGER, null, "365", + CMS.getUserMessage(locale, "CMS_PROFILE_VALIDITY_RANGE")); + } else if (name.equals(CONFIG_NOT_BEFORE_GRACE_PERIOD)) { + return new Descriptor(IDescriptor.INTEGER, null, "0", + CMS.getUserMessage(locale, "CMS_PROFILE_VALIDITY_NOT_BEFORE_GRACE_PERIOD")); + } else if (name.equals(CONFIG_CHECK_NOT_BEFORE)) { + return new Descriptor(IDescriptor.BOOLEAN, null, "false", + CMS.getUserMessage(locale, "CMS_PROFILE_VALIDITY_CHECK_NOT_BEFORE")); + } else if (name.equals(CONFIG_CHECK_NOT_AFTER)) { + return new Descriptor(IDescriptor.BOOLEAN, null, "false", + CMS.getUserMessage(locale, "CMS_PROFILE_VALIDITY_CHECK_NOT_AFTER")); + } + return null; + } + + /** + * Validates the request. The request is not modified + * during the validation. + */ + public void validate(IRequest request, X509CertInfo info) + throws ERejectException { + CertificateValidity v = null; + + try { + v = (CertificateValidity) info.get(X509CertInfo.VALIDITY); + } catch (Exception e) { + throw new ERejectException(CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_VALIDITY_NOT_FOUND")); + } + Date notBefore = null; + + try { + notBefore = (Date) v.get(CertificateValidity.NOT_BEFORE); + } catch (IOException e) { + CMS.debug("ValidityConstraint: not before not found"); + throw new ERejectException(CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_VALIDITY_NOT_FOUND")); + } + Date notAfter = null; + + try { + notAfter = (Date) v.get(CertificateValidity.NOT_AFTER); + } catch (IOException e) { + CMS.debug("ValidityConstraint: not after not found"); + throw new ERejectException(CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_VALIDITY_NOT_FOUND")); + } + + if (notAfter.getTime() < notBefore.getTime()) { + CMS.debug("ValidityConstraint: notAfter (" + notAfter + ") < notBefore (" + notBefore + ")"); + throw new ERejectException(CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_NOT_AFTER_BEFORE_NOT_BEFORE")); + } + + long millisDiff = notAfter.getTime() - notBefore.getTime(); + CMS.debug("ValidityConstraint: millisDiff=" + + millisDiff + " notAfter=" + notAfter.getTime() + " notBefore=" + notBefore.getTime()); + long long_days = (millisDiff / 1000) / 86400; + CMS.debug("ValidityConstraint: long_days: " + long_days); + int days = (int) long_days; + CMS.debug("ValidityConstraint: days: " + days); + + if (days > Integer.parseInt(getConfig(CONFIG_RANGE))) { + throw new ERejectException(CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_VALIDITY_OUT_OF_RANGE", + Integer.toString(days))); + } + + // 613828 + // The validity field shall specify a notBefore value + // that does not precede the current time and a notAfter + // value that does not precede the value specified in + // notBefore (test can be automated; try entering violating + // time values and check result). + String notBeforeCheckStr = getConfig(CONFIG_CHECK_NOT_BEFORE); + boolean notBeforeCheck; + + if (notBeforeCheckStr == null || notBeforeCheckStr.equals("")) { + notBeforeCheckStr = "false"; + } + notBeforeCheck = Boolean.valueOf(notBeforeCheckStr).booleanValue(); + + String notAfterCheckStr = getConfig(CONFIG_CHECK_NOT_AFTER); + boolean notAfterCheck; + + if (notAfterCheckStr == null || notAfterCheckStr.equals("")) { + notAfterCheckStr = "false"; + } + notAfterCheck = Boolean.valueOf(notAfterCheckStr).booleanValue(); + + String notBeforeGracePeriodStr = getConfig(CONFIG_NOT_BEFORE_GRACE_PERIOD); + if (notBeforeGracePeriodStr == null || notBeforeGracePeriodStr.equals("")) { + notBeforeGracePeriodStr = "0"; + } + long notBeforeGracePeriod = Long.parseLong(notBeforeGracePeriodStr) * SECS_IN_MS; + + Date current = CMS.getCurrentDate(); + if (notBeforeCheck) { + if (notBefore.getTime() > (current.getTime() + notBeforeGracePeriod)) { + CMS.debug("ValidityConstraint: notBefore (" + notBefore + ") > current + " + + "gracePeriod (" + new Date(current.getTime() + notBeforeGracePeriod) + ")"); + throw new ERejectException(CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_NOT_BEFORE_AFTER_CURRENT")); + } + } + if (notAfterCheck) { + if (notAfter.getTime() < current.getTime()) { + CMS.debug("ValidityConstraint: notAfter (" + notAfter + ") < current + (" + current + ")"); + throw new ERejectException(CMS.getUserMessage(getLocale(request), + "CMS_PROFILE_NOT_AFTER_BEFORE_CURRENT")); + } + } + } + + public String getText(Locale locale) { + return CMS.getUserMessage(locale, "CMS_PROFILE_CONSTRAINT_VALIDITY_TEXT", getConfig(CONFIG_RANGE)); + } + + public boolean isApplicable(IPolicyDefault def) { + if (def instanceof NoDefault) + return true; + if (def instanceof UserValidityDefault) + return true; + if (def instanceof ValidityDefault) + return true; + if (def instanceof CAValidityDefault) + return true; + return false; + } +} -- cgit