From 34fe6c81202a4ba7d3f3788193fe3d93faeaceff Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Tue, 31 May 2016 16:10:05 +1000 Subject: [PATCH 120/121] Lightweight CAs: generalise subprocess-based key retrieval The IPACustodiaKeyRetriever doesn't really do anything specific to IPA or Custodia; it merely executes a certain executable with a particular behavioural contract. Add support for passing configuration to KeyRetriever instances, and rename IPACustodiaKeyRetriever to ExternalProcessKeyRetriever, updating it to use the "executable" config property instead of a hardcoded filename. Part of: https://fedorahosted.org/pki/ticket/1625 --- .../src/com/netscape/ca/CertificateAuthority.java | 24 +++++++++++++--- ...iever.java => ExternalProcessKeyRetriever.java} | 33 ++++++++++++++++------ 2 files changed, 45 insertions(+), 12 deletions(-) rename base/ca/src/com/netscape/ca/{IPACustodiaKeyRetriever.java => ExternalProcessKeyRetriever.java} (71%) diff --git a/base/ca/src/com/netscape/ca/CertificateAuthority.java b/base/ca/src/com/netscape/ca/CertificateAuthority.java index 5b2f382c29a716f3e72695b7da5406bb85b34845..6ba9ffed3736f38e4ee1fbf3fb058fdf62dac9f9 100644 --- a/base/ca/src/com/netscape/ca/CertificateAuthority.java +++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java @@ -24,6 +24,7 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintStream; +import java.lang.reflect.InvocationTargetException; import java.math.BigInteger; import java.security.KeyPair; import java.security.MessageDigest; @@ -3181,6 +3182,8 @@ public class CertificateAuthority public void run() { String KR_CLASS_KEY = "features.authority.keyRetrieverClass"; + String KR_CONFIG_KEY = "features.authority.keyRetrieverConfig"; + String className = null; try { className = CMS.getConfigStore().getString(KR_CLASS_KEY); @@ -3189,11 +3192,23 @@ public class CertificateAuthority return; } + IConfigStore krConfig = CMS.getConfigStore().getSubStore(KR_CONFIG_KEY); + KeyRetriever kr = null; try { - kr = Class.forName(className) - .asSubclass(KeyRetriever.class) - .newInstance(); + Class cls = + Class.forName(className).asSubclass(KeyRetriever.class); + + // If there is an accessible constructor that takes + // an IConfigStore, invoke that; otherwise invoke + // the nullary constructor. + try { + kr = cls.getDeclaredConstructor(IConfigStore.class) + .newInstance(krConfig); + } catch (NoSuchMethodException | SecurityException + | IllegalAccessException e) { + kr = cls.newInstance(); + } } catch (ClassNotFoundException e) { CMS.debug("Could not find class: " + className); CMS.debug(e); @@ -3202,7 +3217,8 @@ public class CertificateAuthority CMS.debug("Class is not an instance of KeyRetriever: " + className); CMS.debug(e); return; - } catch (InstantiationException | IllegalAccessException e) { + } catch (InstantiationException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException e) { CMS.debug("Could not instantiate class: " + className); CMS.debug(e); return; diff --git a/base/ca/src/com/netscape/ca/IPACustodiaKeyRetriever.java b/base/ca/src/com/netscape/ca/ExternalProcessKeyRetriever.java similarity index 71% rename from base/ca/src/com/netscape/ca/IPACustodiaKeyRetriever.java rename to base/ca/src/com/netscape/ca/ExternalProcessKeyRetriever.java index 4a162d3702fccc19dfef792a5213c653286930f3..6aee9716e1e5953018ed4c3f3316c9b7d4c88a45 100644 --- a/base/ca/src/com/netscape/ca/IPACustodiaKeyRetriever.java +++ b/base/ca/src/com/netscape/ca/ExternalProcessKeyRetriever.java @@ -27,13 +27,32 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang.ArrayUtils; import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.EPropertyNotFound; +import com.netscape.certsrv.base.IConfigStore; + + +public class ExternalProcessKeyRetriever implements KeyRetriever { + protected String executable; + + public ExternalProcessKeyRetriever(IConfigStore config) { + if (config == null) + throw new IllegalArgumentException("Missing config"); + + try { + this.executable = config.getString("executable"); + } catch (EPropertyNotFound e) { + throw new IllegalArgumentException("Missing 'executable' config property"); + } catch (EBaseException e) { + throw new RuntimeException(e); + } + } -public class IPACustodiaKeyRetriever implements KeyRetriever { public Result retrieveKey(String nickname, Collection hostPorts) { - CMS.debug("Running IPACustodiaKeyRetriever"); + CMS.debug("Running ExternalProcessKeyRetriever"); Stack command = new Stack<>(); - command.push("/usr/libexec/pki-ipa-retrieve-key"); + command.push(this.executable); command.push(nickname); for (String hostPort : hostPorts) { @@ -47,11 +66,9 @@ public class IPACustodiaKeyRetriever implements KeyRetriever { if (exitValue != 0) continue; - /* Custodia returns a PEM-encoded certificate and a - * base64-encoded PKIArchiveOptions containing the - * wrapped private key. These values are output by - * the Python 'pki-ipa-retrieve-key' program, - * separated by a null byte (password first) + /* Read a PEM-encoded certificate and a base64-encoded + * PKIArchiveOptions containing the wrapped private key, + * separated by a null byte. */ byte[] output = IOUtils.toByteArray(p.getInputStream()); int splitIndex = ArrayUtils.indexOf(output, (byte) 0); -- 2.5.5