mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-07 15:50:57 +03:00
Merge branch 'master' into issue-358
This commit is contained in:
@@ -23,6 +23,9 @@ import net.schmizz.sshj.signature.SignatureRSA;
|
||||
import net.schmizz.sshj.transport.random.JCERandom;
|
||||
import net.schmizz.sshj.transport.random.SingletonRandomFactory;
|
||||
|
||||
/**
|
||||
* Registers SpongyCastle as JCE provider.
|
||||
*/
|
||||
public class AndroidConfig
|
||||
extends DefaultConfig {
|
||||
|
||||
@@ -30,13 +33,6 @@ public class AndroidConfig
|
||||
SecurityUtils.registerSecurityProvider("org.spongycastle.jce.provider.BouncyCastleProvider");
|
||||
}
|
||||
|
||||
public AndroidConfig(){
|
||||
super();
|
||||
initKeyExchangeFactories(true);
|
||||
initRandomFactory(true);
|
||||
initFileKeyProviderFactories(true);
|
||||
}
|
||||
|
||||
// don't add ECDSA
|
||||
protected void initSignatureFactories() {
|
||||
setSignatureFactories(new SignatureRSA.Factory(), new SignatureDSA.Factory(),
|
||||
|
||||
@@ -92,7 +92,7 @@ public class DefaultConfig
|
||||
properties.load(DefaultConfig.class.getClassLoader().getResourceAsStream("sshj.properties"));
|
||||
String property = properties.getProperty("sshj.version");
|
||||
return "SSHJ_" + property.replace('-', '_'); // '-' is a disallowed character, see RFC-4253#section-4.2
|
||||
} catch (IOException e) {
|
||||
} catch (Exception e) {
|
||||
log.error("Could not read the sshj.properties file, returning an 'unknown' version as fallback.");
|
||||
return "SSHJ_VERSION_UNKNOWN";
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -460,10 +460,13 @@ public class Buffer<T extends Buffer<T>> {
|
||||
|
||||
public PublicKey readPublicKey()
|
||||
throws BufferException {
|
||||
KeyType keyType = KeyType.fromString(readString());
|
||||
try {
|
||||
return KeyType.fromString(readString()).readPubKeyFromBuffer(this);
|
||||
return keyType.readPubKeyFromBuffer(this);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new SSHRuntimeException(e);
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
throw new BufferException("Could not decode keytype " + keyType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,11 +18,21 @@ package net.schmizz.sshj.common;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.Provider;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Security;
|
||||
import java.security.Signature;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyAgreement;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import java.security.*;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
@@ -37,12 +47,17 @@ public class SecurityUtils {
|
||||
*/
|
||||
public static final String BOUNCY_CASTLE = "BC";
|
||||
|
||||
/**
|
||||
* Identifier for the BouncyCastle JCE provider
|
||||
*/
|
||||
public static final String SPONGY_CASTLE = "SC";
|
||||
|
||||
/*
|
||||
* Security provider identifier. null = default JCE
|
||||
*/
|
||||
private static String securityProvider = null;
|
||||
|
||||
// relate to BC registration
|
||||
// relate to BC registration (or SpongyCastle on Android)
|
||||
private static Boolean registerBouncyCastle;
|
||||
private static boolean registrationDone;
|
||||
|
||||
@@ -82,6 +97,8 @@ public class SecurityUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static synchronized Cipher getCipher(String transformation)
|
||||
throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException {
|
||||
register();
|
||||
@@ -222,11 +239,11 @@ public class SecurityUtils {
|
||||
* Attempts registering BouncyCastle as security provider if it has not been previously attempted and returns
|
||||
* whether the registration succeeded.
|
||||
*
|
||||
* @return whether BC registered
|
||||
* @return whether BC (or SC on Android) registered
|
||||
*/
|
||||
public static synchronized boolean isBouncyCastleRegistered() {
|
||||
register();
|
||||
return BOUNCY_CASTLE.equals(securityProvider);
|
||||
return BOUNCY_CASTLE.equals(securityProvider) || SPONGY_CASTLE.equals(securityProvider);
|
||||
}
|
||||
|
||||
public static synchronized void setRegisterBouncyCastle(boolean registerBouncyCastle) {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C)2009 - SSHJ Contributors
|
||||
*
|
||||
* Licensed 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 net.schmizz.sshj.transport.mac;
|
||||
|
||||
public class HMACRIPEMD160 extends BaseMAC {
|
||||
/** Named factory for the HMAC-SHA1 <code>MAC</code> */
|
||||
public static class Factory
|
||||
implements net.schmizz.sshj.common.Factory.Named<MAC> {
|
||||
|
||||
@Override
|
||||
public MAC create() {
|
||||
return new HMACRIPEMD160();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "hmac-ripemd160";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public HMACRIPEMD160() {
|
||||
super("HMACRIPEMD160", 20, 20);
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ public class ConsoleKnownHostsVerifier
|
||||
protected boolean hostKeyUnverifiableAction(String hostname, PublicKey key) {
|
||||
final KeyType type = KeyType.fromKey(key);
|
||||
console.printf("The authenticity of host '%s' can't be established.\n" +
|
||||
"%s key fingerprint is %s.\n", hostname, type, SecurityUtils.getFingerprint(key));
|
||||
"%s key fingerprint is %s.\n", hostname, type, SecurityUtils.getFingerprint(key));
|
||||
String response = console.readLine("Are you sure you want to continue connecting (yes/no)? ");
|
||||
while (!(response.equalsIgnoreCase(YES) || response.equalsIgnoreCase(NO))) {
|
||||
response = console.readLine("Please explicitly enter yes/no: ");
|
||||
@@ -60,7 +60,7 @@ public class ConsoleKnownHostsVerifier
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hostKeyChangedAction(KnownHostEntry entry, String hostname, PublicKey key) {
|
||||
protected boolean hostKeyChangedAction(String hostname, PublicKey key) {
|
||||
final KeyType type = KeyType.fromKey(key);
|
||||
final String fp = SecurityUtils.getFingerprint(key);
|
||||
final String path = getFile().getAbsolutePath();
|
||||
|
||||
@@ -87,14 +87,23 @@ public class OpenSSHKnownHosts
|
||||
|
||||
final String adjustedHostname = (port != 22) ? "[" + hostname + "]:" + port : hostname;
|
||||
|
||||
boolean foundApplicableHostEntry = false;
|
||||
for (KnownHostEntry e : entries) {
|
||||
try {
|
||||
if (e.appliesTo(type, adjustedHostname))
|
||||
return e.verify(key) || hostKeyChangedAction(e, adjustedHostname, key);
|
||||
if (e.appliesTo(type, adjustedHostname)) {
|
||||
foundApplicableHostEntry = true;
|
||||
if (e.verify(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
log.error("Error with {}: {}", e, ioe);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
if (foundApplicableHostEntry) {
|
||||
return hostKeyChangedAction(adjustedHostname, key);
|
||||
}
|
||||
|
||||
return hostKeyUnverifiableAction(adjustedHostname, key);
|
||||
@@ -104,7 +113,7 @@ public class OpenSSHKnownHosts
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean hostKeyChangedAction(KnownHostEntry entry, String hostname, PublicKey key) {
|
||||
protected boolean hostKeyChangedAction(String hostname, PublicKey key) {
|
||||
log.warn("Host key for `{}` has changed!", hostname);
|
||||
return false;
|
||||
}
|
||||
@@ -199,7 +208,7 @@ public class OpenSSHKnownHosts
|
||||
}
|
||||
if(split.length < 3) {
|
||||
log.error("Error reading entry `{}`", line);
|
||||
return null;
|
||||
return new BadHostEntry(line);
|
||||
}
|
||||
final String hostnames = split[i++];
|
||||
final String sType = split[i++];
|
||||
@@ -209,7 +218,13 @@ public class OpenSSHKnownHosts
|
||||
|
||||
if (type != KeyType.UNKNOWN) {
|
||||
final String sKey = split[i++];
|
||||
key = new Buffer.PlainBuffer(Base64.decode(sKey)).readPublicKey();
|
||||
try {
|
||||
byte[] keyBytes = Base64.decode(sKey);
|
||||
key = new Buffer.PlainBuffer(keyBytes).readPublicKey();
|
||||
} catch (IOException ioe) {
|
||||
log.warn("Error decoding Base64 key bytes", ioe);
|
||||
return new BadHostEntry(line);
|
||||
}
|
||||
} else if (isBits(sType)) {
|
||||
type = KeyType.RSA;
|
||||
// int bits = Integer.valueOf(sType);
|
||||
@@ -220,11 +235,11 @@ public class OpenSSHKnownHosts
|
||||
key = keyFactory.generatePublic(new RSAPublicKeySpec(n, e));
|
||||
} catch (Exception ex) {
|
||||
log.error("Error reading entry `{}`, could not create key", line, ex);
|
||||
return null;
|
||||
return new BadHostEntry(line);
|
||||
}
|
||||
} else {
|
||||
log.error("Error reading entry `{}`, could not determine type", line);
|
||||
return null;
|
||||
return new BadHostEntry(line);
|
||||
}
|
||||
|
||||
return new HostEntry(marker, hostnames, type, key);
|
||||
@@ -310,7 +325,7 @@ public class OpenSSHKnownHosts
|
||||
protected final PublicKey key;
|
||||
private final KnownHostMatchers.HostMatcher matcher;
|
||||
|
||||
HostEntry(Marker marker, String hostPart, KeyType type, PublicKey key) throws SSHException {
|
||||
public HostEntry(Marker marker, String hostPart, KeyType type, PublicKey key) throws SSHException {
|
||||
this.marker = marker;
|
||||
this.hostPart = hostPart;
|
||||
this.type = type;
|
||||
@@ -364,6 +379,44 @@ public class OpenSSHKnownHosts
|
||||
}
|
||||
}
|
||||
|
||||
public static class BadHostEntry implements KnownHostEntry {
|
||||
private String line;
|
||||
|
||||
public BadHostEntry(String line) {
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyType getType() {
|
||||
return KeyType.UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFingerprint() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean appliesTo(String host) throws IOException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean appliesTo(KeyType type, String host) throws IOException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(PublicKey key) throws IOException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLine() {
|
||||
return line;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Marker {
|
||||
CA_CERT("@cert-authority"),
|
||||
REVOKED("@revoked");
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package net.schmizz.sshj.userauth.keyprovider;
|
||||
|
||||
import net.schmizz.sshj.common.IOUtils;
|
||||
import net.schmizz.sshj.common.SecurityUtils;
|
||||
import net.schmizz.sshj.userauth.password.PasswordUtils;
|
||||
import org.bouncycastle.openssl.EncryptionException;
|
||||
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
|
||||
@@ -62,12 +63,12 @@ public class PKCS8KeyFile extends BaseFileKeyProvider {
|
||||
final Object o = r.readObject();
|
||||
|
||||
final JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter();
|
||||
pemConverter.setProvider("BC");
|
||||
pemConverter.setProvider(SecurityUtils.getSecurityProvider());
|
||||
|
||||
if (o instanceof PEMEncryptedKeyPair) {
|
||||
final PEMEncryptedKeyPair encryptedKeyPair = (PEMEncryptedKeyPair) o;
|
||||
JcePEMDecryptorProviderBuilder decryptorBuilder = new JcePEMDecryptorProviderBuilder();
|
||||
decryptorBuilder.setProvider("BC");
|
||||
decryptorBuilder.setProvider(SecurityUtils.getSecurityProvider());
|
||||
try {
|
||||
passphrase = pwdf == null ? null : pwdf.reqPassword(resource);
|
||||
kp = pemConverter.getKeyPair(encryptedKeyPair.decryptKeyPair(decryptorBuilder.build(passphrase)));
|
||||
|
||||
Reference in New Issue
Block a user