NETCONF-527 Holding of key-pair in memory 81/80981/1
authorJaroslav Tóth <jtoth@frinx.io>
Tue, 19 Mar 2019 09:28:18 +0000 (10:28 +0100)
committerJaroslav Tóth <jtoth@frinx.io>
Tue, 19 Mar 2019 09:28:18 +0000 (10:28 +0100)
- Generated key-pair is not saved in file but rather kept only in
  memory.
- Created VirtualKeyPairProvider that allows creation of only one
  key-pair that is returned in loadKeys(..) method.

Change-Id: If51f7ae7205bfa85c95649ce327fc01d276c0e6b
Signed-off-by: Jaroslav Tóth <jtoth@frinx.io>
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/NetconfDeviceSimulator.java
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/VirtualKeyPairProvider.java [new file with mode: 0644]

index 321b202604968b3a65d4339c71c2475fd03a0a3f..35625ab30e4db52b735e22c3231c0e5f8bb6847b 100644 (file)
@@ -29,8 +29,6 @@ import java.net.Inet4Address;
 import java.net.InetSocketAddress;
 import java.net.UnknownHostException;
 import java.nio.channels.AsynchronousChannelGroup;
-import java.nio.file.Files;
-import java.nio.file.Path;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
@@ -38,7 +36,6 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
-import org.apache.sshd.common.util.security.SecurityUtils;
 import org.apache.sshd.common.util.threads.ThreadUtils;
 import org.opendaylight.netconf.api.capability.BasicCapability;
 import org.opendaylight.netconf.api.capability.Capability;
@@ -191,7 +188,7 @@ public class NetconfDeviceSimulator implements Closeable {
         final List<Integer> openDevices = Lists.newArrayList();
 
         // Generate key to temp folder
-        final KeyPairProvider keyPairProvider = getPemGeneratorHostKeyProvider();
+        final KeyPairProvider keyPairProvider = new VirtualKeyPairProvider();
 
         final AsynchronousChannelGroup group;
         try {
@@ -288,16 +285,6 @@ public class NetconfDeviceSimulator implements Closeable {
                 .createSshProxyServerConfiguration();
     }
 
-    private static KeyPairProvider getPemGeneratorHostKeyProvider() {
-        try {
-            final Path tempFile = Files.createTempFile("tempKeyNetconfTest", "suffix");
-            return SecurityUtils.createGeneratorHostKeyProvider(tempFile.toAbsolutePath());
-        } catch (final IOException e) {
-            LOG.error("Unable to generate PEM key", e);
-            throw new RuntimeException(e);
-        }
-    }
-
     private Set<Capability> parseSchemasToModuleCapabilities(final SharedSchemaRepository consumer) {
         final Set<SourceIdentifier> loadedSources = Sets.newHashSet();
         consumer.registerSchemaSourceListener(TextToASTTransformer.create(consumer, consumer));
diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/VirtualKeyPairProvider.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/VirtualKeyPairProvider.java
new file mode 100644 (file)
index 0000000..d50f536
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright © 2019 FRINX s.r.o. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netconf.test.tool;
+
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Collections;
+import java.util.Objects;
+import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.util.security.SecurityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Key provider that allows to create exactly one key-pair in memory (key-pair is not persisted in memory).
+ * If the key-pair has already been generated, the existing one is used.
+ */
+public class VirtualKeyPairProvider implements KeyPairProvider {
+
+    private static final Logger LOG = LoggerFactory.getLogger(VirtualKeyPairProvider.class);
+
+    private KeyPair generatedKeyPair;
+    private String algorithm = KeyUtils.RSA_ALGORITHM;
+    private AlgorithmParameterSpec keySpecification;
+    private Integer keySize;
+
+    /**
+     * Creation of the key-provider with default settings - RSA algorithm with key length of 2048.
+     *
+     * @see VirtualKeyPairProvider#VirtualKeyPairProvider(String, AlgorithmParameterSpec, Integer)
+     */
+    VirtualKeyPairProvider() {
+    }
+
+    /**
+     * Creation of the key-provider with explicitly defined algorithmic settings.
+     *
+     * @param algorithm        Algorithm that is used for generation of a new key-pair. Currently supported algorithms:
+     *                         {@link KeyUtils#RSA_ALGORITHM}, {@link KeyUtils#DSS_ALGORITHM},
+     *                         {@link KeyUtils#EC_ALGORITHM}.
+     * @param keySpecification Algorithm-specific settings.
+     * @param keySize          To be generated key length (must be adjusted against selected algorithm).
+     */
+    @SuppressWarnings({"unused", "WeakerAccess"})
+    VirtualKeyPairProvider(final String algorithm,
+                           final AlgorithmParameterSpec keySpecification,
+                           final Integer keySize) {
+        this.algorithm = algorithm;
+        this.keySpecification = keySpecification;
+        this.keySize = keySize;
+    }
+
+    @Override
+    public synchronized Iterable<KeyPair> loadKeys() {
+        if (Objects.isNull(generatedKeyPair)) {
+            try {
+                generatedKeyPair = generateKeyPair();
+            } catch (GeneralSecurityException exception) {
+                LOG.error("Cannot generate key with algorithm '{}', key specification '{}', and key size '{}'.",
+                        algorithm, keySpecification, keySize, exception);
+                throw new IllegalArgumentException("An error occurred during generation of a new ke pair.", exception);
+            }
+        } else {
+            return Collections.singleton(generatedKeyPair);
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Generating of the new key-pair using specified parameters - algorithm, key length, and key specification.
+     *
+     * @return Generated key-pair.
+     * @throws GeneralSecurityException If the generation process fails because of the wrong input parameters.
+     */
+    private KeyPair generateKeyPair() throws GeneralSecurityException {
+        final KeyPairGenerator generator = SecurityUtils.getKeyPairGenerator(algorithm);
+        if (Objects.nonNull(keySpecification)) {
+            generator.initialize(keySpecification);
+        } else if (Objects.nonNull(keySize)) {
+            generator.initialize(keySize);
+        } else if (KeyUtils.EC_ALGORITHM.equals(algorithm)) {
+            int numCurves = ECCurves.SORTED_KEY_SIZE.size();
+            ECCurves curve = ECCurves.SORTED_KEY_SIZE.get(numCurves - 1);
+            generator.initialize(curve.getParameters());
+        }
+        return generator.generateKeyPair();
+    }
+}
\ No newline at end of file