Fix for ONOS-6766: "NETCONF: Exception when using SSH keys and Apache Mina SSHD"
Modified SSH key handling. Now using BouncyCastle. (Update #2)
Change-Id: I27d8aefba6ed5548b9caa592fb5787cf98dfb5b6
diff --git a/protocols/netconf/ctl/BUCK b/protocols/netconf/ctl/BUCK
index 2d79045..8abf233 100644
--- a/protocols/netconf/ctl/BUCK
+++ b/protocols/netconf/ctl/BUCK
@@ -6,6 +6,8 @@
'//cli:onos-cli',
'//lib:org.apache.karaf.shell.console',
'//lib:sshd-core',
+ '//lib:bcpkix-jdk15on',
+ '//lib:bcprov-jdk15on',
]
TEST_DEPS = [
diff --git a/protocols/netconf/ctl/pom.xml b/protocols/netconf/ctl/pom.xml
index c4108ae..0306e181 100644
--- a/protocols/netconf/ctl/pom.xml
+++ b/protocols/netconf/ctl/pom.xml
@@ -78,6 +78,18 @@
<artifactId>org.apache.karaf.shell.console</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-jdk15on</artifactId>
+ <version>1.58</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ <version>1.58</version>
+ </dependency>
+
</dependencies>
<build>
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfControllerImpl.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfControllerImpl.java
index daba5be..a1797d7 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfControllerImpl.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfControllerImpl.java
@@ -24,6 +24,7 @@
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.onlab.packet.IpAddress;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.net.AnnotationKeys;
@@ -49,6 +50,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.security.Security;
import java.util.Arrays;
import java.util.Dictionary;
import java.util.Map;
@@ -128,6 +130,7 @@
public void activate(ComponentContext context) {
cfgService.registerProperties(getClass());
modified(context);
+ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
log.info("Started");
}
@@ -140,6 +143,7 @@
cfgService.unregisterProperties(getClass(), false);
netconfDeviceListeners.clear();
netconfDeviceMap.clear();
+ Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
log.info("Stopped");
}
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java
index 357ae16..241ea23 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java
@@ -28,6 +28,10 @@
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.FactoryManager;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.PEMKeyPair;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.onosproject.netconf.DatastoreId;
import org.onosproject.netconf.NetconfDeviceInfo;
import org.onosproject.netconf.NetconfDeviceOutputEvent;
@@ -39,12 +43,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
import static java.nio.charset.StandardCharsets.UTF_8;
+import java.io.CharArrayReader;
import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
@@ -208,23 +211,15 @@
session = connectFuture.getSession();
//Using the device ssh key if possible
if (deviceInfo.getKey() != null) {
- ByteBuffer buf = StandardCharsets.UTF_8.encode(CharBuffer.wrap(deviceInfo.getKey()));
- byte[] byteKey = new byte[buf.limit()];
- buf.get(byteKey);
- PublicKey key;
+ PEMParser pemParser = new PEMParser(new CharArrayReader(deviceInfo.getKey()));
+ JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME);
try {
- key = getPublicKey(byteKey, RSA);
- } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
- try {
- key = getPublicKey(byteKey, DSA);
- } catch (NoSuchAlgorithmException | InvalidKeySpecException e1) {
- throw new NetconfException("Failed to authenticate session with device " +
- deviceInfo + "check key to be the " +
- "proper DSA or RSA key", e1);
- }
+ KeyPair kp = converter.getKeyPair((PEMKeyPair) pemParser.readObject());
+ session.addPublicKeyIdentity(kp);
+ } catch (java.io.IOException e) {
+ throw new NetconfException("Failed to authenticate session with device " +
+ deviceInfo + "check key to be a valid key", e);
}
- //privateKye can set tu null because is not used by the method.
- session.addPublicKeyIdentity(new KeyPair(key, null));
} else {
session.addPasswordIdentity(deviceInfo.password());
}