From c95cff5899e2975b16db61b811b626742e5e7114 Mon Sep 17 00:00:00 2001 From: Christina Fu Date: Mon, 1 May 2017 17:48:33 -0700 Subject: [PATCH 01/10] Bug 1447145 - CMC: cmc.popLinkWitnessRequired=false would cause error This patch would fix the issue. It also adds the CMCUserSignedAuth authentication instance that was missed in the CS.cfg --- base/ca/shared/conf/CS.cfg | 1 + .../cms/src/com/netscape/cms/profile/common/EnrollProfile.java | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/base/ca/shared/conf/CS.cfg b/base/ca/shared/conf/CS.cfg index 078abee..3eb5b1b 100644 --- a/base/ca/shared/conf/CS.cfg +++ b/base/ca/shared/conf/CS.cfg @@ -180,6 +180,7 @@ auths.impl.SessionAuthentication.class=com.netscape.cms.authentication.SessionAu auths.instance.TokenAuth.pluginName=TokenAuth auths.instance.AgentCertAuth.agentGroup=Certificate Manager Agents auths.instance.AgentCertAuth.pluginName=AgentCertAuth +auths.instance.CMCUserSignedAuth.pluginName=CMCUserSignedAuth auths.instance.raCertAuth.agentGroup=Registration Manager Agents auths.instance.raCertAuth.pluginName=AgentCertAuth auths.instance.flatFileAuth.pluginName=FlatFileAuth diff --git a/base/server/cms/src/com/netscape/cms/profile/common/EnrollProfile.java b/base/server/cms/src/com/netscape/cms/profile/common/EnrollProfile.java index 57f07d1..7d52fc8 100644 --- a/base/server/cms/src/com/netscape/cms/profile/common/EnrollProfile.java +++ b/base/server/cms/src/com/netscape/cms/profile/common/EnrollProfile.java @@ -885,10 +885,7 @@ public abstract class EnrollProfile extends BasicProfile } int nummsgs = reqSeq.size(); - if (!popLinkWitnessRequired) { - CMS.debug(method + "popLinkWitnessRequired false, skip check"); - } else if (nummsgs > 0) { - CMS.debug(method + "cmc.popLinkWitnessRequired is true"); + if (nummsgs > 0) { CMS.debug(method + "nummsgs =" + nummsgs); msgs = new TaggedRequest[reqSeq.size()]; SEQUENCE bpids = new SEQUENCE(); @@ -896,7 +893,8 @@ public abstract class EnrollProfile extends BasicProfile boolean valid = true; for (int i = 0; i < nummsgs; i++) { msgs[i] = (TaggedRequest) reqSeq.elementAt(i); - if (!context.containsKey("POPLinkWitnessV2") && + if (popLinkWitnessRequired && + !context.containsKey("POPLinkWitnessV2") && !context.containsKey("POPLinkWitness")) { CMS.debug(method + "popLinkWitness(V2) required"); if (randomSeed == null) { -- 1.8.3.1 From 220e35d2b5610cb051831b990451b3b3ff53604e Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Tue, 2 May 2017 21:44:36 +1000 Subject: [PATCH 02/10] CAInfoService: retrieve info from KRA The CAInfoService returns CA configuration info, including KRA-related values the CA clients may need to know (e.g. for generating a CRMF cert request that will cause keys to be archived in KRA). Currently that information is statically configured and does not respect the actual configuration of the KRA. Update the service to retrieve info from the KRA, which is queried according to the KRA Connector configuration. After the KRA has been successfully contacted, the recorded KRA-related settings are regarded as authoritative. The KRA is contacted ONLY if the current info is NOT authoritative, otherwise the currently recorded values are used. This means that any change to relevant KRA configuration (which should occur seldom if ever) necessitates restart of the CA subsystem. If this is unsuccessful (e.g. if the KRA is down or the connector is misconfigured) we use the default values, which may be incorrect. Fixes: https://pagure.io/dogtagpki/issue/2665 Change-Id: I30a37c42ef9327471e8cce8a171f79f388fec746 --- .../org/dogtagpki/server/rest/CAInfoService.java | 143 ++++++++++++++++++--- 1 file changed, 126 insertions(+), 17 deletions(-) diff --git a/base/server/cms/src/org/dogtagpki/server/rest/CAInfoService.java b/base/server/cms/src/org/dogtagpki/server/rest/CAInfoService.java index f4724a6..398f499 100644 --- a/base/server/cms/src/org/dogtagpki/server/rest/CAInfoService.java +++ b/base/server/cms/src/org/dogtagpki/server/rest/CAInfoService.java @@ -18,26 +18,63 @@ package org.dogtagpki.server.rest; +import java.net.MalformedURLException; +import java.net.URISyntaxException; + import javax.servlet.http.HttpSession; import javax.ws.rs.core.Response; import org.dogtagpki.common.CAInfo; import org.dogtagpki.common.CAInfoResource; +import org.dogtagpki.common.KRAInfo; +import org.dogtagpki.common.KRAInfoClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.PKIException; +import com.netscape.certsrv.client.ClientConfig; +import com.netscape.certsrv.client.PKIClient; +import com.netscape.certsrv.system.KRAConnectorInfo; +import com.netscape.cms.servlet.admin.KRAConnectorProcessor; import com.netscape.cms.servlet.base.PKIService; /** * @author Ade Lee + * + * This class returns CA info, including KRA-related values the CA + * clients may need to know (e.g. for generating a CRMF cert request + * that will cause keys to be archived in KRA). + * + * The KRA-related info is read from the KRAInfoService, which is + * queried according to the KRA Connector configuration. After + * the KRAInfoService has been successfully contacted, the recorded + * KRA-related settings are regarded as authoritative. + * + * The KRA is contacted ONLY if the current info is NOT + * authoritative, otherwise the currently recorded values are used. + * This means that any change to relevant KRA configuration (which + * should occur seldom if ever) necessitates restart of the CA + * subsystem. + * + * If this is unsuccessful (e.g. if the KRA is down or the + * connector is misconfigured) we use the default values, which + * may be incorrect. */ public class CAInfoService extends PKIService implements CAInfoResource { private static Logger logger = LoggerFactory.getLogger(InfoService.class); + // is the current KRA-related info authoritative? + private static boolean kraInfoAuthoritative = false; + + // KRA-related fields (the initial values are only used if we + // did not yet receive authoritative info from KRA) + private static String archivalMechanism = KRAInfoService.KEYWRAP_MECHANISM; + private static String wrappingKeySet = "0"; + @Override public Response getInfo() throws Exception { @@ -45,30 +82,102 @@ public class CAInfoService extends PKIService implements CAInfoResource { logger.debug("CAInfoService.getInfo(): session: " + session.getId()); CAInfo info = new CAInfo(); - String archivalMechanism = getArchivalMechanism(); - - if (archivalMechanism != null) - info.setArchivalMechanism(getArchivalMechanism()); - info.setWrappingKeySet(getWrappingKeySet()); + addKRAInfo(info); return createOKResponse(info); } - String getArchivalMechanism() throws EBaseException { - IConfigStore cs = CMS.getConfigStore(); - boolean kra_present = cs.getBoolean("ca.connector.KRA.enable", false); - if (!kra_present) return null; - - boolean encrypt_archival = cs.getBoolean("kra.allowEncDecrypt.archival", false); - return encrypt_archival ? KRAInfoService.ENCRYPT_MECHANISM : KRAInfoService.KEYWRAP_MECHANISM; + /** + * Add KRA fields if KRA is configured, querying the KRA + * if necessary. + * + * Apart from reading 'headers', this method doesn't access + * any instance data. + */ + private void addKRAInfo(CAInfo info) { + KRAConnectorInfo connInfo = null; + try { + KRAConnectorProcessor processor = + new KRAConnectorProcessor(getLocale(headers)); + connInfo = processor.getConnectorInfo(); + } catch (Throwable e) { + // connInfo remains as null + } + boolean kraEnabled = + connInfo != null + && "true".equalsIgnoreCase(connInfo.getEnable()); + + if (kraEnabled) { + if (!kraInfoAuthoritative) { + // KRA is enabled but we are yet to successfully + // query the KRA-related info. Do it now. + queryKRAInfo(connInfo); + } + + info.setArchivalMechanism(archivalMechanism); + info.setWrappingKeySet(wrappingKeySet); + } } - String getWrappingKeySet() throws EBaseException { - IConfigStore cs = CMS.getConfigStore(); - boolean kra_present = cs.getBoolean("ca.connector.KRA.enable", false); - if (!kra_present) return null; + private static void queryKRAInfo(KRAConnectorInfo connInfo) { + try { + KRAInfo kraInfo = getKRAInfoClient(connInfo).getInfo(); + + archivalMechanism = kraInfo.getArchivalMechanism(); + + // request succeeded; the KRA is 10.4 or higher, + // therefore supports key set v1 + wrappingKeySet = "1"; + + // mark info as authoritative + kraInfoAuthoritative = true; + } catch (PKIException e) { + if (e.getCode() == 404) { + // The KRAInfoResource was added in 10.4, + // so we are talking to a pre-10.4 KRA + + // pre-10.4 only supports key set v0 + wrappingKeySet = "0"; + + // pre-10.4 KRA does not advertise the archival + // mechanism; look for the old knob in CA's config + // or fall back to the default + IConfigStore cs = CMS.getConfigStore(); + boolean encrypt_archival; + try { + encrypt_archival = cs.getBoolean( + "kra.allowEncDecrypt.archival", false); + } catch (EBaseException e1) { + encrypt_archival = false; + } + archivalMechanism = encrypt_archival + ? KRAInfoService.ENCRYPT_MECHANISM + : KRAInfoService.KEYWRAP_MECHANISM; + + // mark info as authoritative + kraInfoAuthoritative = true; + } else { + CMS.debug("Failed to retrieve archive wrapping information from the CA: " + e); + CMS.debug(e); + } + } catch (Throwable e) { + CMS.debug("Failed to retrieve archive wrapping information from the CA: " + e); + CMS.debug(e); + } + } - return cs.getString("kra.wrappingKeySet", "1"); + /** + * Construct KRAInfoClient given KRAConnectorInfo + */ + private static KRAInfoClient getKRAInfoClient(KRAConnectorInfo connInfo) + throws MalformedURLException, URISyntaxException, EBaseException { + ClientConfig config = new ClientConfig(); + int port = Integer.parseInt(connInfo.getPort()); + config.setServerURL("https", connInfo.getHost(), port); + config.setCertDatabase( + CMS.getConfigStore().getString("instanceRoot") + "/alias"); + return new KRAInfoClient(new PKIClient(config), "kra"); } + } -- 1.8.3.1 From c64d6331d52dcf07108226c5dff26bd8b6c41e70 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Thu, 4 May 2017 10:36:49 +0200 Subject: [PATCH 03/10] pki.authority: Don't send header as POST body pki.authority was mistakenly sending headers as POST body instead of sending an empty POST body with right headers. Change-Id: I6a5089e55233cf72f4d8e79832150e7c45f0fdae Signed-off-by: Christian Heimes --- base/common/python/pki/authority.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/base/common/python/pki/authority.py b/base/common/python/pki/authority.py index 9fa459c..0d83a4b 100644 --- a/base/common/python/pki/authority.py +++ b/base/common/python/pki/authority.py @@ -140,7 +140,7 @@ class AuthorityClient(object): url = self.ca_url + '/' + str(aid) headers = {'Content-type': 'application/json', 'Accept': 'application/json'} - r = self.connection.get(url, headers) + r = self.connection.get(url, headers=headers) return AuthorityData.from_json(r.json()) @pki.handle_exceptions() @@ -167,7 +167,7 @@ class AuthorityClient(object): raise ValueError( "Invalid format passed in - PEM or DER expected.") - r = self.connection.get(url, headers) + r = self.connection.get(url, headers=headers) return r.text @pki.handle_exceptions() @@ -189,7 +189,7 @@ class AuthorityClient(object): elif output_format == "PKCS7": headers['Accept'] = "application/pkcs7-mime" - r = self.connection.get(url, headers) + r = self.connection.get(url, headers=headers) return r.text @pki.handle_exceptions() @@ -238,7 +238,7 @@ class AuthorityClient(object): response = self.connection.post( self.ca_url, create_request, - headers) + headers=headers) new_ca = AuthorityData.from_json(response.json()) return new_ca @@ -257,7 +257,7 @@ class AuthorityClient(object): headers = {'Content-type': 'application/json', 'Accept': 'application/json'} - self.connection.post(url, headers) + self.connection.post(url, None, headers=headers) @pki.handle_exceptions() def disable_ca(self, aid): @@ -272,7 +272,7 @@ class AuthorityClient(object): headers = {'Content-type': 'application/json', 'Accept': 'application/json'} - self.connection.post(url, headers) + self.connection.post(url, None, headers=headers) @pki.handle_exceptions() def delete_ca(self, aid): @@ -287,7 +287,7 @@ class AuthorityClient(object): headers = {'Content-type': 'application/json', 'Accept': 'application/json'} - self.connection.delete(url, headers) + self.connection.delete(url, headers=headers) encoder.NOTYPES['AuthorityData'] = AuthorityData -- 1.8.3.1 From 62a78bfa227b5e75a7cb931d7e65e824f5fe01ec Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Fri, 5 May 2017 19:54:15 +1000 Subject: [PATCH 04/10] Fix PKCS #12 import during clone installation PKCS #12 export was updated to use AES / PBES2 encryption for the key bags, but an import code path used when spawning a clone was missed, and now fails (because it doesn't grok PBES2). Update it to use CryptoStore.importEncryptedPrivateKeyInfo() instead, fixing the problem. Fixes: https://pagure.io/dogtagpki/issue/2677 Change-Id: I11f26ae8a4811f27690541f2c70b3a2adb6264e9 --- .../cms/servlet/csadmin/ConfigurationUtils.java | 32 +++++++--------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java index ee1984b..07c64af 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java +++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java @@ -886,9 +886,7 @@ public class ConfigurationUtils { if (oid.equals(SafeBag.PKCS8_SHROUDED_KEY_BAG)) { CMS.debug(" - Bag #" + j + ": key"); - EncryptedPrivateKeyInfo privkeyinfo = - (EncryptedPrivateKeyInfo) bag.getInterpretedBagContent(); - PrivateKeyInfo pkeyinfo = privkeyinfo.decrypt(password, new PasswordConverter()); + byte[] epki = bag.getBagContent().getEncoded(); SET bagAttrs = bag.getBagAttributes(); String subjectDN = null; @@ -910,9 +908,10 @@ public class ConfigurationUtils { } } - // pkeyinfo_v stores private key (PrivateKeyInfo) and subject DN (String) + // pkeyinfo_v stores EncryptedPrivateKeyInfo + // (byte[]) and subject DN (String) Vector pkeyinfo_v = new Vector(); - pkeyinfo_v.addElement(pkeyinfo); + pkeyinfo_v.addElement(epki); if (subjectDN != null) pkeyinfo_v.addElement(subjectDN); @@ -971,7 +970,7 @@ public class ConfigurationUtils { } } - importKeyCert(pkeyinfo_collection, cert_collection); + importKeyCert(password, pkeyinfo_collection, cert_collection); } public static void verifySystemCertificates() throws Exception { @@ -1012,6 +1011,7 @@ public class ConfigurationUtils { } public static void importKeyCert( + Password password, Vector> pkeyinfo_collection, Vector> cert_collection ) throws Exception { @@ -1028,7 +1028,7 @@ public class ConfigurationUtils { CMS.debug("Importing new keys:"); for (int i = 0; i < pkeyinfo_collection.size(); i++) { Vector pkeyinfo_v = pkeyinfo_collection.elementAt(i); - PrivateKeyInfo pkeyinfo = (PrivateKeyInfo) pkeyinfo_v.elementAt(0); + byte[] epki = (byte[]) pkeyinfo_v.elementAt(0); String nickname = (String) pkeyinfo_v.elementAt(1); CMS.debug("- Key: " + nickname); @@ -1037,11 +1037,6 @@ public class ConfigurationUtils { continue; } - // encode private key - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - pkeyinfo.encode(bos); - byte[] pkey = bos.toByteArray(); - CMS.debug(" Find cert with subject DN " + nickname); // TODO: use better mechanism to find the cert byte[] x509cert = getX509Cert(nickname, cert_collection); @@ -1063,16 +1058,9 @@ public class ConfigurationUtils { // this is OK } - // encrypt private key - SymmetricKey sk = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3, 0, null, true); - byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; - IVParameterSpec param = new IVParameterSpec(iv); - byte[] encpkey = CryptoUtil.encryptUsingSymmetricKey(token, sk, pkey, EncryptionAlgorithm.DES3_CBC_PAD, param); - - // unwrap private key to load into database - KeyWrapper wrapper = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD); - wrapper.initUnwrap(sk, param); - wrapper.unwrapPrivate(encpkey, getPrivateKeyType(publicKey), publicKey); + // import private key into database + store.importEncryptedPrivateKeyInfo( + new PasswordConverter(), password, nickname, publicKey, epki); } CMS.debug("Importing new certificates:"); -- 1.8.3.1 From 3fb95590cdf0e45418fa0be7a020691567ef152a Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Fri, 5 May 2017 20:13:07 +1000 Subject: [PATCH 05/10] Delete unused methods Change-Id: I81d3aa98a05208b2f5b1be3700c2e0759b387203 --- .../cms/servlet/csadmin/ConfigurationUtils.java | 103 --------------------- 1 file changed, 103 deletions(-) diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java index 07c64af..c9a375f 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java +++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java @@ -1203,13 +1203,6 @@ public class ConfigurationUtils { return null; } - public static org.mozilla.jss.crypto.PrivateKey.Type getPrivateKeyType(PublicKey pubkey) { - if (pubkey.getAlgorithm().equals("EC")) { - return org.mozilla.jss.crypto.PrivateKey.Type.EC; - } - return org.mozilla.jss.crypto.PrivateKey.Type.RSA; - } - public static boolean isCASigningCert(String name) throws EBaseException { IConfigStore cs = CMS.getConfigStore(); try { @@ -3495,102 +3488,6 @@ public class ConfigurationUtils { } } - public static void addKeyBag(PrivateKey pkey, X509Certificate x509cert, - Password pass, byte[] localKeyId, SEQUENCE safeContents) - throws NoSuchAlgorithmException, InvalidBERException, InvalidKeyException, - InvalidAlgorithmParameterException, NotInitializedException, TokenException, IllegalStateException, - IllegalBlockSizeException, BadPaddingException, CharConversionException { - - PasswordConverter passConverter = new PasswordConverter(); - - SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); - byte salt[] = random.generateSeed(4); // 4 bytes salt - byte[] priData = getEncodedKey(pkey); - - PrivateKeyInfo pki = (PrivateKeyInfo) - ASN1Util.decode(PrivateKeyInfo.getTemplate(), priData); - ASN1Value key = EncryptedPrivateKeyInfo.createPBE( - PBEAlgorithm.PBE_SHA1_DES3_CBC, - pass, salt, 1, passConverter, pki); - SET keyAttrs = createBagAttrs( - x509cert.getSubjectDN().toString(), localKeyId); - SafeBag keyBag = new SafeBag(SafeBag.PKCS8_SHROUDED_KEY_BAG, - key, keyAttrs); - safeContents.addElement(keyBag); - - } - - public static byte[] addCertBag(X509Certificate x509cert, String nickname, - SEQUENCE safeContents) throws CertificateEncodingException, NoSuchAlgorithmException, - CharConversionException { - byte[] localKeyId = null; - - ASN1Value cert = new OCTET_STRING(x509cert.getEncoded()); - localKeyId = createLocalKeyId(x509cert); - SET certAttrs = null; - if (nickname != null) - certAttrs = createBagAttrs(nickname, localKeyId); - SafeBag certBag = new SafeBag(SafeBag.CERT_BAG, - new CertBag(CertBag.X509_CERT_TYPE, cert), certAttrs); - safeContents.addElement(certBag); - - return localKeyId; - } - - public static byte[] getEncodedKey(PrivateKey pkey) throws NotInitializedException, NoSuchAlgorithmException, - TokenException, IllegalStateException, CharConversionException, InvalidKeyException, - InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { - CryptoManager cm = CryptoManager.getInstance(); - CryptoToken token = cm.getInternalKeyStorageToken(); - KeyGenerator kg = token.getKeyGenerator(KeyGenAlgorithm.DES3); - SymmetricKey sk = kg.generate(); - KeyWrapper wrapper = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD); - byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; - IVParameterSpec param = new IVParameterSpec(iv); - wrapper.initWrap(sk, param); - byte[] enckey = wrapper.wrap(pkey); - Cipher c = token.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD); - c.initDecrypt(sk, param); - byte[] recovered = c.doFinal(enckey); - return recovered; - } - - public static byte[] createLocalKeyId(X509Certificate cert) - throws NoSuchAlgorithmException, CertificateEncodingException { - - // SHA1 hash of the X509Cert der encoding - byte certDer[] = cert.getEncoded(); - - MessageDigest md = MessageDigest.getInstance("SHA"); - - md.update(certDer); - return md.digest(); - - } - - public static SET createBagAttrs(String nickName, byte localKeyId[]) throws CharConversionException { - - SET attrs = new SET(); - SEQUENCE nickNameAttr = new SEQUENCE(); - - nickNameAttr.addElement(SafeBag.FRIENDLY_NAME); - SET nickNameSet = new SET(); - - nickNameSet.addElement(new BMPString(nickName)); - nickNameAttr.addElement(nickNameSet); - attrs.addElement(nickNameAttr); - SEQUENCE localKeyAttr = new SEQUENCE(); - - localKeyAttr.addElement(SafeBag.LOCAL_KEY_ID); - SET localKeySet = new SET(); - - localKeySet.addElement(new OCTET_STRING(localKeyId)); - localKeyAttr.addElement(localKeySet); - attrs.addElement(localKeyAttr); - return attrs; - - } - public static void createAdminCertificate(String certRequest, String certRequestType, String subject) throws Exception { IConfigStore cs = CMS.getConfigStore(); -- 1.8.3.1 From f26b3aaee1cf36941f387b464b937ffee1403048 Mon Sep 17 00:00:00 2001 From: Jack Magne Date: Fri, 5 May 2017 11:44:17 -0700 Subject: [PATCH 06/10] Non server keygen issue in SCP03. Ticket 1663 Add SCP03 support: https://pagure.io/dogtagpki/issue/1663 We discovered a minor issue when trying to log values that don't exist when performing the non server side keygen case. For instance , we don't need to generate a kek session key in this case, and we were trying to print info about it to the logs. This fix allows this case to work without issue. --- .../server/tps/channel/SecureChannel.java | 4 +- .../server/tps/processor/TPSProcessor.java | 51 +++++++++++++++------- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java b/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java index fc5472c..5e5646b 100644 --- a/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java +++ b/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java @@ -148,8 +148,8 @@ public class SecureChannel { CMS.debug("SecureChannel.SecureChannel: For SCP03. : "); - CMS.debug("kekDesKey: " + kekDesKey.toHexString()); - CMS.debug("keyCheck: " + keyCheck.toHexString()); + if (keyCheck != null) + CMS.debug("keyCheck: " + keyCheck.toHexString()); this.platProtInfo = platformInfo; this.processor = processor; diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java index 0cfac59..0f96915 100644 --- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java +++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java @@ -33,6 +33,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import netscape.security.x509.RevocationReason; + import org.dogtagpki.server.tps.TPSSession; import org.dogtagpki.server.tps.TPSSubsystem; import org.dogtagpki.server.tps.authentication.AuthUIParameter; @@ -100,8 +102,6 @@ import com.netscape.cms.servlet.tks.SecureChannelProtocol; import com.netscape.cmsutil.crypto.CryptoUtil; import com.netscape.symkey.SessionKey; -import netscape.security.x509.RevocationReason; - public class TPSProcessor { public static final int RESULT_NO_ERROR = 0; @@ -923,20 +923,39 @@ public class TPSProcessor { TPSBuffer drmDesKeyBuff = resp.getDRM_Trans_DesKey(); TPSBuffer kekDesKeyBuff = resp.getKekWrappedDesKey(); - CMS.debug(method + " encSessionKeyBuff: " + encSessionKeyBuff.toHexString()); - CMS.debug(method + " kekSessionKeyBuff: " + kekSessionKeyBuff.toHexString()); - CMS.debug(method + " macSessionKeyBuff: " + macSessionKeyBuff.toHexString()); - CMS.debug(method + " hostCryptogramBuff: " + hostCryptogramBuff.toHexString()); - CMS.debug(method + " keyCheckBuff: " + keyCheckBuff.toHexString()); - CMS.debug(method + " drmDessKeyBuff: " + drmDesKeyBuff.toHexString()); - CMS.debug(method + " kekDesKeyBuff: " + kekDesKeyBuff.toHexString()); - - encSessionKeySCP03 = (PK11SymKey) protocol.unwrapWrappedSymKeyOnToken(token, sharedSecret, - encSessionKeyBuff.toBytesArray(), false, SymmetricKey.AES); - macSessionKeySCP03 = (PK11SymKey) protocol.unwrapWrappedSymKeyOnToken(token, sharedSecret, - macSessionKeyBuff.toBytesArray(), false, SymmetricKey.AES); - kekSessionKeySCP03 = (PK11SymKey) protocol.unwrapWrappedSymKeyOnToken(token, sharedSecret, - kekSessionKeyBuff.toBytesArray(), false, SymmetricKey.AES); + if (encSessionKeyBuff != null) + CMS.debug(method + " encSessionKeyBuff: " + encSessionKeyBuff.toHexString()); + + if (kekSessionKeyBuff != null) + CMS.debug(method + " kekSessionKeyBuff: " + kekSessionKeyBuff.toHexString()); + + if (macSessionKeyBuff != null) + CMS.debug(method + " macSessionKeyBuff: " + macSessionKeyBuff.toHexString()); + + if (hostCryptogramBuff != null) + CMS.debug(method + " hostCryptogramBuff: " + hostCryptogramBuff.toHexString()); + + if (keyCheckBuff != null) + CMS.debug(method + " keyCheckBuff: " + keyCheckBuff.toHexString()); + + if (drmDesKeyBuff != null) + CMS.debug(method + " drmDessKeyBuff: " + drmDesKeyBuff.toHexString()); + + if (kekDesKeyBuff != null) + CMS.debug(method + " kekDesKeyBuff: " + kekDesKeyBuff.toHexString()); + + + if (encSessionKeyBuff != null) + encSessionKeySCP03 = (PK11SymKey) protocol.unwrapWrappedSymKeyOnToken(token, sharedSecret, + encSessionKeyBuff.toBytesArray(), false, SymmetricKey.AES); + + if (macSessionKeyBuff != null) + macSessionKeySCP03 = (PK11SymKey) protocol.unwrapWrappedSymKeyOnToken(token, sharedSecret, + macSessionKeyBuff.toBytesArray(), false, SymmetricKey.AES); + + if (kekSessionKeyBuff != null) + kekSessionKeySCP03 = (PK11SymKey) protocol.unwrapWrappedSymKeyOnToken(token, sharedSecret, + kekSessionKeyBuff.toBytesArray(), false, SymmetricKey.AES); channel = new SecureChannel(this, encSessionKeySCP03, macSessionKeySCP03, kekSessionKeySCP03, drmDesKeyBuff, kekDesKeyBuff, -- 1.8.3.1 From f84bfab30647ae1492fcdca0a026bfa4d91350c9 Mon Sep 17 00:00:00 2001 From: Ade Lee Date: Mon, 1 May 2017 15:56:58 -0400 Subject: [PATCH 07/10] Make sure generated asym keys are extractable In HSMs, we were not able to retrieve asym keys that were generated from the AsymKeyGenService, because the right flags were not set (ie. set like in the server side keygen case). To do this, I extracted the key generation function from NetKeygenService to KeyRecoveryAuthority, so that it could be used by both services. Bugzilla BZ# 1386303 Change-Id: I13b5f4b602217a685acada94091e91df75e25eff --- .../certsrv/kra/IKeyRecoveryAuthority.java | 17 ++ .../src/com/netscape/kra/AsymKeyGenService.java | 23 +-- .../src/com/netscape/kra/KeyRecoveryAuthority.java | 184 ++++++++++++++++++++ .../src/com/netscape/kra/NetkeyKeygenService.java | 185 +-------------------- 4 files changed, 213 insertions(+), 196 deletions(-) diff --git a/base/common/src/com/netscape/certsrv/kra/IKeyRecoveryAuthority.java b/base/common/src/com/netscape/certsrv/kra/IKeyRecoveryAuthority.java index a12d773..4f709e9 100644 --- a/base/common/src/com/netscape/certsrv/kra/IKeyRecoveryAuthority.java +++ b/base/common/src/com/netscape/certsrv/kra/IKeyRecoveryAuthority.java @@ -17,12 +17,15 @@ // --- END COPYRIGHT BLOCK --- package com.netscape.certsrv.kra; +import java.security.KeyPair; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import org.dogtagpki.legacy.policy.IPolicyProcessor; import org.mozilla.jss.crypto.CryptoToken; +import org.mozilla.jss.crypto.KeyPairGeneratorSpi; +import org.mozilla.jss.crypto.PQGParams; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.ISubsystem; @@ -337,4 +340,18 @@ public interface IKeyRecoveryAuthority extends ISubsystem { * @return */ public boolean isRetrievalSynchronous(String realm); + + /** + * Generate an asymmetric key pair. + * + * @param alg + * @param keySize + * @param keyCurve + * @param pqg + * @param usageList - RSA only for now + * @return key pair + * @throws EBaseException + */ + public KeyPair generateKeyPair(String alg, int keySize, String keyCurve, + PQGParams pqg, KeyPairGeneratorSpi.Usage[] usageList) throws EBaseException; } diff --git a/base/kra/src/com/netscape/kra/AsymKeyGenService.java b/base/kra/src/com/netscape/kra/AsymKeyGenService.java index 9528972..7351d50 100644 --- a/base/kra/src/com/netscape/kra/AsymKeyGenService.java +++ b/base/kra/src/com/netscape/kra/AsymKeyGenService.java @@ -19,14 +19,10 @@ package com.netscape.kra; import java.math.BigInteger; import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; import org.mozilla.jss.crypto.CryptoToken; -import org.mozilla.jss.crypto.KeyPairAlgorithm; -import org.mozilla.jss.crypto.KeyPairGenerator; import org.mozilla.jss.crypto.KeyPairGeneratorSpi; import org.mozilla.jss.crypto.PrivateKey; -import org.mozilla.jss.crypto.TokenException; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; @@ -42,7 +38,6 @@ import com.netscape.certsrv.request.IRequest; import com.netscape.certsrv.request.IService; import com.netscape.certsrv.request.RequestId; import com.netscape.certsrv.security.IStorageKeyUnit; -import com.netscape.cms.servlet.key.KeyRequestDAO; import com.netscape.cmscore.dbs.KeyRecord; import netscape.security.util.WrappingParams; @@ -132,8 +127,6 @@ public class AsymKeyGenService implements IService { CMS.debug("AsymKeyGenService.serviceRequest. Request id: " + request.getRequestId()); CMS.debug("AsymKeyGenService.serviceRequest algorithm: " + algorithm); - KeyPairAlgorithm keyPairAlgorithm = KeyRequestDAO.ASYMKEY_GEN_ALGORITHMS.get(algorithm.toUpperCase()); - String owner = request.getExtDataInString(IRequest.ATTR_REQUEST_OWNER); String auditSubjectID = owner; @@ -141,16 +134,18 @@ public class AsymKeyGenService implements IService { CryptoToken token = kra.getKeygenToken(); // Generating the asymmetric keys - KeyPairGenerator keyPairGen = null; KeyPair kp = null; try { - keyPairGen = token.getKeyPairGenerator(keyPairAlgorithm); - keyPairGen.initialize(keySize); - if (usageList != null) - keyPairGen.setKeyPairUsages(usageList, usageList); - kp = keyPairGen.genKeyPair(); - } catch (NoSuchAlgorithmException | TokenException e) { + kp = kra.generateKeyPair( + algorithm.toUpperCase(), + keySize, + null, // keyCurve for ECC, not yet supported + null, // PQG not yet supported + usageList + ); + + } catch (EBaseException e) { CMS.debugStackTrace(); auditAsymKeyGenRequestProcessed(auditSubjectID, ILogger.FAILURE, request.getRequestId(), clientKeyId, null, "Failed to generate Asymmetric key"); diff --git a/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java b/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java index ec920e6..54953d1 100644 --- a/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java +++ b/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java @@ -20,6 +20,10 @@ package com.netscape.kra; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; @@ -32,6 +36,12 @@ import org.dogtagpki.legacy.kra.KRAPolicy; import org.dogtagpki.legacy.policy.IPolicyProcessor; import org.mozilla.jss.NoSuchTokenException; import org.mozilla.jss.crypto.CryptoToken; +import org.mozilla.jss.crypto.KeyPairAlgorithm; +import org.mozilla.jss.crypto.KeyPairGenerator; +import org.mozilla.jss.crypto.KeyPairGeneratorSpi; +import org.mozilla.jss.crypto.PQGParamGenException; +import org.mozilla.jss.crypto.PQGParams; +import org.mozilla.jss.crypto.TokenException; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.authority.IAuthority; @@ -1816,4 +1826,178 @@ public class KeyRecoveryAuthority implements IAuthority, IKeyService, IKeyRecove return agents; } + + public KeyPair generateKeyPair(String alg, int keySize, String keyCurve, + PQGParams pqg, KeyPairGeneratorSpi.Usage[] usageList) throws EBaseException { + KeyPairAlgorithm kpAlg = null; + + if (alg.equals("RSA")) + kpAlg = KeyPairAlgorithm.RSA; + else if (alg.equals("EC")) + kpAlg = KeyPairAlgorithm.EC; + else + kpAlg = KeyPairAlgorithm.DSA; + + try { + KeyPair kp = generateKeyPair(kpAlg, keySize, keyCurve, pqg, usageList); + + return kp; + } catch (InvalidParameterException e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEYSIZE_PARAMS", + "" + keySize)); + } catch (PQGParamGenException e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_PQG_GEN_FAILED")); + } catch (NoSuchAlgorithmException e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_ALG_NOT_SUPPORTED", + kpAlg.toString())); + } catch (TokenException e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_TOKEN_ERROR_1", e.toString())); + } catch (InvalidAlgorithmParameterException e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_ALG_NOT_SUPPORTED", "DSA")); + } + } + + public KeyPair generateKeyPair( + KeyPairAlgorithm kpAlg, int keySize, String keyCurve, PQGParams pqg, + KeyPairGeneratorSpi.Usage[] usageList ) + throws NoSuchAlgorithmException, TokenException, InvalidAlgorithmParameterException, + InvalidParameterException, PQGParamGenException { + + CryptoToken token = getKeygenToken(); + + CMS.debug("NetkeyKeygenService: key pair is to be generated on slot: " + token.getName()); + + /* + make it temporary so can work with HSM + netHSM works with + temporary == true + sensitive == + extractable == + LunaSA2 works with + temporary == true + sensitive == true + extractable == true + */ + KeyPairGenerator kpGen = token.getKeyPairGenerator(kpAlg); + IConfigStore config = CMS.getConfigStore(); + IConfigStore kgConfig = config.getSubStore("kra.keygen"); + boolean tp = false; + boolean sp = false; + boolean ep = false; + if ((kgConfig != null) && (!kgConfig.equals(""))) { + try { + tp = kgConfig.getBoolean("temporaryPairs", false); + sp = kgConfig.getBoolean("sensitivePairs", false); + ep = kgConfig.getBoolean("extractablePairs", false); + CMS.debug("NetkeyKeygenService: found config store: kra.keygen"); + // by default, let nethsm work + if ((tp == false) && (sp == false) && (ep == false)) { + if (kpAlg == KeyPairAlgorithm.EC) { + // set to what works for nethsm + tp = true; + sp = false; + ep = true; + } else + tp = true; + } + } catch (Exception e) { + CMS.debug("NetkeyKeygenService: kgConfig.getBoolean failed"); + // by default, let nethsm work + tp = true; + } + } else { + // by default, let nethsm work + CMS.debug("NetkeyKeygenService: cannot find config store: kra.keygen, assume temporaryPairs==true"); + if (kpAlg == KeyPairAlgorithm.EC) { + // set to what works for nethsm + tp = true; + sp = false; + ep = true; + } else { + tp = true; + } + } + + if (kpAlg == KeyPairAlgorithm.EC) { + + boolean isECDHE = false; + KeyPair pair = null; + + // used with isECDHE == true + org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage usages_mask_ECDSA[] = { + org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage.DERIVE + }; + + // used with isECDHE == false + org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage usages_mask_ECDH[] = { + org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage.SIGN, + org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage.SIGN_RECOVER + }; + + try { + pair = CryptoUtil.generateECCKeyPair(token.getName(), + keyCurve /*ECC_curve default*/, + null, + (isECDHE==true) ? usages_mask_ECDSA: usages_mask_ECDH, + tp /*temporary*/, sp? 1:0 /*sensitive*/, ep? 1:0 /*extractable*/); + CMS.debug("NetkeyKeygenService: after key pair generation" ); + } catch (Exception e) { + CMS.debug("NetkeyKeygenService: key pair generation with exception:"+e.toString()); + } + return pair; + + } else { // !EC + //only specified to "true" will it be set + if (tp == true) { + CMS.debug("NetkeyKeygenService: setting temporaryPairs to true"); + kpGen.temporaryPairs(true); + } + + if (sp == true) { + CMS.debug("NetkeyKeygenService: setting sensitivePairs to true"); + kpGen.sensitivePairs(true); + } + + if (ep == true) { + CMS.debug("NetkeyKeygenService: setting extractablePairs to true"); + kpGen.extractablePairs(true); + } + + if (kpAlg == KeyPairAlgorithm.DSA) { + if (pqg == null) { + kpGen.initialize(keySize); + } else { + kpGen.initialize(pqg); + } + } else { + kpGen.initialize(keySize); + } + + if (usageList != null) + kpGen.setKeyPairUsages(usageList, usageList); + + if (pqg == null) { + KeyPair kp = null; + synchronized (new Object()) { + CMS.debug("NetkeyKeygenService: key pair generation begins"); + kp = kpGen.genKeyPair(); + CMS.debug("NetkeyKeygenService: key pair generation done"); + addEntropy(true); + } + return kp; + } else { + // DSA + KeyPair kp = null; + + /* no DSA for now... netkey prototype + do { + // 602548 NSS bug - to overcome it, we use isBadDSAKeyPair + kp = kpGen.genKeyPair(); + } + while (isBadDSAKeyPair(kp)); + */ + return kp; + } + } + } } diff --git a/base/kra/src/com/netscape/kra/NetkeyKeygenService.java b/base/kra/src/com/netscape/kra/NetkeyKeygenService.java index e09eb42..f068a4a 100644 --- a/base/kra/src/com/netscape/kra/NetkeyKeygenService.java +++ b/base/kra/src/com/netscape/kra/NetkeyKeygenService.java @@ -23,11 +23,8 @@ import java.io.FilterOutputStream; import java.io.IOException; import java.io.PrintStream; import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; -import java.security.InvalidParameterException; import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import org.mozilla.jss.asn1.ASN1Util; @@ -35,21 +32,15 @@ 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.KeyPairAlgorithm; -import org.mozilla.jss.crypto.KeyPairGenerator; import org.mozilla.jss.crypto.KeyWrapAlgorithm; -import org.mozilla.jss.crypto.PQGParamGenException; -import org.mozilla.jss.crypto.PQGParams; import org.mozilla.jss.crypto.PrivateKey; import org.mozilla.jss.crypto.SymmetricKey; -import org.mozilla.jss.crypto.TokenException; import org.mozilla.jss.pkcs11.PK11SymKey; import org.mozilla.jss.pkix.crmf.PKIArchiveOptions; import org.mozilla.jss.util.Base64OutputStream; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; -import com.netscape.certsrv.base.IConfigStore; import com.netscape.certsrv.base.MetaInfo; import com.netscape.certsrv.base.SessionContext; import com.netscape.certsrv.dbs.keydb.IKeyRecord; @@ -122,177 +113,6 @@ public class NetkeyKeygenService implements IService { return archOpts; } - public KeyPair generateKeyPair( - KeyPairAlgorithm kpAlg, int keySize, String keyCurve, PQGParams pqg) - throws NoSuchAlgorithmException, TokenException, InvalidAlgorithmParameterException, - InvalidParameterException, PQGParamGenException { - - CryptoToken token = mKRA.getKeygenToken(); - - CMS.debug("NetkeyKeygenService: key pair is to be generated on slot: " + token.getName()); - - /* - make it temporary so can work with HSM - netHSM works with - temporary == true - sensitive == - extractable == - LunaSA2 works with - temporary == true - sensitive == true - extractable == true - */ - KeyPairGenerator kpGen = token.getKeyPairGenerator(kpAlg); - IConfigStore config = CMS.getConfigStore(); - IConfigStore kgConfig = config.getSubStore("kra.keygen"); - boolean tp = false; - boolean sp = false; - boolean ep = false; - if ((kgConfig != null) && (!kgConfig.equals(""))) { - try { - tp = kgConfig.getBoolean("temporaryPairs", false); - sp = kgConfig.getBoolean("sensitivePairs", false); - ep = kgConfig.getBoolean("extractablePairs", false); - CMS.debug("NetkeyKeygenService: found config store: kra.keygen"); - // by default, let nethsm work - if ((tp == false) && (sp == false) && (ep == false)) { - if (kpAlg == KeyPairAlgorithm.EC) { - // set to what works for nethsm - tp = true; - sp = false; - ep = true; - } else - tp = true; - } - } catch (Exception e) { - CMS.debug("NetkeyKeygenService: kgConfig.getBoolean failed"); - // by default, let nethsm work - tp = true; - } - } else { - // by default, let nethsm work - CMS.debug("NetkeyKeygenService: cannot find config store: kra.keygen, assume temporaryPairs==true"); - if (kpAlg == KeyPairAlgorithm.EC) { - // set to what works for nethsm - tp = true; - sp = false; - ep = true; - } else { - tp = true; - } - } - - if (kpAlg == KeyPairAlgorithm.EC) { - - boolean isECDHE = false; - KeyPair pair = null; - - // used with isECDHE == true - org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage usages_mask_ECDSA[] = { - org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage.DERIVE - }; - - // used with isECDHE == false - org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage usages_mask_ECDH[] = { - org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage.SIGN, - org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage.SIGN_RECOVER - }; - - try { - pair = CryptoUtil.generateECCKeyPair(token.getName(), - keyCurve /*ECC_curve default*/, - null, - (isECDHE==true) ? usages_mask_ECDSA: usages_mask_ECDH, - tp /*temporary*/, sp? 1:0 /*sensitive*/, ep? 1:0 /*extractable*/); - CMS.debug("NetkeyKeygenService: after key pair generation" ); - } catch (Exception e) { - CMS.debug("NetkeyKeygenService: key pair generation with exception:"+e.toString()); - } - return pair; - - } else { // !EC - //only specified to "true" will it be set - if (tp == true) { - CMS.debug("NetkeyKeygenService: setting temporaryPairs to true"); - kpGen.temporaryPairs(true); - } - - if (sp == true) { - CMS.debug("NetkeyKeygenService: setting sensitivePairs to true"); - kpGen.sensitivePairs(true); - } - - if (ep == true) { - CMS.debug("NetkeyKeygenService: setting extractablePairs to true"); - kpGen.extractablePairs(true); - } - - if (kpAlg == KeyPairAlgorithm.DSA) { - if (pqg == null) { - kpGen.initialize(keySize); - } else { - kpGen.initialize(pqg); - } - } else { - kpGen.initialize(keySize); - } - - if (pqg == null) { - KeyPair kp = null; - synchronized (new Object()) { - CMS.debug("NetkeyKeygenService: key pair generation begins"); - kp = kpGen.genKeyPair(); - CMS.debug("NetkeyKeygenService: key pair generation done"); - mKRA.addEntropy(true); - } - return kp; - } else { - // DSA - KeyPair kp = null; - - /* no DSA for now... netkey prototype - do { - // 602548 NSS bug - to overcome it, we use isBadDSAKeyPair - kp = kpGen.genKeyPair(); - } - while (isBadDSAKeyPair(kp)); - */ - return kp; - } - } - } - - public KeyPair generateKeyPair(String alg, - int keySize, String keyCurve, PQGParams pqg) throws EBaseException { - - KeyPairAlgorithm kpAlg = null; - - if (alg.equals("RSA")) - kpAlg = KeyPairAlgorithm.RSA; - else if (alg.equals("EC")) - kpAlg = KeyPairAlgorithm.EC; - else - kpAlg = KeyPairAlgorithm.DSA; - - try { - KeyPair kp = generateKeyPair(kpAlg, keySize, keyCurve, pqg); - - return kp; - } catch (InvalidParameterException e) { - throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEYSIZE_PARAMS", - "" + keySize)); - } catch (PQGParamGenException e) { - throw new EBaseException(CMS.getUserMessage("CMS_BASE_PQG_GEN_FAILED")); - } catch (NoSuchAlgorithmException e) { - throw new EBaseException(CMS.getUserMessage("CMS_BASE_ALG_NOT_SUPPORTED", - kpAlg.toString())); - } catch (TokenException e) { - throw new EBaseException(CMS.getUserMessage("CMS_BASE_TOKEN_ERROR_1", e.toString())); - } catch (InvalidAlgorithmParameterException e) { - throw new EBaseException(CMS.getUserMessage("CMS_BASE_ALG_NOT_SUPPORTED", "DSA")); - } - } - private static String base64Encode(byte[] bytes) throws IOException { // All this streaming is lame, but Base64OutputStream needs a // PrintStream @@ -430,10 +250,11 @@ public class NetkeyKeygenService implements IService { CMS.debug("NetkeyKeygenService: about to generate key pair"); - keypair = generateKeyPair(rKeytype /* rKeytype: "RSA" or "EC" */, + keypair = mKRA.generateKeyPair(rKeytype /* rKeytype: "RSA" or "EC" */, keysize /*Integer.parseInt(len)*/, rKeycurve /* for "EC" only */, - null /*pqgParams*/); + null /*pqgParams*/, + null /* usageList*/); if (keypair == null) { CMS.debug("NetkeyKeygenService: failed generating key pair for " + rCUID + ":" + rUserid); -- 1.8.3.1 From bea446868e282955d9c70028be657530eaccbe29 Mon Sep 17 00:00:00 2001 From: Ade Lee Date: Mon, 1 May 2017 18:25:59 -0400 Subject: [PATCH 08/10] Use AES-CBC in storage unit for archival in key wrapping When AES-KW or AES-KWP is not available, we need to be sure to use a key wrap algorithm that is available for keywrap. This would be AES-CBC. Removes some TODOs. Refactor so that getWrappingParams is only defined on the StorageUnit, which is where it makes sense in any case. Part of Bugzilla BZ# 1386303 Change-Id: I28711f7fe0a00e9d12d26c6e170fb125418d6d51 --- .../src/com/netscape/certsrv/security/IEncryptionUnit.java | 2 -- .../src/com/netscape/certsrv/security/IStorageKeyUnit.java | 6 ++++++ base/kra/src/com/netscape/kra/AsymKeyGenService.java | 11 +++-------- base/kra/src/com/netscape/kra/EncryptionUnit.java | 2 -- base/kra/src/com/netscape/kra/EnrollmentService.java | 2 +- base/kra/src/com/netscape/kra/NetkeyKeygenService.java | 7 +++++-- base/kra/src/com/netscape/kra/SecurityDataProcessor.java | 2 +- base/kra/src/com/netscape/kra/StorageKeyUnit.java | 12 +++++++++++- base/kra/src/com/netscape/kra/SymKeyGenService.java | 7 +++++-- base/kra/src/com/netscape/kra/TransportKeyUnit.java | 4 ---- 10 files changed, 32 insertions(+), 23 deletions(-) diff --git a/base/common/src/com/netscape/certsrv/security/IEncryptionUnit.java b/base/common/src/com/netscape/certsrv/security/IEncryptionUnit.java index add15cb..e55713d 100644 --- a/base/common/src/com/netscape/certsrv/security/IEncryptionUnit.java +++ b/base/common/src/com/netscape/certsrv/security/IEncryptionUnit.java @@ -63,7 +63,5 @@ public interface IEncryptionUnit extends IToken { SymmetricKey.Usage usage, WrappingParams params) throws Exception; - public WrappingParams getWrappingParams() throws Exception; - public WrappingParams getOldWrappingParams(); } diff --git a/base/common/src/com/netscape/certsrv/security/IStorageKeyUnit.java b/base/common/src/com/netscape/certsrv/security/IStorageKeyUnit.java index cd94143..bfc6012 100644 --- a/base/common/src/com/netscape/certsrv/security/IStorageKeyUnit.java +++ b/base/common/src/com/netscape/certsrv/security/IStorageKeyUnit.java @@ -174,4 +174,10 @@ public interface IStorageKeyUnit extends IEncryptionUnit { public PrivateKey unwrap(byte privateKey[], PublicKey pubKey, boolean temporary, WrappingParams params) throws Exception; + /** + * Get the wrapping parameters for this storage unit + * + */ + public WrappingParams getWrappingParams(boolean encrypt) throws Exception; + } diff --git a/base/kra/src/com/netscape/kra/AsymKeyGenService.java b/base/kra/src/com/netscape/kra/AsymKeyGenService.java index 7351d50..cfee504 100644 --- a/base/kra/src/com/netscape/kra/AsymKeyGenService.java +++ b/base/kra/src/com/netscape/kra/AsymKeyGenService.java @@ -20,7 +20,6 @@ package com.netscape.kra; import java.math.BigInteger; import java.security.KeyPair; -import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.KeyPairGeneratorSpi; import org.mozilla.jss.crypto.PrivateKey; @@ -68,7 +67,7 @@ public class AsymKeyGenService implements IService { @Override public boolean serviceRequest(IRequest request) throws EBaseException { - IConfigStore cs = CMS.getConfigStore(); + IConfigStore configStore = CMS.getConfigStore(); String clientKeyId = request.getExtDataInString(IRequest.SECURITY_DATA_CLIENT_KEY_ID); String algorithm = request.getExtDataInString(IRequest.KEY_GEN_ALGORITHM); @@ -77,7 +76,7 @@ public class AsymKeyGenService implements IService { String realm = request.getRealm(); - boolean allowEncDecrypt_archival = cs.getBoolean("kra.allowEncDecrypt.archival", false); + boolean allowEncDecrypt_archival = configStore.getBoolean("kra.allowEncDecrypt.archival", false); KeyPairGeneratorSpi.Usage[] usageList = null; String usageStr = request.getExtDataInString(IRequest.KEY_GEN_USAGES); @@ -130,9 +129,6 @@ public class AsymKeyGenService implements IService { String owner = request.getExtDataInString(IRequest.ATTR_REQUEST_OWNER); String auditSubjectID = owner; - // Get the token - CryptoToken token = kra.getKeygenToken(); - // Generating the asymmetric keys KeyPair kp = null; @@ -162,8 +158,7 @@ public class AsymKeyGenService implements IService { WrappingParams params = null; try { - // TODO(alee) What happens if key wrap algorithm is not supported? - params = storageUnit.getWrappingParams(); + params = storageUnit.getWrappingParams(allowEncDecrypt_archival); privateSecurityData = storageUnit.wrap((PrivateKey) kp.getPrivate(), params); } catch (Exception e) { CMS.debug("Failed to generate security data to archive: " + e); diff --git a/base/kra/src/com/netscape/kra/EncryptionUnit.java b/base/kra/src/com/netscape/kra/EncryptionUnit.java index 02a4ca1..b460c9e 100644 --- a/base/kra/src/com/netscape/kra/EncryptionUnit.java +++ b/base/kra/src/com/netscape/kra/EncryptionUnit.java @@ -67,8 +67,6 @@ public abstract class EncryptionUnit implements IEncryptionUnit { public abstract PrivateKey getPrivateKey(org.mozilla.jss.crypto.X509Certificate cert); - public abstract WrappingParams getWrappingParams() throws Exception; - public WrappingParams getOldWrappingParams() { return new WrappingParams( SymmetricKey.DES3, KeyGenAlgorithm.DES3, 168, diff --git a/base/kra/src/com/netscape/kra/EnrollmentService.java b/base/kra/src/com/netscape/kra/EnrollmentService.java index a200c34..e413a06 100644 --- a/base/kra/src/com/netscape/kra/EnrollmentService.java +++ b/base/kra/src/com/netscape/kra/EnrollmentService.java @@ -396,7 +396,7 @@ public class EnrollmentService implements IService { WrappingParams params = null; try { - params = mStorageUnit.getWrappingParams(); + params = mStorageUnit.getWrappingParams(allowEncDecrypt_archival); if (allowEncDecrypt_archival == true) { privateKeyData = mStorageUnit.encryptInternalPrivate(unwrapped, params); } else { diff --git a/base/kra/src/com/netscape/kra/NetkeyKeygenService.java b/base/kra/src/com/netscape/kra/NetkeyKeygenService.java index f068a4a..636e93e 100644 --- a/base/kra/src/com/netscape/kra/NetkeyKeygenService.java +++ b/base/kra/src/com/netscape/kra/NetkeyKeygenService.java @@ -41,6 +41,7 @@ import org.mozilla.jss.util.Base64OutputStream; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; import com.netscape.certsrv.base.MetaInfo; import com.netscape.certsrv.base.SessionContext; import com.netscape.certsrv.dbs.keydb.IKeyRecord; @@ -155,6 +156,9 @@ public class NetkeyKeygenService implements IService { IVParameterSpec algParam = new IVParameterSpec(iv); + IConfigStore configStore = CMS.getConfigStore(); + boolean allowEncDecrypt_archival = configStore.getBoolean("kra.allowEncDecrypt.archival", false); + wrapped_des_key = null; boolean archive = true; byte[] publicKeyData = null; @@ -405,8 +409,7 @@ public class NetkeyKeygenService implements IService { WrappingParams params = null; try { - // TODO(alee) What happens if key wrap algorithm is not supported? - params = mStorageUnit.getWrappingParams(); + params = mStorageUnit.getWrappingParams(allowEncDecrypt_archival); privateKeyData = mStorageUnit.wrap((org.mozilla.jss.crypto.PrivateKey) privKey, params); } catch (Exception e) { request.setExtData(IRequest.RESULT, Integer.valueOf(4)); diff --git a/base/kra/src/com/netscape/kra/SecurityDataProcessor.java b/base/kra/src/com/netscape/kra/SecurityDataProcessor.java index 701b611..95d07c4 100644 --- a/base/kra/src/com/netscape/kra/SecurityDataProcessor.java +++ b/base/kra/src/com/netscape/kra/SecurityDataProcessor.java @@ -217,7 +217,7 @@ public class SecurityDataProcessor { boolean doEncrypt = false; try { - params = storageUnit.getWrappingParams(); + params = storageUnit.getWrappingParams(allowEncDecrypt_archival); if (securitySymKey != null && unwrapped == null) { privateSecurityData = storageUnit.wrap(securitySymKey, params); } else if (unwrapped != null && allowEncDecrypt_archival == true) { diff --git a/base/kra/src/com/netscape/kra/StorageKeyUnit.java b/base/kra/src/com/netscape/kra/StorageKeyUnit.java index 3e7f1de..1df30f6 100644 --- a/base/kra/src/com/netscape/kra/StorageKeyUnit.java +++ b/base/kra/src/com/netscape/kra/StorageKeyUnit.java @@ -133,7 +133,7 @@ public class StorageKeyUnit extends EncryptionUnit implements throw new EBaseException(CMS.getUserMessage("CMS_INVALID_OPERATION")); } - public WrappingParams getWrappingParams() throws Exception { + public WrappingParams getWrappingParams(boolean encrypt) throws Exception { String choice = null; try { choice = mConfig.getString(PROP_WRAPPING_CHOICE); @@ -177,6 +177,16 @@ public class StorageKeyUnit extends EncryptionUnit implements KeyRecordParser.OUT_PL_WRAP_IV_LEN); if (iv != null) params.setPayloadWrappingIV(new IVParameterSpec(iv)); + if (encrypt) { + // Some HSMs have not yet implemented AES-KW. Use AES-CBC-PAD instead + if (params.getPayloadWrapAlgorithm().equals(KeyWrapAlgorithm.AES_KEY_WRAP) || + params.getPayloadWrapAlgorithm().equals(KeyWrapAlgorithm.AES_KEY_WRAP_PAD)) { + params.setPayloadWrapAlgorithm(KeyWrapAlgorithm.AES_CBC_PAD); + iv = CryptoUtil.getNonceData(16); + params.setPayloadWrappingIV(new IVParameterSpec(iv)); + } + } + return params; } diff --git a/base/kra/src/com/netscape/kra/SymKeyGenService.java b/base/kra/src/com/netscape/kra/SymKeyGenService.java index c1830ec..bf350d5 100644 --- a/base/kra/src/com/netscape/kra/SymKeyGenService.java +++ b/base/kra/src/com/netscape/kra/SymKeyGenService.java @@ -29,6 +29,7 @@ import org.mozilla.jss.crypto.SymmetricKey; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; import com.netscape.certsrv.dbs.keydb.IKeyRecord; import com.netscape.certsrv.dbs.keydb.IKeyRepository; import com.netscape.certsrv.key.KeyRequestResource; @@ -107,6 +108,9 @@ public class SymKeyGenService implements IService { throw new EBaseException("Bad data in SymKeyGenService.serviceRequest"); } + IConfigStore configStore = CMS.getConfigStore(); + boolean allowEncDecrypt_archival = configStore.getBoolean("kra.allowEncDecrypt.archival", false); + CryptoToken token = mStorageUnit.getToken(); KeyGenAlgorithm kgAlg = KeyRequestDAO.SYMKEY_GEN_ALGORITHMS.get(algorithm); if (kgAlg == null) { @@ -170,8 +174,7 @@ public class SymKeyGenService implements IService { } try { - // TODO(alee) what happens if key wrap algorithm is not supported? - params = mStorageUnit.getWrappingParams(); + params = mStorageUnit.getWrappingParams(allowEncDecrypt_archival); privateSecurityData = mStorageUnit.wrap(sk, params); } catch (Exception e) { CMS.debug("Failed to generate security data to archive: " + e); diff --git a/base/kra/src/com/netscape/kra/TransportKeyUnit.java b/base/kra/src/com/netscape/kra/TransportKeyUnit.java index 513c0b2..fc66e66 100644 --- a/base/kra/src/com/netscape/kra/TransportKeyUnit.java +++ b/base/kra/src/com/netscape/kra/TransportKeyUnit.java @@ -115,10 +115,6 @@ public class TransportKeyUnit extends EncryptionUnit implements } } - public WrappingParams getWrappingParams() { - return getOldWrappingParams(); - } - public CryptoToken getInternalToken() { try { return CryptoManager.getInstance().getInternalKeyStorageToken(); -- 1.8.3.1 From 00c17b3e2f81c9df12e1a89fc85dc2e3d4c3a2b1 Mon Sep 17 00:00:00 2001 From: Ade Lee Date: Fri, 5 May 2017 21:30:15 -0400 Subject: [PATCH 09/10] Fix symmetic key retrieval in HSM When using an HSM, AES KeyWrapping is not available and so some different code paths were exercised. Fixing bugs in those paths uncovered a case where we were calling unwrapSymmetric() with bits and not bytes for the key length. This does not matter for 3DES, where JSS expects a length of 0, but very much matters for AES. Fixing this - and the KeyClient to actually use the returned wrapping algorithm to unwrap, allows us now to return generated symmetric keys correctly. Bugzilla BZ#1448521 Pagure: 2690 Change-Id: I2c5c87e28f6f36798b16de238bbaa21da90e7890 --- base/common/src/com/netscape/certsrv/key/KeyClient.java | 4 ++-- base/kra/src/com/netscape/kra/EncryptionUnit.java | 2 +- base/kra/src/com/netscape/kra/SecurityDataProcessor.java | 12 ++++++++++++ base/kra/src/com/netscape/kra/TransportKeyUnit.java | 4 ++-- base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java | 4 ++-- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/base/common/src/com/netscape/certsrv/key/KeyClient.java b/base/common/src/com/netscape/certsrv/key/KeyClient.java index 2c99e1c..9a69372 100644 --- a/base/common/src/com/netscape/certsrv/key/KeyClient.java +++ b/base/common/src/com/netscape/certsrv/key/KeyClient.java @@ -429,7 +429,7 @@ public class KeyClient extends Client { bytes = crypto.unwrapSymmetricKeyWithSessionKey( data.getEncryptedData(), sessionKey, - wrapAlgorithm, + KeyWrapAlgorithm.fromString(data.getWrapAlgorithm()), data.getNonceData(), data.getAlgorithm(), data.getSize()); @@ -446,7 +446,7 @@ public class KeyClient extends Client { bytes = crypto.unwrapAsymmetricKeyWithSessionKey( data.getEncryptedData(), sessionKey, - wrapAlgorithm, + KeyWrapAlgorithm.fromString(data.getWrapAlgorithm()), data.getNonceData(), pubKey); } diff --git a/base/kra/src/com/netscape/kra/EncryptionUnit.java b/base/kra/src/com/netscape/kra/EncryptionUnit.java index b460c9e..eb8a2f8 100644 --- a/base/kra/src/com/netscape/kra/EncryptionUnit.java +++ b/base/kra/src/com/netscape/kra/EncryptionUnit.java @@ -84,7 +84,7 @@ public abstract class EncryptionUnit implements IEncryptionUnit { return CryptoUtil.unwrap( token, params.getSkType(), - 0, + params.getSkType().equals(SymmetricKey.DES3)? 0: params.getSkLength(), usage, wrappingKey, encSymmKey, params.getSkWrapAlgorithm()); diff --git a/base/kra/src/com/netscape/kra/SecurityDataProcessor.java b/base/kra/src/com/netscape/kra/SecurityDataProcessor.java index 95d07c4..344f376 100644 --- a/base/kra/src/com/netscape/kra/SecurityDataProcessor.java +++ b/base/kra/src/com/netscape/kra/SecurityDataProcessor.java @@ -411,6 +411,18 @@ public class SecurityDataProcessor { String payloadWrapName = (String) params.get(IRequest.SECURITY_DATA_PL_WRAPPING_NAME); String transportKeyAlgo = transportUnit.getCertificate().getPublicKey().getAlgorithm(); + if (allowEncDecrypt_recovery) { + if (payloadWrapName == null) { + // assume old client + payloadWrapName = "DES3/CBC/Pad"; + } else if (payloadWrapName.equals("AES KeyWrap/Padding") || + payloadWrapName.equals("AES KeyWrap")) { + // Some HSMs have not implemented AES-KW yet + // Make sure we select an algorithm that is supported. + payloadWrapName = "AES/CBC/PKCS5Padding"; + } + } + byte[] iv = null; byte[] iv_wrap = null; try { diff --git a/base/kra/src/com/netscape/kra/TransportKeyUnit.java b/base/kra/src/com/netscape/kra/TransportKeyUnit.java index fc66e66..d0ad8b3 100644 --- a/base/kra/src/com/netscape/kra/TransportKeyUnit.java +++ b/base/kra/src/com/netscape/kra/TransportKeyUnit.java @@ -289,7 +289,7 @@ public class TransportKeyUnit extends EncryptionUnit implements SymmetricKey sk = CryptoUtil.unwrap( token, params.getSkType(), - 0, + params.getSkType().equals(SymmetricKey.DES3)? 0: params.getSkLength(), SymmetricKey.Usage.DECRYPT, wrappingKey, encSymmKey, @@ -360,7 +360,7 @@ public class TransportKeyUnit extends EncryptionUnit implements SymmetricKey sk = CryptoUtil.unwrap( token, params.getSkType(), - 0, + params.getSkType().equals(SymmetricKey.DES3)? 0: params.getSkLength(), SymmetricKey.Usage.UNWRAP, wrappingKey, encSymmKey, diff --git a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java index d22856d..e529a0f 100644 --- a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java +++ b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java @@ -2346,7 +2346,7 @@ public class CryptoUtil { KeyWrapAlgorithm wrapAlgorithm, IVParameterSpec wrappingIV) throws Exception { KeyWrapper wrapper = token.getKeyWrapper(wrapAlgorithm); wrapper.initUnwrap(wrappingKey, wrappingIV); - return wrapper.unwrapSymmetric(wrappedData, keyType, usage, strength); + return wrapper.unwrapSymmetric(wrappedData, keyType, usage, strength/8); } public static SymmetricKey unwrap(CryptoToken token, SymmetricKey.Type keyType, @@ -2355,7 +2355,7 @@ public class CryptoUtil { KeyWrapper keyWrapper = token.getKeyWrapper(wrapAlgorithm); keyWrapper.initUnwrap(wrappingKey, null); - return keyWrapper.unwrapSymmetric(wrappedData, keyType, usage, strength); + return keyWrapper.unwrapSymmetric(wrappedData, keyType, usage, strength/8); } public static PrivateKey unwrap(CryptoToken token, PublicKey pubKey, boolean temporary, -- 1.8.3.1 From c0bb0ee8e36a85673e30352a7205414b215196a5 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 8 May 2017 18:53:26 +0200 Subject: [PATCH 10/10] pkispawn: wait after final restart The finalization scriptlet now waits after service has been restarted. Change-Id: Id462728386b9d7e6b3364e1651ef6676115dd1de Bugzilla: BZ#1446364 Pagure: 2644 Signed-off-by: Christian Heimes --- .travis/40-spawn-ca | 5 ----- .travis/50-spawn-kra | 5 ----- .../server/python/pki/server/deployment/scriptlets/finalization.py | 7 +++++++ 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/.travis/40-spawn-ca b/.travis/40-spawn-ca index d6771db..d57e6b7 100755 --- a/.travis/40-spawn-ca +++ b/.travis/40-spawn-ca @@ -2,8 +2,3 @@ set -e pkispawn -vv -f ${BUILDDIR}/pki/.travis/pki.cfg -s CA - -echo "Waiting for port 8080" -for i in {1..20}; do - curl http://localhost:8080 && break || sleep 1 -done diff --git a/.travis/50-spawn-kra b/.travis/50-spawn-kra index 93f2f4c..f7e8fc1 100755 --- a/.travis/50-spawn-kra +++ b/.travis/50-spawn-kra @@ -2,8 +2,3 @@ set -e pkispawn -vv -f ${BUILDDIR}/pki/.travis/pki.cfg -s KRA - -echo "Waiting for port 8080" -for i in {1..20}; do - curl http://localhost:8080 && break || sleep 1 -done diff --git a/base/server/python/pki/server/deployment/scriptlets/finalization.py b/base/server/python/pki/server/deployment/scriptlets/finalization.py index 3dc7f66..941691c 100644 --- a/base/server/python/pki/server/deployment/scriptlets/finalization.py +++ b/base/server/python/pki/server/deployment/scriptlets/finalization.py @@ -57,6 +57,13 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet): # Optionally, programmatically 'restart' the configured PKI instance if config.str2bool(deployer.mdict['pki_restart_configured_instance']): deployer.systemd.restart() + # wait for startup + status = deployer.instance.wait_for_startup(60) + if status is None: + config.pki_log.error( + "server failed to restart", + extra=config.PKI_INDENTATION_LEVEL_1) + raise RuntimeError("server failed to restart") # Optionally, 'purge' the entire temporary client infrastructure # including the client NSS security databases and password files -- 1.8.3.1