From a4682ceae6774956461edd03b2485bbacea445f4 Mon Sep 17 00:00:00 2001 From: mharmsen Date: Tue, 4 Oct 2011 01:17:41 +0000 Subject: Bugzilla Bug #688225 - (dogtagIPAv2.1) TRACKER: of the Dogtag fixes for freeIPA 2.1 git-svn-id: svn+ssh://svn.fedorahosted.org/svn/pki/tags/IPA_v2_RHEL_6_2_20111003@2252 c9f7a03b-bd48-0410-a16d-cbbf54688b0b --- .../cms/policy/extensions/BasicConstraintsExt.java | 498 +++++++++++++++++++++ 1 file changed, 498 insertions(+) create mode 100644 pki/base/common/src/com/netscape/cms/policy/extensions/BasicConstraintsExt.java (limited to 'pki/base/common/src/com/netscape/cms/policy/extensions/BasicConstraintsExt.java') diff --git a/pki/base/common/src/com/netscape/cms/policy/extensions/BasicConstraintsExt.java b/pki/base/common/src/com/netscape/cms/policy/extensions/BasicConstraintsExt.java new file mode 100644 index 000000000..73a6b58af --- /dev/null +++ b/pki/base/common/src/com/netscape/cms/policy/extensions/BasicConstraintsExt.java @@ -0,0 +1,498 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cms.policy.extensions; + + +import java.util.*; +import java.io.*; +import java.security.cert.*; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.policy.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.ra.*; +import com.netscape.certsrv.authentication.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.authority.*; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.apps.*; +import netscape.security.x509.*; +import netscape.ldap.*; +import com.netscape.cms.policy.APolicyRule; + + +/** + * Basic Constraints policy. + * Adds the Basic constraints extension. + *

+ *

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

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

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