Merge pull request #271 from joval/master

Gracefully load OpenSSH known_hosts without requiring BouncyCastle
This commit is contained in:
Jeroen van Erp
2016-09-13 15:21:09 +02:00
committed by GitHub
4 changed files with 43 additions and 44 deletions

View File

@@ -426,8 +426,7 @@ public class Buffer<T extends Buffer<T>> {
public PublicKey readPublicKey() public PublicKey readPublicKey()
throws BufferException { throws BufferException {
try { try {
final String type = readString(); return KeyType.fromString(readString()).readPubKeyFromBuffer(this);
return KeyType.fromString(type).readPubKeyFromBuffer(type, this);
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
throw new SSHRuntimeException(e); throw new SSHRuntimeException(e);
} }

View File

@@ -46,7 +46,7 @@ public enum KeyType {
/** SSH identifier for RSA keys */ /** SSH identifier for RSA keys */
RSA("ssh-rsa") { RSA("ssh-rsa") {
@Override @Override
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf) public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException { throws GeneralSecurityException {
final BigInteger e, n; final BigInteger e, n;
try { try {
@@ -77,7 +77,7 @@ public enum KeyType {
/** SSH identifier for DSA keys */ /** SSH identifier for DSA keys */
DSA("ssh-dss") { DSA("ssh-dss") {
@Override @Override
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf) public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException { throws GeneralSecurityException {
BigInteger p, q, g, y; BigInteger p, q, g, y;
try { try {
@@ -114,8 +114,11 @@ public enum KeyType {
private final Logger log = LoggerFactory.getLogger(getClass()); private final Logger log = LoggerFactory.getLogger(getClass());
@Override @Override
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf) public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException { throws GeneralSecurityException {
if (!SecurityUtils.isBouncyCastleRegistered()) {
throw new GeneralSecurityException("BouncyCastle is required to read a key of type " + sType);
}
try { try {
// final String algo = buf.readString(); it has been already read // final String algo = buf.readString(); it has been already read
final String curveName = buf.readString(); final String curveName = buf.readString();
@@ -127,7 +130,7 @@ public enum KeyType {
buf.readRawBytes(y); buf.readRawBytes(y);
if(log.isDebugEnabled()) { if(log.isDebugEnabled()) {
log.debug(String.format("Key algo: %s, Key curve: %s, Key Len: %s, 0x04: %s\nx: %s\ny: %s", log.debug(String.format("Key algo: %s, Key curve: %s, Key Len: %s, 0x04: %s\nx: %s\ny: %s",
type, sType,
curveName, curveName,
keyLen, keyLen,
x04, x04,
@@ -176,14 +179,14 @@ public enum KeyType {
ED25519("ssh-ed25519") { ED25519("ssh-ed25519") {
private final Logger log = LoggerFactory.getLogger(KeyType.class); private final Logger log = LoggerFactory.getLogger(KeyType.class);
@Override @Override
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf) throws GeneralSecurityException { public PublicKey readPubKeyFromBuffer(Buffer<?> buf) throws GeneralSecurityException {
try { try {
final int keyLen = buf.readUInt32AsInt(); final int keyLen = buf.readUInt32AsInt();
final byte[] p = new byte[keyLen]; final byte[] p = new byte[keyLen];
buf.readRawBytes(p); buf.readRawBytes(p);
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug(String.format("Key algo: %s, Key curve: 25519, Key Len: %s\np: %s", log.debug(String.format("Key algo: %s, Key curve: 25519, Key Len: %s\np: %s",
type, sType,
keyLen, keyLen,
Arrays.toString(p)) Arrays.toString(p))
); );
@@ -213,9 +216,9 @@ public enum KeyType {
/** Unrecognized */ /** Unrecognized */
UNKNOWN("unknown") { UNKNOWN("unknown") {
@Override @Override
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf) public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException { throws GeneralSecurityException {
throw new UnsupportedOperationException("Don't know how to decode key:" + type); throw new UnsupportedOperationException("Don't know how to decode key:" + sType);
} }
@Override @Override
@@ -238,7 +241,7 @@ public enum KeyType {
this.sType = type; this.sType = type;
} }
public abstract PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf) public abstract PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException; throws GeneralSecurityException;
public abstract void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf); public abstract void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf);
@@ -263,5 +266,4 @@ public enum KeyType {
public String toString() { public String toString() {
return sType; return sType;
} }
} }

View File

@@ -57,7 +57,7 @@ public class OpenSSHKnownHosts
try { try {
// Read in the file, storing each line as an entry // Read in the file, storing each line as an entry
String line; String line;
while ((line = br.readLine()) != null) while ((line = br.readLine()) != null) {
try { try {
HostEntry entry = entryFactory.parseEntry(line); HostEntry entry = entryFactory.parseEntry(line);
if (entry != null) { if (entry != null) {
@@ -65,7 +65,10 @@ public class OpenSSHKnownHosts
} }
} catch (SSHException ignore) { } catch (SSHException ignore) {
log.debug("Bad line ({}): {} ", ignore.toString(), line); log.debug("Bad line ({}): {} ", ignore.toString(), line);
} catch (SSHRuntimeException ignore) {
log.debug("Failed to process line ({}): {} ", ignore.toString(), line);
} }
}
} finally { } finally {
IOUtils.closeQuietly(br); IOUtils.closeQuietly(br);
} }
@@ -207,7 +210,7 @@ public class OpenSSHKnownHosts
if (type != KeyType.UNKNOWN) { if (type != KeyType.UNKNOWN) {
final String sKey = split[i++]; final String sKey = split[i++];
key = getKey(sKey); key = new Buffer.PlainBuffer(Base64.decode(sKey)).readPublicKey();
} else if (isBits(sType)) { } else if (isBits(sType)) {
type = KeyType.RSA; type = KeyType.RSA;
// int bits = Integer.valueOf(sType); // int bits = Integer.valueOf(sType);
@@ -232,11 +235,6 @@ public class OpenSSHKnownHosts
} }
} }
private PublicKey getKey(String sKey)
throws IOException {
return new Buffer.PlainBuffer(Base64.decode(sKey)).readPublicKey();
}
private boolean isBits(String type) { private boolean isBits(String type) {
try { try {
Integer.parseInt(type); Integer.parseInt(type);

View File

@@ -194,31 +194,31 @@ public class PKCS5KeyFile
throw new FormatException("PKCS5 header not found"); throw new FormatException("PKCS5 header not found");
} }
ASN1Data asn = new ASN1Data(data = decrypt(Base64.decode(sb.toString()), cipher, iv)); ASN1Data asn = new ASN1Data(data = decrypt(Base64.decode(sb.toString()), cipher, iv));
switch(type) { switch (type) {
case RSA: { case RSA: {
KeyFactory factory = KeyFactory.getInstance("RSA"); KeyFactory factory = KeyFactory.getInstance("RSA");
asn.readNext(); asn.readNext();
BigInteger modulus = asn.readNext(); BigInteger modulus = asn.readNext();
BigInteger pubExp = asn.readNext(); BigInteger pubExp = asn.readNext();
BigInteger prvExp = asn.readNext(); BigInteger prvExp = asn.readNext();
PublicKey pubKey = factory.generatePublic(new RSAPublicKeySpec(modulus, pubExp)); PublicKey pubKey = factory.generatePublic(new RSAPublicKeySpec(modulus, pubExp));
PrivateKey prvKey = factory.generatePrivate(new RSAPrivateKeySpec(modulus, prvExp)); PrivateKey prvKey = factory.generatePrivate(new RSAPrivateKeySpec(modulus, prvExp));
return new KeyPair(pubKey, prvKey); return new KeyPair(pubKey, prvKey);
} }
case DSA: { case DSA: {
KeyFactory factory = KeyFactory.getInstance("DSA"); KeyFactory factory = KeyFactory.getInstance("DSA");
asn.readNext(); asn.readNext();
BigInteger p = asn.readNext(); BigInteger p = asn.readNext();
BigInteger q = asn.readNext(); BigInteger q = asn.readNext();
BigInteger g = asn.readNext(); BigInteger g = asn.readNext();
BigInteger pub = asn.readNext(); BigInteger pub = asn.readNext();
BigInteger prv = asn.readNext(); BigInteger prv = asn.readNext();
PublicKey pubKey = factory.generatePublic(new DSAPublicKeySpec(pub, p, q, g)); PublicKey pubKey = factory.generatePublic(new DSAPublicKeySpec(pub, p, q, g));
PrivateKey prvKey = factory.generatePrivate(new DSAPrivateKeySpec(prv, p, q, g)); PrivateKey prvKey = factory.generatePrivate(new DSAPrivateKeySpec(prv, p, q, g));
return new KeyPair(pubKey, prvKey); return new KeyPair(pubKey, prvKey);
} }
default: default:
throw new IOException("Unrecognized PKCS5 key type: " + type); throw new IOException("Unrecognized PKCS5 key type: " + type);
} }
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
throw new IOException(e); throw new IOException(e);