mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-06 15:20:54 +03:00
Add overloaded init methods that take the public key from a stream an… (#908)
* Add overloaded init methods that take the public key from a stream and properly initialize. Resolves #907. * Override public key.
This commit is contained in:
@@ -20,6 +20,7 @@ import com.hierynomus.sshj.common.KeyDecryptionFailedException;
|
|||||||
import com.hierynomus.sshj.transport.cipher.BlockCiphers;
|
import com.hierynomus.sshj.transport.cipher.BlockCiphers;
|
||||||
import com.hierynomus.sshj.transport.cipher.ChachaPolyCiphers;
|
import com.hierynomus.sshj.transport.cipher.ChachaPolyCiphers;
|
||||||
import com.hierynomus.sshj.transport.cipher.GcmCiphers;
|
import com.hierynomus.sshj.transport.cipher.GcmCiphers;
|
||||||
|
import com.hierynomus.sshj.userauth.keyprovider.bcrypt.BCrypt;
|
||||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
|
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
|
||||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
|
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
|
||||||
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
|
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
|
||||||
@@ -29,24 +30,23 @@ import net.schmizz.sshj.transport.cipher.Cipher;
|
|||||||
import net.schmizz.sshj.userauth.keyprovider.BaseFileKeyProvider;
|
import net.schmizz.sshj.userauth.keyprovider.BaseFileKeyProvider;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider;
|
import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.KeyFormat;
|
import net.schmizz.sshj.userauth.keyprovider.KeyFormat;
|
||||||
|
import net.schmizz.sshj.userauth.password.PasswordFinder;
|
||||||
import org.bouncycastle.asn1.nist.NISTNamedCurves;
|
import org.bouncycastle.asn1.nist.NISTNamedCurves;
|
||||||
import org.bouncycastle.asn1.x9.X9ECParameters;
|
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||||
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
|
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
|
||||||
import com.hierynomus.sshj.userauth.keyprovider.bcrypt.BCrypt;
|
|
||||||
import org.bouncycastle.openssl.EncryptionException;
|
import org.bouncycastle.openssl.EncryptionException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.*;
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.CharBuffer;
|
import java.nio.CharBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.*;
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.PublicKey;
|
||||||
import java.security.spec.ECPrivateKeySpec;
|
import java.security.spec.ECPrivateKeySpec;
|
||||||
import java.security.spec.RSAPrivateCrtKeySpec;
|
import java.security.spec.RSAPrivateCrtKeySpec;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -83,6 +83,12 @@ public class OpenSSHKeyV1KeyFile extends BaseFileKeyProvider {
|
|||||||
|
|
||||||
private PublicKey pubKey;
|
private PublicKey pubKey;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PublicKey getPublic()
|
||||||
|
throws IOException {
|
||||||
|
return pubKey != null ? pubKey : super.getPublic();
|
||||||
|
}
|
||||||
|
|
||||||
public static class Factory
|
public static class Factory
|
||||||
implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
|
implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
|
||||||
|
|
||||||
@@ -100,16 +106,41 @@ public class OpenSSHKeyV1KeyFile extends BaseFileKeyProvider {
|
|||||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(File location) {
|
public void init(File location, PasswordFinder pwdf) {
|
||||||
File pubKey = OpenSSHKeyFileUtil.getPublicKeyFile(location);
|
File pubKey = OpenSSHKeyFileUtil.getPublicKeyFile(location);
|
||||||
if (pubKey != null)
|
if (pubKey != null) {
|
||||||
try {
|
try {
|
||||||
initPubKey(new FileReader(pubKey));
|
initPubKey(new FileReader(pubKey));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// let super provide both public & private key
|
// let super provide both public & private key
|
||||||
log.warn("Error reading public key file: {}", e.toString());
|
log.warn("Error reading public key file: {}", e.toString());
|
||||||
}
|
}
|
||||||
super.init(location);
|
}
|
||||||
|
super.init(location, pwdf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(String privateKey, String publicKey, PasswordFinder pwdf) {
|
||||||
|
if (pubKey != null) {
|
||||||
|
try {
|
||||||
|
initPubKey(new StringReader(publicKey));
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Error reading public key file: {}", e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.init(privateKey, null, pwdf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Reader privateKey, Reader publicKey, PasswordFinder pwdf) {
|
||||||
|
if (pubKey != null) {
|
||||||
|
try {
|
||||||
|
initPubKey(publicKey);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Error reading public key file: {}", e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.init(privateKey, null, pwdf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -34,38 +34,47 @@ public abstract class BaseFileKeyProvider implements FileKeyProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Reader location) {
|
public void init(Reader location) {
|
||||||
assert location != null;
|
this.init(location, (PasswordFinder) null);
|
||||||
resource = new PrivateKeyReaderResource(location);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Reader location, PasswordFinder pwdf) {
|
public void init(Reader location, PasswordFinder pwdf) {
|
||||||
init(location);
|
this.init(location, null, pwdf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Reader privateKey, Reader publicKey) {
|
||||||
|
this.init(privateKey, publicKey, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Reader privateKey, Reader publicKey, PasswordFinder pwdf) {
|
||||||
|
assert publicKey == null;
|
||||||
|
this.resource = new PrivateKeyReaderResource(privateKey);
|
||||||
this.pwdf = pwdf;
|
this.pwdf = pwdf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(File location) {
|
public void init(File location) {
|
||||||
assert location != null;
|
this.init(location, null);
|
||||||
resource = new PrivateKeyFileResource(location.getAbsoluteFile());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(File location, PasswordFinder pwdf) {
|
public void init(File location, PasswordFinder pwdf) {
|
||||||
init(location);
|
this.resource = new PrivateKeyFileResource(location.getAbsoluteFile());
|
||||||
this.pwdf = pwdf;
|
this.pwdf = pwdf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(String privateKey, String publicKey) {
|
public void init(String privateKey, String publicKey) {
|
||||||
assert privateKey != null;
|
this.init(privateKey, publicKey, null);
|
||||||
assert publicKey == null;
|
|
||||||
resource = new PrivateKeyStringResource(privateKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(String privateKey, String publicKey, PasswordFinder pwdf) {
|
public void init(String privateKey, String publicKey, PasswordFinder pwdf) {
|
||||||
init(privateKey, publicKey);
|
assert privateKey != null;
|
||||||
|
assert publicKey == null;
|
||||||
|
this.resource = new PrivateKeyStringResource(privateKey);
|
||||||
this.pwdf = pwdf;
|
this.pwdf = pwdf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ public interface FileKeyProvider
|
|||||||
|
|
||||||
void init(Reader location);
|
void init(Reader location);
|
||||||
|
|
||||||
|
void init(Reader privateKey, Reader publicKey);
|
||||||
|
|
||||||
|
void init(Reader privateKey, Reader publicKey, PasswordFinder pwdf);
|
||||||
|
|
||||||
void init(Reader location, PasswordFinder pwdf);
|
void init(Reader location, PasswordFinder pwdf);
|
||||||
|
|
||||||
void init(String privateKey, String publicKey);
|
void init(String privateKey, String publicKey);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
package net.schmizz.sshj.userauth.keyprovider;
|
package net.schmizz.sshj.userauth.keyprovider;
|
||||||
|
|
||||||
import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyFileUtil;
|
import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyFileUtil;
|
||||||
|
import net.schmizz.sshj.userauth.password.PasswordFinder;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
@@ -54,21 +55,22 @@ public class OpenSSHKeyFile
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(File location) {
|
public void init(File location, PasswordFinder pwdf) {
|
||||||
// try cert key location first
|
// try cert key location first
|
||||||
File pubKey = OpenSSHKeyFileUtil.getPublicKeyFile(location);
|
File pubKey = OpenSSHKeyFileUtil.getPublicKeyFile(location);
|
||||||
if (pubKey != null)
|
if (pubKey != null) {
|
||||||
try {
|
try {
|
||||||
initPubKey(new FileReader(pubKey));
|
initPubKey(new FileReader(pubKey));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// let super provide both public & private key
|
// let super provide both public & private key
|
||||||
log.warn("Error reading public key file: {}", e.toString());
|
log.warn("Error reading public key file: {}", e.toString());
|
||||||
}
|
}
|
||||||
super.init(location);
|
}
|
||||||
|
super.init(location, pwdf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(String privateKey, String publicKey) {
|
public void init(String privateKey, String publicKey, PasswordFinder pwdf) {
|
||||||
if (publicKey != null) {
|
if (publicKey != null) {
|
||||||
try {
|
try {
|
||||||
initPubKey(new StringReader(publicKey));
|
initPubKey(new StringReader(publicKey));
|
||||||
@@ -77,7 +79,20 @@ public class OpenSSHKeyFile
|
|||||||
log.warn("Error reading public key: {}", e.toString());
|
log.warn("Error reading public key: {}", e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.init(privateKey, null);
|
super.init(privateKey, null, pwdf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Reader privateKey, Reader publicKey, PasswordFinder pwdf) {
|
||||||
|
if (publicKey != null) {
|
||||||
|
try {
|
||||||
|
initPubKey(publicKey);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// let super provide both public & private key
|
||||||
|
log.warn("Error reading public key: {}", e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.init(privateKey, null, pwdf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -381,6 +381,18 @@ public class OpenSSHKeyFileTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldSuccessfullyLoadSignedRSAPublicKeyFromStream() throws IOException {
|
||||||
|
FileKeyProvider keyFile = new OpenSSHKeyFile();
|
||||||
|
keyFile.init(new FileReader("src/test/resources/keytypes/certificate/test_rsa"),
|
||||||
|
new FileReader("src/test/resources/keytypes/certificate/test_rsa.pub"),
|
||||||
|
PasswordUtils.createOneOff(correctPassphrase));
|
||||||
|
assertNotNull(keyFile.getPrivate());
|
||||||
|
PublicKey pubKey = keyFile.getPublic();
|
||||||
|
assertNotNull(pubKey);
|
||||||
|
assertEquals("RSA", pubKey.getAlgorithm());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldSuccessfullyLoadSignedRSAPublicKeyWithMaxDate() throws IOException {
|
public void shouldSuccessfullyLoadSignedRSAPublicKeyWithMaxDate() throws IOException {
|
||||||
FileKeyProvider keyFile = new OpenSSHKeyFile();
|
FileKeyProvider keyFile = new OpenSSHKeyFile();
|
||||||
@@ -422,6 +434,17 @@ public class OpenSSHKeyFileTest {
|
|||||||
assertEquals("", certificate.getExtensions().get("permit-pty"));
|
assertEquals("", certificate.getExtensions().get("permit-pty"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldSuccessfullyLoadSignedDSAPublicKeyFromStream() throws IOException {
|
||||||
|
FileKeyProvider keyFile = new OpenSSHKeyFile();
|
||||||
|
keyFile.init(new FileReader("src/test/resources/keytypes/certificate/test_dsa"),
|
||||||
|
new FileReader("src/test/resources/keytypes/certificate/test_dsa-cert.pub"),
|
||||||
|
PasswordUtils.createOneOff(correctPassphrase));
|
||||||
|
assertNotNull(keyFile.getPrivate());
|
||||||
|
PublicKey pubKey = keyFile.getPublic();
|
||||||
|
assertEquals("DSA", pubKey.getAlgorithm());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sometimes users copy-pastes private and public keys in text editors. It leads to redundant
|
* Sometimes users copy-pastes private and public keys in text editors. It leads to redundant
|
||||||
* spaces and newlines. OpenSSH can easily read such keys, so users expect from SSHJ the same.
|
* spaces and newlines. OpenSSH can easily read such keys, so users expect from SSHJ the same.
|
||||||
|
|||||||
Reference in New Issue
Block a user