/* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*/ | |
package org.apache.karaf.shell.ssh; | |
import java.io.BufferedReader; | |
import java.io.BufferedWriter; | |
import java.io.Closeable; | |
import java.io.File; | |
import java.io.FileReader; | |
import java.io.FileWriter; | |
import java.io.IOException; | |
import java.net.InetSocketAddress; | |
import java.net.SocketAddress; | |
import java.security.KeyFactory; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.PublicKey; | |
import java.security.spec.InvalidKeySpecException; | |
import java.security.spec.X509EncodedKeySpec; | |
import org.apache.sshd.common.util.Base64; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
public class KnownHostsManager { | |
Logger LOG = LoggerFactory.getLogger(KnownHostsManager.class); | |
private final File knownHosts; | |
public KnownHostsManager(File knownHosts) { | |
this.knownHosts = knownHosts; | |
this.knownHosts.getParentFile().mkdirs(); | |
if (!this.knownHosts.exists()) { | |
try { | |
knownHosts.createNewFile(); | |
} catch (IOException e) { | |
throw new RuntimeException("Error creating file for known hosts at: " + knownHosts); | |
} | |
} | |
} | |
public PublicKey getKnownKey(SocketAddress remoteAddress, String checkAlgorithm) throws InvalidKeySpecException { | |
FileReader fr = null; | |
BufferedReader reader = null; | |
try { | |
fr = new FileReader(knownHosts); | |
reader = new BufferedReader(fr); | |
return getKnownKeyInternal(remoteAddress, checkAlgorithm, reader); | |
} catch (IOException e) { | |
throw new RuntimeException("Error reading known_hosts " + knownHosts, e); | |
} catch (NoSuchAlgorithmException e) { | |
throw new RuntimeException(e); | |
} finally { | |
close(reader); | |
close(fr); | |
} | |
} | |
private PublicKey getKnownKeyInternal(SocketAddress remoteAddress, | |
String checkAlgorithm, BufferedReader reader) throws IOException, | |
NoSuchAlgorithmException, InvalidKeySpecException { | |
String checkServerAddress = getAddressString(remoteAddress); | |
String line = reader.readLine(); | |
while (line != null) { | |
String[] lineParts = line.split(" "); | |
String serverAddress = lineParts[0]; | |
String algorithm = lineParts[1]; | |
if (checkServerAddress.equals(serverAddress) && checkAlgorithm.equals(algorithm)) { | |
byte[] key = Base64.decodeBase64(lineParts[2].getBytes()); | |
KeyFactory keyFactory = KeyFactory.getInstance(algorithm); | |
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(key); | |
return keyFactory.generatePublic(keySpec); | |
} | |
line = reader.readLine(); | |
} | |
return null; | |
} | |
public void storeKeyForHost(SocketAddress remoteAddress, | |
PublicKey serverKey) { | |
FileWriter ps = null; | |
BufferedWriter bw = null; | |
try { | |
ps = new FileWriter(knownHosts, true); | |
bw = new BufferedWriter(ps); | |
writeKey(bw, remoteAddress, serverKey); | |
} catch (Exception e) { | |
throw new RuntimeException("Error storing key for host" + remoteAddress, e); | |
} finally { | |
close(bw); | |
close(ps); | |
} | |
} | |
private void writeKey(BufferedWriter bw, SocketAddress remoteAddress, | |
PublicKey serverKey) throws IOException { | |
bw.append(getAddressString(remoteAddress)); | |
bw.append(" "); | |
bw.append(serverKey.getAlgorithm()); | |
bw.append(" "); | |
serverKey.getEncoded(); | |
bw.append(new String(Base64.encodeBase64(serverKey.getEncoded()), | |
"UTF-8")); | |
bw.append("\n"); | |
} | |
String getAddressString(SocketAddress address) { | |
if (address instanceof InetSocketAddress) { | |
InetSocketAddress inetAddress = (InetSocketAddress) address; | |
return String.format("%s,%s:%s", inetAddress.getHostName(), | |
inetAddress.getAddress().getHostAddress(), | |
inetAddress.getPort()); | |
} | |
return ""; | |
} | |
private void close(Closeable closeable) { | |
if (closeable != null) { | |
try { | |
closeable.close(); | |
} catch (IOException e) { | |
LOG.warn("Error closing: " + e.getMessage(), e); | |
} | |
} | |
} | |
} |