Comprehensive support for publickey auth with certificates (#702)

* Add key types for ECDSA and ED25519 with certificates to implement publickey auth with that keys.

* Read public key certificates in OpenSSHKeyV1KeyFile.

* Fix ClassCastException in ECDSAVariationsAdapter.isECKeyWithFieldSize.

* Introduce an integration test for publickey auth with certificates.

* Refactor: merge copy-paste from OpenSshKey*File.java into an util class.

* Add the license to KeyWithCertificateSpec.groovy

* Add the license to OpenSSHKeyFileUtil.java
This commit is contained in:
Vladimir Lagunov
2021-07-02 18:50:37 +07:00
committed by GitHub
parent 0882efb5cb
commit ff4a4774bd
108 changed files with 823 additions and 36 deletions

View File

@@ -137,9 +137,13 @@ public class DefaultConfig
protected void initKeyAlgorithms() {
setKeyAlgorithms(Arrays.<Factory.Named<KeyAlgorithm>>asList(
KeyAlgorithms.EdDSA25519CertV01(),
KeyAlgorithms.EdDSA25519(),
KeyAlgorithms.ECDSASHANistp521CertV01(),
KeyAlgorithms.ECDSASHANistp521(),
KeyAlgorithms.ECDSASHANistp384CertV01(),
KeyAlgorithms.ECDSASHANistp384(),
KeyAlgorithms.ECDSASHANistp256CertV01(),
KeyAlgorithms.ECDSASHANistp256(),
KeyAlgorithms.RSASHA512(),
KeyAlgorithms.RSASHA256(),

View File

@@ -105,6 +105,7 @@ class ECDSAVariationsAdapter {
static boolean isECKeyWithFieldSize(Key key, int fieldSize) {
return (KeyAlgorithm.ECDSA.equals(key.getAlgorithm()) || KeyAlgorithm.EC_KEYSTORE.equals(key.getAlgorithm()))
&& key instanceof ECKey
&& fieldSizeFromKey((ECKey) key) == fieldSize;
}

View File

@@ -251,6 +251,98 @@ public enum KeyType {
}
},
ED25519_CERT("ssh-ed25519-cert-v01@openssh.com") {
@Override
public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException {
return CertUtils.readPubKey(buf, ED25519);
}
@Override
protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer<?> buf) {
CertUtils.writePubKeyContentsIntoBuffer(pk, ED25519, buf);
}
@Override
protected boolean isMyType(Key key) {
return CertUtils.isCertificateOfType(key, ED25519);
}
@Override
public KeyType getParent() {
return KeyType.ED25519;
}
},
ECDSA256_CERT("ecdsa-sha2-nistp256-cert-v01@openssh.com") {
@Override
public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException {
return CertUtils.readPubKey(buf, ECDSA256);
}
@Override
protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer<?> buf) {
CertUtils.writePubKeyContentsIntoBuffer(pk, ECDSA256, buf);
}
@Override
protected boolean isMyType(Key key) {
return CertUtils.isCertificateOfType(key, ECDSA256);
}
@Override
public KeyType getParent() {
return KeyType.ECDSA256;
}
},
ECDSA384_CERT("ecdsa-sha2-nistp384-cert-v01@openssh.com") {
@Override
public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException {
return CertUtils.readPubKey(buf, ECDSA384);
}
@Override
protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer<?> buf) {
CertUtils.writePubKeyContentsIntoBuffer(pk, ECDSA384, buf);
}
@Override
protected boolean isMyType(Key key) {
return CertUtils.isCertificateOfType(key, ECDSA384);
}
@Override
public KeyType getParent() {
return KeyType.ECDSA384;
}
},
ECDSA521_CERT("ecdsa-sha2-nistp521-cert-v01@openssh.com") {
@Override
public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException {
return CertUtils.readPubKey(buf, ECDSA521);
}
@Override
protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer<?> buf) {
CertUtils.writePubKeyContentsIntoBuffer(pk, ECDSA521, buf);
}
@Override
protected boolean isMyType(Key key) {
return CertUtils.isCertificateOfType(key, ECDSA521);
}
@Override
public KeyType getParent() {
return KeyType.ECDSA521;
}
},
/** Unrecognized */
UNKNOWN("unknown") {
@Override

View File

@@ -15,9 +15,7 @@
*/
package net.schmizz.sshj.userauth.keyprovider;
import net.schmizz.sshj.common.Base64;
import net.schmizz.sshj.common.Buffer;
import net.schmizz.sshj.common.KeyType;
import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyFileUtil;
import java.io.*;
import java.security.PublicKey;
@@ -58,11 +56,8 @@ public class OpenSSHKeyFile
@Override
public void init(File location) {
// try cert key location first
File pubKey = new File(location + "-cert.pub");
if (!pubKey.exists()) {
pubKey = new File(location + ".pub");
}
if (pubKey.exists())
File pubKey = OpenSSHKeyFileUtil.getPublicKeyFile(location);
if (pubKey != null)
try {
initPubKey(new FileReader(pubKey));
} catch (IOException e) {
@@ -91,25 +86,8 @@ public class OpenSSHKeyFile
* @param publicKey Public key accessible through a {@code Reader}
*/
private void initPubKey(Reader publicKey) throws IOException {
final BufferedReader br = new BufferedReader(publicKey);
try {
String keydata;
while ((keydata = br.readLine()) != null) {
keydata = keydata.trim();
if (!keydata.isEmpty()) {
String[] parts = keydata.trim().split("\\s+");
if (parts.length >= 2) {
type = KeyType.fromString(parts[0]);
pubKey = new Buffer.PlainBuffer(Base64.decode(parts[1])).readPublicKey();
} else {
throw new IOException("Got line with only one column");
}
return;
}
}
throw new IOException("Public key file is blank");
} finally {
br.close();
}
OpenSSHKeyFileUtil.ParsedPubKey parsed = OpenSSHKeyFileUtil.initPubKey(publicKey);
type = parsed.getType();
pubKey = parsed.getPubKey();
}
}