diff --git a/base/ca/shared/conf/registry.cfg b/base/ca/shared/conf/registry.cfg index 08fafde2dfe..fe13ad25334 100644 --- a/base/ca/shared/conf/registry.cfg +++ b/base/ca/shared/conf/registry.cfg @@ -1,5 +1,5 @@ types=profile,defaultPolicy,constraintPolicy,profileInput,profileOutput,profileUpdater -constraintPolicy.ids=noConstraintImpl,subjectNameConstraintImpl,uniqueSubjectNameConstraintImpl,userSubjectNameConstraintImpl,cmcSharedTokenSubjectNameConstraintImpl,cmcUserSignedSubjectNameConstraintImpl,caValidityConstraintImpl,validityConstraintImpl,keyUsageExtConstraintImpl,nsCertTypeExtConstraintImpl,extendedKeyUsageExtConstraintImpl,keyConstraintImpl,basicConstraintsExtConstraintImpl,extensionConstraintImpl,signingAlgConstraintImpl,uniqueKeyConstraintImpl,renewGracePeriodConstraintImpl,authzRealmConstraintImpl,externalProcessConstraintImpl +constraintPolicy.ids=noConstraintImpl,subjectNameConstraintImpl,uniqueSubjectNameConstraintImpl,userSubjectNameConstraintImpl,cmcSharedTokenSubjectNameConstraintImpl,cmcUserSignedSubjectNameConstraintImpl,caValidityConstraintImpl,validityConstraintImpl,keyUsageExtConstraintImpl,nsCertTypeExtConstraintImpl,extendedKeyUsageExtConstraintImpl,keyConstraintImpl,basicConstraintsExtConstraintImpl,extensionConstraintImpl,signingAlgConstraintImpl,uniqueKeyConstraintImpl,renewGracePeriodConstraintImpl,authzRealmConstraintImpl,externalProcessConstraintImpl,p12ExportPasswordConstraintImpl constraintPolicy.signingAlgConstraintImpl.class=com.netscape.cms.profile.constraint.SigningAlgConstraint constraintPolicy.signingAlgConstraintImpl.desc=Signing Algorithm Constraint constraintPolicy.signingAlgConstraintImpl.name=Signing Algorithm Constraint @@ -27,6 +27,9 @@ constraintPolicy.nsCertTypeExtConstraintImpl.name=Netscape Certificate Type Exte constraintPolicy.noConstraintImpl.class=com.netscape.cms.profile.constraint.NoConstraint constraintPolicy.noConstraintImpl.desc=No Constraint constraintPolicy.noConstraintImpl.name=No Constraint +constraintPolicy.p12ExportPasswordConstraintImpl.class=com.netscape.cms.profile.constraint.P12ExportPasswordConstraint +constraintPolicy.p12ExportPasswordConstraintImpl.desc=Generated PKCS12 Constraint +constraintPolicy.p12ExportPasswordConstraintImpl.name=Generated PKCS12 Constraint constraintPolicy.subjectNameConstraintImpl.class=com.netscape.cms.profile.constraint.SubjectNameConstraint constraintPolicy.subjectNameConstraintImpl.desc=Subject Name Constraint constraintPolicy.subjectNameConstraintImpl.name=Subject Name Constraint diff --git a/base/ca/shared/profiles/ca/caServerKeygen_DirUserCert.cfg b/base/ca/shared/profiles/ca/caServerKeygen_DirUserCert.cfg index 6baeeee94ef..589965e6d30 100644 --- a/base/ca/shared/profiles/ca/caServerKeygen_DirUserCert.cfg +++ b/base/ca/shared/profiles/ca/caServerKeygen_DirUserCert.cfg @@ -9,7 +9,7 @@ input.i1.class_id=serverKeygenInputImpl output.list=o1 output.o1.class_id=pkcs12OutputImpl policyset.list=userCertSet -policyset.userCertSet.list=1,10,2,3,4,5,6,7,8,9 +policyset.userCertSet.list=1,10,2,3,4,5,6,7,8,9,11 policyset.userCertSet.1.constraint.class_id=subjectNameConstraintImpl policyset.userCertSet.1.constraint.name=Subject Name Constraint policyset.userCertSet.1.constraint.params.pattern=UID=.* @@ -100,3 +100,12 @@ policyset.userCertSet.9.constraint.params.signingAlgsAllowed=SHA256withRSA,SHA51 policyset.userCertSet.9.default.class_id=signingAlgDefaultImpl policyset.userCertSet.9.default.name=Signing Alg policyset.userCertSet.9.default.params.signingAlg=- +policyset.userCertSet.11.constraint.class_id=p12ExportPasswordConstraintImpl +policyset.userCertSet.11.constraint.name=PKCS12 Password Constraint +policyset.userCertSet.11.constraint.params.password.minSize=20 +policyset.userCertSet.11.constraint.params.password.minCharCategory=2,2,2,2 +policyset.userCertSet.11.constraint.params.password.substringMatch=6 +policyset.userCertSet.11.constraint.params.password.maxRepeatedChar=3 +policyset.userCertSet.11.constraint.params.password.cracklibCheck=false +policyset.userCertSet.11.default.class_id=noDefaultImpl +policyset.userCertSet.11.default.name=No Default diff --git a/base/ca/shared/profiles/ca/caServerKeygen_UserCert.cfg b/base/ca/shared/profiles/ca/caServerKeygen_UserCert.cfg index 567ed8c3c33..c1af882c495 100644 --- a/base/ca/shared/profiles/ca/caServerKeygen_UserCert.cfg +++ b/base/ca/shared/profiles/ca/caServerKeygen_UserCert.cfg @@ -11,7 +11,7 @@ input.i3.class_id=submitterInfoInputImpl output.list=o1 output.o1.class_id=pkcs12OutputImpl policyset.list=userCertSet -policyset.userCertSet.list=1,10,2,3,4,5,6,7,8,9 +policyset.userCertSet.list=1,10,2,3,4,5,6,7,8,9,11 policyset.userCertSet.1.constraint.class_id=subjectNameConstraintImpl policyset.userCertSet.1.constraint.name=Subject Name Constraint policyset.userCertSet.1.constraint.params.pattern=UID=.* @@ -102,3 +102,12 @@ policyset.userCertSet.9.constraint.params.signingAlgsAllowed=SHA256withRSA,SHA51 policyset.userCertSet.9.default.class_id=signingAlgDefaultImpl policyset.userCertSet.9.default.name=Signing Alg policyset.userCertSet.9.default.params.signingAlg=- +policyset.userCertSet.11.constraint.class_id=p12ExportPasswordConstraintImpl +policyset.userCertSet.11.constraint.name=PKCS12 Password Constraint +policyset.userCertSet.11.constraint.params.password.minSize=20 +policyset.userCertSet.11.constraint.params.password.minCharCategory=2,2,2,2 +policyset.userCertSet.11.constraint.params.password.substringMatch=6 +policyset.userCertSet.11.constraint.params.password.maxRepeatedChar=3 +policyset.userCertSet.11.constraint.params.password.cracklibCheck=false +policyset.userCertSet.11.default.class_id=noDefaultImpl +policyset.userCertSet.11.default.name=No Default diff --git a/base/ca/src/main/java/com/netscape/cms/profile/common/CAEnrollProfile.java b/base/ca/src/main/java/com/netscape/cms/profile/common/CAEnrollProfile.java index 92b93b5cf1f..df93c20d4b5 100644 --- a/base/ca/src/main/java/com/netscape/cms/profile/common/CAEnrollProfile.java +++ b/base/ca/src/main/java/com/netscape/cms/profile/common/CAEnrollProfile.java @@ -22,11 +22,21 @@ import java.security.cert.CertificateException; import java.util.Date; import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import org.dogtagpki.server.ca.CAConfig; import org.dogtagpki.server.ca.CAEngine; +import org.dogtagpki.server.ca.CAEngineConfig; +import org.mozilla.jss.CryptoManager; +import org.mozilla.jss.crypto.CryptoToken; +import org.mozilla.jss.crypto.EncryptionAlgorithm; +import org.mozilla.jss.crypto.IVParameterSpec; +import org.mozilla.jss.crypto.KeyGenAlgorithm; +import org.mozilla.jss.crypto.KeyWrapAlgorithm; +import org.mozilla.jss.crypto.SymmetricKey; import org.mozilla.jss.netscape.security.x509.CertificateSubjectName; import org.mozilla.jss.netscape.security.x509.CertificateX509Key; -import org.mozilla.jss.netscape.security.x509.Extension; import org.mozilla.jss.netscape.security.x509.KeyIdentifier; import org.mozilla.jss.netscape.security.x509.PKIXExtensions; import org.mozilla.jss.netscape.security.x509.SubjectKeyIdentifierExtension; @@ -37,10 +47,13 @@ import org.mozilla.jss.pkix.crmf.PKIArchiveOptions; import com.netscape.ca.CAService; +import com.netscape.ca.CertificateAuthority; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.SessionContext; import com.netscape.certsrv.ca.AuthorityID; import com.netscape.certsrv.connector.Connector; +import com.netscape.certsrv.connector.ConnectorConfig; +import com.netscape.certsrv.connector.ConnectorsConfig; import com.netscape.certsrv.logging.AuditFormat; import com.netscape.certsrv.logging.event.SecurityDataArchivalRequestEvent; import com.netscape.certsrv.logging.event.ServerSideKeygenEnrollKeyRetrievalEvent; @@ -65,7 +78,7 @@ */ public class CAEnrollProfile extends EnrollProfile { - public static org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CAEnrollProfile.class); + public static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CAEnrollProfile.class); public CAEnrollProfile() { } @@ -125,7 +138,7 @@ public void execute(Request request) throws EProfileException, ERejectException // if PKI Archive Option present, send this request // to DRM - byte optionsData[] = request.getExtDataInByteArray(Request.REQUEST_ARCHIVE_OPTIONS); + byte[] optionsData = request.getExtDataInByteArray(Request.REQUEST_ARCHIVE_OPTIONS); byte[] transWrappedSessionKey = null; byte[] sessionWrappedPassphrase = null; @@ -135,19 +148,11 @@ public void execute(Request request) throws EProfileException, ERejectException logger.info("CAEnrollProfile: Processing server-side keygen enrollment"); request.setExtData(Request.SSK_STAGE, Request.SSK_STAGE_KEYGEN); - /* - * temporarily remove the items not needed for SSK_STAGE_KEYGEN - * so not to pass them to KRA. - * They will be put back at SSK_STAGE_KEY_RETRIEVE below - */ - transWrappedSessionKey = request.getExtDataInByteArray("serverSideKeygenP12PasswdTransSession"); + Map p12PasswordInfo = processP12Password(request); + transWrappedSessionKey = p12PasswordInfo.get("serverSideKeygenP12PasswdTransSession"); - sessionWrappedPassphrase = request.getExtDataInByteArray("serverSideKeygenP12PasswdEnc"); + sessionWrappedPassphrase = p12PasswordInfo.get("serverSideKeygenP12PasswdEnc"); - request.setExtData("serverSideKeygenP12PasswdTransSession", ""); - request.deleteExtData("serverSideKeygenP12PasswdTransSession"); - request.setExtData("serverSideKeygenP12PasswdEnc", ""); - request.deleteExtData("serverSideKeygenP12PasswdEnc"); try { Connector kraConnector = caService.getKRAConnector(); @@ -342,7 +347,7 @@ public void execute(Request request) throws EProfileException, ERejectException } catch (IOException e) { old_ski = null; } - if (old_ski != null) { + if (old_ski != null) { byte[] old_ski_val = old_ski.getIdentifier(); if (old_ski_val != null) { int old_ski_len = old_ski_val.length; @@ -377,11 +382,7 @@ public void execute(Request request) throws EProfileException, ERejectException logger.debug(method + "did not find SubjectKey_Id"); */ - } catch (IOException e) { - logger.error(method + e.getMessage(), e); - throw new EProfileException(e); - - } catch (CertificateException e) { + } catch (CertificateException | IOException e) { logger.error(method + e.getMessage(), e); throw new EProfileException(e); } catch (Exception e) { @@ -531,4 +532,108 @@ public void execute(Request request) throws EProfileException, ERejectException } } + /** + * Read the p12 password and generate symmetric keys + * + * The password is read from the request and removed after the keys are generated. + * + * @param request + * @return symmetric keys + * @throws EProfileException + */ + private Map processP12Password (Request request) throws EProfileException { + String method = "CAEnrollProfile: processP12Password: "; + Map returnPass = null; + + String p12passwd = request.getExtDataInString("serverSideKeygenP12Passwd"); + + org.mozilla.jss.crypto.X509Certificate transCert = null; + + CAEngine engine = CAEngine.getInstance(); + CertificateAuthority ca = engine.getCA(); + CAConfig caConfig = ca.getConfigStore(); + ConnectorsConfig connectorsConfig = caConfig.getConnectorsConfig(); + ConnectorConfig kraConnectorConfig = connectorsConfig.getConnectorConfig("KRA"); + + try { + CryptoManager cm = CryptoManager.getInstance(); + String transportNickname = kraConnectorConfig.getString("transportCertNickname", "KRA Transport Certificate"); + transCert = cm.findCertByNickname(transportNickname); + } catch (Exception e) { + logger.error(method + "'KRA transport certificate' not found in nssdb; need to be manually setup for Server-Side keygen enrollment"); + throw new EProfileException(CMS.getUserMessage("CMS_MISSING_KRA_TRANSPORT_CERT_IN_CA_NSSDB")); + } + + try + { + // todo: make things configurable in CS.cfg or profile + CryptoToken ct = + CryptoUtil.getCryptoToken(CryptoUtil.INTERNAL_TOKEN_NAME); + + EncryptionAlgorithm encryptAlgorithm = + EncryptionAlgorithm.AES_128_CBC_PAD; + + CAEngineConfig caCfg = engine.getConfig(); + boolean useOAEP = caCfg.getUseOAEPKeyWrap(); + + KeyWrapAlgorithm wrapAlgorithm = KeyWrapAlgorithm.RSA; + if(useOAEP) { + wrapAlgorithm = KeyWrapAlgorithm.RSA_OAEP; + } + + logger.debug(method + "KeyWrapAlgorithm: " + wrapAlgorithm); + + SymmetricKey sessionKey = CryptoUtil.generateKey( + ct, + KeyGenAlgorithm.AES, + 128, + null, + true); + + byte[] iv = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; + byte[] sessionWrappedPassphrase = CryptoUtil.encryptUsingSymmetricKey( + ct, + sessionKey, + p12passwd.getBytes("UTF-8"), + encryptAlgorithm, + new IVParameterSpec(iv)); + + logger.debug(method + "sessionWrappedPassphrase.length=" + sessionWrappedPassphrase.length); + + byte[] transWrappedSessionKey = CryptoUtil.wrapUsingPublicKey( + ct, + transCert.getPublicKey(), + sessionKey, + wrapAlgorithm); + logger.debug(method + " transWrappedSessionKey.length =" +transWrappedSessionKey.length); + + CertificateSubjectName reqSubj = + request.getExtDataInCertSubjectName(Request.REQUEST_SUBJECT_NAME); + String subj = "unknown serverKeyGenUser"; + if (reqSubj != null) { + X500Name xN = reqSubj.getX500Name(); + subj = xN.toString(); + logger.debug(method + "subj = " + subj); + } + // store in request to pass to kra + request.setExtData(Request.SECURITY_DATA_CLIENT_KEY_ID, + subj); + returnPass = new HashMap<>(); + + returnPass.put("serverSideKeygenP12PasswdEnc", + sessionWrappedPassphrase); + returnPass.put("serverSideKeygenP12PasswdTransSession", + transWrappedSessionKey); + + // delete + request.setExtData("serverSideKeygenP12Passwd", ""); + request.deleteExtData("serverSideKeygenP12Passwd"); + } catch(Exception e) { + logger.debug("{}{}", method, e.toString()); + throw new EProfileException(e.getMessage()); + + } + return returnPass; + } + } diff --git a/base/ca/src/main/java/com/netscape/cms/profile/constraint/P12ExportPasswordConstraint.java b/base/ca/src/main/java/com/netscape/cms/profile/constraint/P12ExportPasswordConstraint.java new file mode 100644 index 00000000000..6a7b8986aa1 --- /dev/null +++ b/base/ca/src/main/java/com/netscape/cms/profile/constraint/P12ExportPasswordConstraint.java @@ -0,0 +1,171 @@ +// --- 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) 2025 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cms.profile.constraint; + +import java.util.Locale; + +import org.dogtagpki.server.ca.CAEngine; +import org.mozilla.jss.netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.password.EPasswordCheckException; +import com.netscape.certsrv.profile.ERejectException; +import com.netscape.certsrv.property.EPropertyException; +import com.netscape.certsrv.property.IDescriptor; +import com.netscape.cms.password.PasswordChecker; +import com.netscape.cms.profile.def.NoDefault; +import com.netscape.cms.profile.def.PolicyDefault; +import com.netscape.cmscore.apps.CMS; +import com.netscape.cmscore.request.Request; + +/** + * This class implement a policy constraint for the pkcs12 export password + * + * The policy has several configurations, the are: + * - password.minSize + * - password.minUpperLetter + * - password.minLowerLetter + * - password.minNumber + * - password.minSpecialChar + * - password.substringMatch + * - password.maxRepeatedChar + * - password.cracklibCheck + * + * @author Marco Fargetta {@literal } + */ +public class P12ExportPasswordConstraint extends EnrollConstraint { + + public static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(P12ExportPasswordConstraint.class); + + public static final String CONFIG_PASSWORD_MIN_SIZE = "password.minSize"; + public static final String CONFIG_PASSWORD_MIN_UPPER_LETTER = "password.minUpperLetter"; + public static final String CONFIG_PASSWORD_MIN_LOWER_LETTER = "password.minLowerLetter"; + public static final String CONFIG_PASSWORD_MIN_NUMBER = "password.minNumber"; + public static final String CONFIG_PASSWORD_MIN_SPECIAL_CHAR = "password.minSpecialChar"; + public static final String CONFIG_PASSWORD_SEQUENCE_LENGTH = "password.seqLength"; + public static final String CONFIG_PASSWORD_MAX_REPEATED_CHAR = "password.maxRepeatedChar"; + public static final String CONFIG_PASSWORD_CRACKLIB_CHECK = "password.cracklibCheck"; + + public P12ExportPasswordConstraint() { + super(); + addConfigName(CONFIG_PASSWORD_MIN_SIZE); + addConfigName(CONFIG_PASSWORD_MIN_UPPER_LETTER); + addConfigName(CONFIG_PASSWORD_MIN_LOWER_LETTER); + addConfigName(CONFIG_PASSWORD_MIN_NUMBER); + addConfigName(CONFIG_PASSWORD_MIN_SPECIAL_CHAR); + addConfigName(CONFIG_PASSWORD_SEQUENCE_LENGTH); + addConfigName(CONFIG_PASSWORD_MAX_REPEATED_CHAR); + addConfigName(CONFIG_PASSWORD_CRACKLIB_CHECK); + + } + + @Override + public void setConfig(String name, String value) + throws EPropertyException { + if (name.equals(CONFIG_PASSWORD_MIN_SIZE) || + name.equals(CONFIG_PASSWORD_MIN_UPPER_LETTER) || + name.equals(CONFIG_PASSWORD_MIN_LOWER_LETTER) || + name.equals(CONFIG_PASSWORD_MIN_NUMBER) || + name.equals(CONFIG_PASSWORD_MIN_SPECIAL_CHAR) || + name.equals(CONFIG_PASSWORD_SEQUENCE_LENGTH) || + name.equals(CONFIG_PASSWORD_MAX_REPEATED_CHAR)) { + try { + Integer.parseInt(value); + } catch (Exception e) { + throw new EPropertyException(CMS.getUserMessage( + "CMS_INVALID_PROPERTY", name)); + } + } + super.setConfig(name, value); + } + + @Override + public IDescriptor getConfigDescriptor(Locale locale, String name) { + return null; + } + + @Override + public void validate(Request req, X509CertInfo info) + throws ERejectException { + String method = "P12ExportPasswordConstraint: validate: "; + String password = req.getExtDataInString("serverSideKeygenP12Passwd"); + PasswordChecker pCheck = getChecker(); + + try { + if (!pCheck.isGoodPassword(password)) { + throw new ERejectException(pCheck.getReason(getLocale(req))); + } + } catch (EPasswordCheckException e) { + logger.error("{password rejected because }", method, e.getMessage()); + throw new ERejectException(CMS.getUserMessage(getLocale(req), + "CMS_PROFILE_P12EXPORT_PASSWORD_ERROR", e.getMessage())); + } + } + + @Override + public String getText(Locale locale) { + PasswordChecker pCheck = getChecker(); + String[] params = { + Integer.toString(pCheck.getMinSize()), + Integer.toString(pCheck.getMinUpperLetter()), + Integer.toString(pCheck.getMinLowerLetter()), + Integer.toString(pCheck.getMinNumber()), + Integer.toString(pCheck.getMinPunctuationChar()), + Integer.toString(pCheck.getSeqLength()), + Integer.toString(pCheck.getMaxRepeatedChar()), + Boolean.toString(pCheck.isCracklibCheck()) + }; + return CMS.getUserMessage(locale, "CMS_PROFILE_CONSTRAINT_P12EXPORT_PASSWORD_TEXT", params); + } + + @Override + public boolean isApplicable(PolicyDefault def) { + return (def instanceof NoDefault); + } + + private PasswordChecker getChecker() { + CAEngine engine = CAEngine.getInstance(); + PasswordChecker pCheck = engine.getPasswordChecker(); + + if (!getConfig(CONFIG_PASSWORD_MIN_SIZE).isEmpty()) { + pCheck.setMinSize(Integer.parseInt(getConfig(CONFIG_PASSWORD_MIN_SIZE))); + } + if (!getConfig(CONFIG_PASSWORD_MIN_UPPER_LETTER).isEmpty()) { + pCheck.setMinUpperLetter(Integer.parseInt(getConfig(CONFIG_PASSWORD_MIN_UPPER_LETTER))); + } + if (!getConfig(CONFIG_PASSWORD_MIN_LOWER_LETTER).isEmpty()) { + pCheck.setMinLowerLetter(Integer.parseInt(getConfig(CONFIG_PASSWORD_MIN_LOWER_LETTER))); + } + if (!getConfig(CONFIG_PASSWORD_MIN_NUMBER).isEmpty()) { + pCheck.setMinNumber(Integer.parseInt(getConfig(CONFIG_PASSWORD_MIN_NUMBER))); + } + if (!getConfig(CONFIG_PASSWORD_MIN_SPECIAL_CHAR).isEmpty()) { + pCheck.setMinPunctuationChar(Integer.parseInt(getConfig(CONFIG_PASSWORD_MIN_SPECIAL_CHAR))); + } + if (!getConfig(CONFIG_PASSWORD_SEQUENCE_LENGTH).isEmpty()) { + pCheck.setSeqLength(Integer.parseInt(getConfig(CONFIG_PASSWORD_SEQUENCE_LENGTH))); + } + if (!getConfig(CONFIG_PASSWORD_MAX_REPEATED_CHAR).isEmpty()) { + pCheck.setMaxRepeatedChar(Integer.parseInt(getConfig(CONFIG_PASSWORD_MAX_REPEATED_CHAR))); + } + if (!getConfig(CONFIG_PASSWORD_MAX_REPEATED_CHAR).isEmpty()) { + pCheck.setCracklibCheck(getConfigBoolean(CONFIG_PASSWORD_CRACKLIB_CHECK)); + } + + return pCheck; + } +} diff --git a/base/ca/src/main/java/com/netscape/cms/profile/def/ServerKeygenUserKeyDefault.java b/base/ca/src/main/java/com/netscape/cms/profile/def/ServerKeygenUserKeyDefault.java index 4d865abe947..2c9d0d0e7a5 100644 --- a/base/ca/src/main/java/com/netscape/cms/profile/def/ServerKeygenUserKeyDefault.java +++ b/base/ca/src/main/java/com/netscape/cms/profile/def/ServerKeygenUserKeyDefault.java @@ -23,28 +23,14 @@ import java.util.Locale; import java.util.Vector; -import org.dogtagpki.server.ca.CAConfig; -import org.dogtagpki.server.ca.CAEngine; import org.dogtagpki.server.ca.CAEngineConfig; -import org.mozilla.jss.CryptoManager; -import org.mozilla.jss.crypto.CryptoToken; -import org.mozilla.jss.crypto.EncryptionAlgorithm; -import org.mozilla.jss.crypto.IVParameterSpec; -import org.mozilla.jss.crypto.KeyGenAlgorithm; -import org.mozilla.jss.crypto.KeyWrapAlgorithm; -import org.mozilla.jss.crypto.SymmetricKey; import org.mozilla.jss.netscape.security.provider.DSAPublicKey; import org.mozilla.jss.netscape.security.provider.RSAPublicKey; import org.mozilla.jss.netscape.security.x509.AlgorithmId; -import org.mozilla.jss.netscape.security.x509.CertificateSubjectName; import org.mozilla.jss.netscape.security.x509.CertificateX509Key; -import org.mozilla.jss.netscape.security.x509.X500Name; import org.mozilla.jss.netscape.security.x509.X509CertInfo; import org.mozilla.jss.netscape.security.x509.X509Key; -import com.netscape.ca.CertificateAuthority; -import com.netscape.certsrv.connector.ConnectorConfig; -import com.netscape.certsrv.connector.ConnectorsConfig; import com.netscape.certsrv.profile.EProfileException; import com.netscape.certsrv.property.Descriptor; import com.netscape.certsrv.property.EPropertyException; @@ -63,7 +49,7 @@ */ public class ServerKeygenUserKeyDefault extends EnrollDefault { - public static org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(SubjectNameDefault.class); + public static org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ServerKeygenUserKeyDefault.class); public static final String CONFIG_ENABLE_ARCHIVAL = "enableArchival"; public static final String CONFIG_LEN = "keySize"; @@ -228,7 +214,7 @@ public String getValue(String name, Locale locale, @Override public String getText(Locale locale) { - String params[] = { + String[] params = { getConfig(CONFIG_TYPE), getConfig(CONFIG_LEN) }; @@ -283,107 +269,7 @@ public void populate(Request request, X509CertInfo info) logger.debug(method + "p12passwd not found"); throw new EPropertyException(CMS.getUserMessage("CMS_PASSWORD_EMPTY_PASSWORD")); } - - // Encrypt the password before putting it back in - String transportCertStr = null; - CryptoManager cm = CryptoManager.getInstance(); - org.mozilla.jss.crypto.X509Certificate transCert = null; - - CAEngine engine = CAEngine.getInstance(); - CertificateAuthority ca = engine.getCA(); - CAConfig caConfig = ca.getConfigStore(); - ConnectorsConfig connectorsConfig = caConfig.getConnectorsConfig(); - ConnectorConfig kraConnectorConfig = connectorsConfig.getConnectorConfig("KRA"); - - try { - String transportNickname = kraConnectorConfig.getString("transportCertNickname", "KRA Transport Certificate"); - transCert = cm.findCertByNickname(transportNickname); - } catch (Exception e) { - logger.debug(method + "'KRA transport certificate' not found in nssdb; need to be manually setup for Server-Side keygen enrollment"); - throw new EPropertyException(CMS.getUserMessage("CMS_MISSING_KRA_TRANSPORT_CERT_IN_CA_NSSDB")); - - /* future; cert nickname can't be controlled yet at import in jss - logger.debug(method + "KRA transport certificate not found in nssdb; getting from CS.cfg"); - transportCertStr = connectorsConfig.getString("KRA.transportCert", ""); - logger.debug(method + "transportCert found in CS.cfg: " + transportCertStr); - - byte[] transportCertB = Utils.base64decode(transportCertStr); - logger.debug(method + "transportCertB.length=" + transportCertB.length); - // hmmm, can't yet control the nickname - transCert = cm.importCACertPackage(transportCertB); - logger.debug(method + "KRA transport certificate imported"); - */ - } - - { - // todo: make things configurable in CS.cfg or profile - CryptoToken ct = - CryptoUtil.getCryptoToken(CryptoUtil.INTERNAL_TOKEN_NAME); - if (ct == null) - logger.debug(method + "crypto token null"); - - EncryptionAlgorithm encryptAlgorithm = - EncryptionAlgorithm.AES_128_CBC_PAD; - - CAEngineConfig caCfg = engine.getConfig(); - boolean useOAEP = caCfg.getUseOAEPKeyWrap(); - - KeyWrapAlgorithm wrapAlgorithm = KeyWrapAlgorithm.RSA; - if(useOAEP == true) { - wrapAlgorithm = KeyWrapAlgorithm.RSA_OAEP; - } - - logger.debug(method + "KeyWrapAlgorithm: " + wrapAlgorithm); - - SymmetricKey sessionKey = CryptoUtil.generateKey( - ct, - KeyGenAlgorithm.AES, - 128, - null, - true); - - byte[] iv = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; - byte[] sessionWrappedPassphrase = CryptoUtil.encryptUsingSymmetricKey( - ct, - sessionKey, - p12passwd.getBytes("UTF-8"), - encryptAlgorithm, - new IVParameterSpec(iv)); - - logger.debug(method + "sessionWrappedPassphrase.length=" + sessionWrappedPassphrase.length); - - byte[] transWrappedSessionKey = CryptoUtil.wrapUsingPublicKey( - ct, - transCert.getPublicKey(), - sessionKey, - wrapAlgorithm); - logger.debug(method + " transWrappedSessionKey.length =" +transWrappedSessionKey.length); - - CertificateSubjectName reqSubj = - request.getExtDataInCertSubjectName(Request.REQUEST_SUBJECT_NAME); - String subj = "unknown serverKeyGenUser"; - if (reqSubj != null) { - X500Name xN = reqSubj.getX500Name(); - subj = xN.toString(); - logger.debug(method + "subj = " + subj); - } - // store in request to pass to kra - request.setExtData(Request.SECURITY_DATA_CLIENT_KEY_ID, - subj); - - request.setExtData("serverSideKeygenP12PasswdEnc", - sessionWrappedPassphrase); - request.setExtData("serverSideKeygenP12PasswdTransSession", - transWrappedSessionKey); - - // delete - request.setExtData("serverSideKeygenP12Passwd", ""); - request.deleteExtData("serverSideKeygenP12Passwd"); - } - - // request.setExtData("isServerSideKeygen", "true"); - CryptoToken token = cm.getInternalKeyStorageToken(); String keyTypeStr = request.getExtDataInString("keyType"); String keyType = "RSA"; diff --git a/base/server/src/main/java/com/netscape/cms/password/PasswordChecker.java b/base/server/src/main/java/com/netscape/cms/password/PasswordChecker.java index dd1a30bb9a5..a8e88f2baf6 100644 --- a/base/server/src/main/java/com/netscape/cms/password/PasswordChecker.java +++ b/base/server/src/main/java/com/netscape/cms/password/PasswordChecker.java @@ -17,6 +17,13 @@ // --- END COPYRIGHT BLOCK --- package com.netscape.cms.password; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import com.netscape.certsrv.password.EPasswordCheckException; import com.netscape.cmscore.apps.CMS; @@ -27,14 +34,126 @@ */ public class PasswordChecker { - public static final int MIN_LEN = 8; + public enum PasswordQuality { + CMS_PASSWORD_GOOD, + CMS_PASSWORD_EMPTY_PASSWORD, + CMS_PASSWORD_INVALID_LEN, + CMS_PASSWORD_MISSING_UPPER_CASE, + CMS_PASSWORD_MISSING_LOWER_CASE, + CMS_PASSWORD_MISSING_NUMERIC, + CMS_PASSWORD_MISSING_PUNCTUATION, + CMS_PASSWORD_SEQUENCE, + CMS_PASSWORD_REPEATED_CHAR, + CMS_PASSWORD_CRACKLIB_FAILS + } + private int minSize = 8; + private int minUpperLetter = 0; + private int minLowerLetter = 0; + private int minNumber = 0; + private int minPunctuationChar = 0; + private int seqLength = 0; + private int maxRepeatedChar = 0; + private boolean cracklibCheck = false; + private PasswordQuality quality; /** * Default constructor. */ public PasswordChecker() { } + public PasswordChecker(int minSize, int minUpperLetter, int minLowerLetter, int minNumber, int minPunctuationChar, + int seqLength, int maxRepeatedChar, boolean cracklibCheck) { + this.minSize = minSize; + this.minUpperLetter = minUpperLetter; + this.minLowerLetter = minLowerLetter; + this.minNumber = minNumber; + this.minPunctuationChar = minPunctuationChar; + this.seqLength = seqLength; + this.maxRepeatedChar = maxRepeatedChar; + this.cracklibCheck = cracklibCheck; + } + + private PasswordQuality checkPassword(String password) throws EPasswordCheckException { + if (password == null || password.length() == 0) { + return PasswordQuality.CMS_PASSWORD_EMPTY_PASSWORD; + } + + if (password.length() < minSize) { + return PasswordQuality.CMS_PASSWORD_INVALID_LEN; + } + + if (minUpperLetter > 0 && countLetters(password, "\\p{Upper}") < minUpperLetter) { + return PasswordQuality.CMS_PASSWORD_MISSING_UPPER_CASE; + } + if (minLowerLetter > 0 && countLetters(password, "\\p{Lower}") < minLowerLetter) { + return PasswordQuality.CMS_PASSWORD_MISSING_LOWER_CASE; + } + if (minNumber > 0 && countLetters(password, "\\d") < minNumber) { + return PasswordQuality.CMS_PASSWORD_MISSING_NUMERIC; + } + if (minPunctuationChar > 0 && countLetters(password, "\\p{Punct}") < minPunctuationChar) { + return PasswordQuality.CMS_PASSWORD_MISSING_PUNCTUATION; + } + + + if (seqLength > 0) { + for (int i = 0; i< password.length() - (seqLength * 2); i++) { + String seq = password.substring(i, i + seqLength); + String invSeq = new StringBuilder(seq).reverse().toString(); + if(password.indexOf(seq, i + seqLength) > 0 || password.indexOf(invSeq, i + seqLength) > 0){ + return PasswordQuality.CMS_PASSWORD_SEQUENCE; + } + } + } + + if (maxRepeatedChar > 0) { + int mostRepeatedChar = 0; + char last = 0; + for (char c: password.toCharArray()) { + if (c == last) { + mostRepeatedChar ++; + if (maxRepeatedChar < mostRepeatedChar) { + return PasswordQuality.CMS_PASSWORD_REPEATED_CHAR; + } + } else { + mostRepeatedChar = 1; + last = c; + } + } + } + + if (cracklibCheck) { + try { + Process crack = new ProcessBuilder("/usr/sbin/cracklib-check").start(); + BufferedWriter crackIn = crack.outputWriter(); + BufferedReader crackOut = crack.inputReader(); + crackIn.write(password); + crackIn.close(); + + String crackResult = crackOut.readLine().substring(password.length() + 2); + if (!crackResult.equals("OK")) { + return PasswordQuality.CMS_PASSWORD_CRACKLIB_FAILS; + } + + } catch (IOException e) { + throw new EPasswordCheckException("Impossible check password with cracklib.", e); + } + + } + return PasswordQuality.CMS_PASSWORD_GOOD; + } + + private int countLetters(String password, String pattern) { + int count = 0; + Pattern patt = Pattern.compile(pattern); + Matcher matcher = patt.matcher(password); + while (matcher.find()) { + count++; + } + return count; + } + /** * Returns true if the given password meets the quality requirement; * otherwise returns false. @@ -42,29 +161,111 @@ public PasswordChecker() { * @param pwd The given password being checked. * @return true if the password meets the quality requirement; otherwise * returns false. + * @throws EPasswordCheckException If there is a configuration problem with the password checker + */ + public boolean isGoodPassword(String pwd) throws EPasswordCheckException { + quality = checkPassword(pwd); + return quality == PasswordQuality.CMS_PASSWORD_GOOD; + } + + /** + * Returns a reason if the password doesn't meet the quality requirement. + * + * @return string as a reason if the password quality requirement is not met. */ - public boolean isGoodPassword(String pwd) { - return pwd != null && pwd.length() >= MIN_LEN; + public String getReason() { + return getReason(null); } /** * Returns a reason if the password doesn't meet the quality requirement. * - * @param pwd the given password + * @param loc * @return string as a reason if the password quality requirement is not met. */ - public String getReason(String pwd) { - if (pwd == null || pwd.length() == 0) { - EPasswordCheckException e = new EPasswordCheckException( - CMS.getUserMessage("CMS_PASSWORD_EMPTY_PASSWORD")); + public String getReason(Locale loc) { + return switch (quality) { + case CMS_PASSWORD_GOOD -> null; + case CMS_PASSWORD_INVALID_LEN -> new EPasswordCheckException( + CMS.getUserMessage(loc,"CMS_PASSWORD_INVALID_LEN", "" + minSize)).toString(); + case CMS_PASSWORD_MISSING_UPPER_CASE -> new EPasswordCheckException( + CMS.getUserMessage(loc,"CMS_PASSWORD_MISSING_UPPER_CASE", "" + minUpperLetter)).toString(); + case CMS_PASSWORD_MISSING_LOWER_CASE -> new EPasswordCheckException( + CMS.getUserMessage(loc,"CMS_PASSWORD_MISSING_LOWER_CASE", "" + minLowerLetter)).toString(); + case CMS_PASSWORD_MISSING_NUMERIC -> new EPasswordCheckException( + CMS.getUserMessage(loc,"CMS_PASSWORD_MISSING_NUMERIC", "" + minNumber)).toString(); + case CMS_PASSWORD_MISSING_PUNCTUATION -> new EPasswordCheckException( + CMS.getUserMessage(loc,"CMS_PASSWORD_MISSING_PUNCTUATION", "" + minPunctuationChar)).toString(); + case CMS_PASSWORD_REPEATED_CHAR -> new EPasswordCheckException( + CMS.getUserMessage(loc,"CMS_PASSWORD_REPEATED_CHAR", "" + maxRepeatedChar)).toString(); + default -> new EPasswordCheckException( + CMS.getUserMessage(loc, quality.name())).toString(); + }; + } - return e.toString(); - } else if (pwd.length() < MIN_LEN) { - EPasswordCheckException e = new EPasswordCheckException( - CMS.getUserMessage("CMS_PASSWORD_INVALID_LEN", "" + MIN_LEN)); + public int getMinSize() { + return minSize; + } - return e.toString(); - } - return null; + public void setMinSize(int minSize) { + this.minSize = minSize; + } + + public int getMinUpperLetter() { + return minUpperLetter; + } + + public void setMinUpperLetter(int minUpperLetter) { + this.minUpperLetter = minUpperLetter; + } + + public int getMinLowerLetter() { + return minLowerLetter; + } + + public void setMinLowerLetter(int minLowerLetter) { + this.minLowerLetter = minLowerLetter; + } + + public int getMinNumber() { + return minNumber; + } + + public void setMinNumber(int minNumber) { + this.minNumber = minNumber; + } + + public int getMinPunctuationChar() { + return minPunctuationChar; } + + public void setMinPunctuationChar(int minPunctuationChar) { + this.minPunctuationChar = minPunctuationChar; + } + + public int getSeqLength() { + return seqLength; + } + + public void setSeqLength(int seqLength) { + this.seqLength = seqLength; + } + + public int getMaxRepeatedChar() { + return maxRepeatedChar; + } + + public void setMaxRepeatedChar(int maxRepeatedChar) { + this.maxRepeatedChar = maxRepeatedChar; + } + + public boolean isCracklibCheck() { + return cracklibCheck; + } + + public void setCracklibCheck(boolean cracklibCheck) { + this.cracklibCheck = cracklibCheck; + } + + } diff --git a/base/server/src/main/java/com/netscape/cms/servlet/admin/UsrGrpAdminServlet.java b/base/server/src/main/java/com/netscape/cms/servlet/admin/UsrGrpAdminServlet.java index 7e72fa35afd..67d10b24f31 100644 --- a/base/server/src/main/java/com/netscape/cms/servlet/admin/UsrGrpAdminServlet.java +++ b/base/server/src/main/java/com/netscape/cms/servlet/admin/UsrGrpAdminServlet.java @@ -676,7 +676,7 @@ private synchronized void addUser(HttpServletRequest req, ILogger.FAILURE, auditParams(req))); - throw new EUsrGrpException(passwdCheck.getReason(pword)); + throw new EUsrGrpException(passwdCheck.getReason(req.getLocale())); } user.setPassword(pword); @@ -1808,7 +1808,7 @@ private synchronized void modifyUser(HttpServletRequest req, ILogger.FAILURE, auditParams(req))); - throw new EUsrGrpException(passwdCheck.getReason(pword)); + throw new EUsrGrpException(passwdCheck.getReason(req.getLocale())); } user.setPassword(pword); diff --git a/base/server/src/main/java/com/netscape/cmscore/apps/CMSEngine.java b/base/server/src/main/java/com/netscape/cmscore/apps/CMSEngine.java index 3417ec38a98..d0430dae4aa 100644 --- a/base/server/src/main/java/com/netscape/cmscore/apps/CMSEngine.java +++ b/base/server/src/main/java/com/netscape/cmscore/apps/CMSEngine.java @@ -1417,6 +1417,14 @@ public PasswordChecker getPasswordChecker() { String className = mConfig.getString("passwordCheckerClass", "com.netscape.cms.password.PasswordChecker"); PasswordChecker check = (PasswordChecker) Class.forName(className).getDeclaredConstructor().newInstance(); + check.setMinSize(mConfig.getInteger("passwordChecker.minSize", 8)); + check.setMinUpperLetter(mConfig.getInteger("passwordChecker.minUpperLetter", 0)); + check.setMinLowerLetter(mConfig.getInteger("passwordChecker.minLowerLetter", 0)); + check.setMinNumber(mConfig.getInteger("passwordChecker.minNumber", 0)); + check.setMinPunctuationChar(mConfig.getInteger("passwordChecker.minSpecialChar", 0)); + check.setSeqLength(mConfig.getInteger("passwordChecker.seqLength", 0)); + check.setMaxRepeatedChar(mConfig.getInteger("passwordChecker.maxRepeatedChar", 0)); + check.setCracklibCheck(mConfig.getBoolean("passwordChecker.cracklibCheck", false)); return check; } catch (Exception e) { diff --git a/base/server/src/main/java/org/dogtagpki/server/rest/base/UserServletBase.java b/base/server/src/main/java/org/dogtagpki/server/rest/base/UserServletBase.java index ca1ad0c9b98..1b5678a017e 100644 --- a/base/server/src/main/java/org/dogtagpki/server/rest/base/UserServletBase.java +++ b/base/server/src/main/java/org/dogtagpki/server/rest/base/UserServletBase.java @@ -433,7 +433,7 @@ public UserData addUser(UserData userData, Locale loc) { PasswordChecker passwdCheck = engine.getPasswordChecker(); if (!passwdCheck.isGoodPassword(pword)) { - throw new EUsrGrpException(passwdCheck.getReason(pword)); + throw new EUsrGrpException(passwdCheck.getReason(loc)); } user.setPassword(pword); @@ -536,7 +536,7 @@ public UserData modifyUser(String userID, UserData userData, Locale loc) { PasswordChecker passwdCheck = engine.getPasswordChecker(); if (!passwdCheck.isGoodPassword(pword)) { - throw new EUsrGrpException(passwdCheck.getReason(pword)); + throw new EUsrGrpException(passwdCheck.getReason(loc)); } user.setPassword(pword); diff --git a/base/server/src/main/java/org/dogtagpki/server/rest/v1/UserService.java b/base/server/src/main/java/org/dogtagpki/server/rest/v1/UserService.java index 713baba3d07..100fd9fb2fa 100644 --- a/base/server/src/main/java/org/dogtagpki/server/rest/v1/UserService.java +++ b/base/server/src/main/java/org/dogtagpki/server/rest/v1/UserService.java @@ -313,7 +313,7 @@ public Response addUser(UserData userData) { PasswordChecker passwdCheck = engine.getPasswordChecker(); if (!passwdCheck.isGoodPassword(pword)) { - throw new EUsrGrpException(passwdCheck.getReason(pword)); + throw new EUsrGrpException(passwdCheck.getReason()); } user.setPassword(pword); @@ -440,7 +440,7 @@ public Response modifyUser(String userID, UserData userData) { PasswordChecker passwdCheck = engine.getPasswordChecker(); if (!passwdCheck.isGoodPassword(pword)) { - throw new EUsrGrpException(passwdCheck.getReason(pword)); + throw new EUsrGrpException(passwdCheck.getReason()); } user.setPassword(pword); @@ -826,7 +826,7 @@ public Response addUserCert(String userID, UserCertData userCertData) { } if (leafCert instanceof PK11Cert) { - ((PK11Cert) leafCert).setSSLTrust( + leafCert.setSSLTrust( PK11Cert.VALID_CA | PK11Cert.TRUSTED_CA | PK11Cert.TRUSTED_CLIENT_CA); diff --git a/base/server/src/main/resources/UserMessages.properties b/base/server/src/main/resources/UserMessages.properties index 3b445bebee7..1f7f747de8a 100644 --- a/base/server/src/main/resources/UserMessages.properties +++ b/base/server/src/main/resources/UserMessages.properties @@ -576,9 +576,16 @@ CMS_PASSWORD_EMPTY_PASSWORD=The password is empty CMS_PASSWORD_INVALID_LEN=The password must be at least {0} characters CMS_PASSWORD_INVALID_LEN_1=The password must be at least {0} characters CMS_PASSWORD_NON_ALPHANUMERIC=The password contains non-alphanumeric characters +CMS_PASSWORD_MISSING_PUNCTUATION=The password requires at least {0} punctuation symbol(s) +CMS_PASSWORD_MISSING_NUMERIC=The password requires at least {0} numeric digit(s), excluding digits in the final position CMS_PASSWORD_MISSING_NUMERIC_1=The password requires at least {0} numeric digit(s) +CMS_PASSWORD_MISSING_UPPER_CASE=The password requires at least {0} upper case letter(s), excluding capitals in the initial position CMS_PASSWORD_MISSING_UPPER_CASE_1=The password requires at least {0} upper case letter(s) +CMS_PASSWORD_MISSING_LOWER_CASE=The password requires at least {0} lower case letter(s) CMS_PASSWORD_MISSING_LOWER_CASE_1=The password requires at least {0} lower case letter(s) +CMS_PASSWORD_SEQUENCE=The password cannot have repeated sequences (check also inverted). +CMS_PASSWORD_REPEATED_CHAR=The password cannot contain the same character more then {0} times. +CMS_PASSWORD_CRACKLIB_FAILS=The password did not pass cracklib test. ####################################################### # Policy # @@ -966,6 +973,8 @@ CMS_PROFILE_CONSTRAINT_VALIDITY_TEXT=This constraint rejects the validity that i CMS_PROFILE_CONSTRAINT_RENEWAL_GRACE_PERIOD_TEXT=This constraint rejects the renewal requests that are outside of the grace period {0} CMS_PROFILE_CONSTRAINT_VALIDITY_RENEWAL_TEXT=This constraint rejects the validity that is not between {0} days. If renewal, grace period is {1} days before and {2} days after the expiration date of the original certificate. CMS_PROFILE_CONSTRAINT_REALM_TEXT=This constraint accepts only specified authorization realms. +CMS_PROFILE_CONSTRAINT_P12EXPORT_PASSWORD_TEXT=This constraint accept export password with minimum size {0}, minimum number of characters upper case {1}, minimum number of characters lower case {2}, minimum number of digits {3}, minimum number of punctuation {4} (these excluding initial capital and final digits) no repeated substrings of size {5}, no more {6} repeated character and verified with cracklib {7}. +CMS_PROFILE_P12EXPORT_PASSWORD_ERROR=PKCS12 password not accepted: {0} CMS_PROFILE_DEF_SIA_TEXT=This default populates a Subject Info Access Extension (1.3.6.1.5.5.7.1.11) to the request. The default values are Criticality={0}, {1} CMS_PROFILE_DEF_AIA_TEXT=This default populates a Authority Info Access Extension (1.3.6.1.5.5.7.1.1) to the request. The default values are Criticality={0}, {1} diff --git a/docs/changes/v11.6.0/Server-Changes.adoc b/docs/changes/v11.6.0/Server-Changes.adoc index be69889f0d7..a347180cd76 100644 --- a/docs/changes/v11.6.0/Server-Changes.adoc +++ b/docs/changes/v11.6.0/Server-Changes.adoc @@ -40,3 +40,22 @@ A new `pki_authdb_url` parameter has been added for `pkispawn` to replace the fo * `pki_authdb_hostname` * `pki_authdb_port` * `pki_authdb_secure_conn` + +== Implement new policy constraint for p12 password == + +A new policy constraint is defined to enforce the password quality: *p12ExportPasswordConstraintImpl*. The constraint allows to check: + +* `password.minSize` - the minimum size for the password; +* `password.minUpperLetter` - the minimum number of capital letters; +* `password.minLowerLetter` - the minimum number of lower letters; +* `password.minNumber` - the minimum number of digits; +* `password.minSpecialChar` - the minimum number of punctuation characters; +* `password.seqLength` - the size of substring sequence which cannot be repeated; +* `password.maxRepeatedChar` - maximum number of repeating for each character; +* `password.cracklibCheck` - a boolean to request an additional check with *cracklib* (it has to be installed if not present). + +The same options can be configured in the `CS.cfg` replacing +`password.*` with `passwordChecker.*`. The configuration in `CS.cfg` +are used for all the passwords but each profile can overwrite to allow +stronger or weaker passwords. +