diff --git a/src/main/java/com/hierynomus/sshj/userauth/certificate/Certificate.java b/src/main/java/com/hierynomus/sshj/userauth/certificate/Certificate.java new file mode 100644 index 00000000..fda31b92 --- /dev/null +++ b/src/main/java/com/hierynomus/sshj/userauth/certificate/Certificate.java @@ -0,0 +1,258 @@ +package com.hierynomus.sshj.userauth.certificate; + +import java.math.BigInteger; +import java.security.PublicKey; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/* + * 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. + */ +/** + * Certificate wrapper for public keys, created to help implement + * protocol described here: + * + * https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD + * + * Consumed primarily by net.shmizz.sshj.common.KeyType + * + * @param inner public key type + */ +public class Certificate implements PublicKey { + private static final long serialVersionUID = 1L; + + private final T publicKey; + private final byte[] nonce; + private final BigInteger serial; + private final long type; + private final String id; + private final List validPrincipals; + private final Date validAfter; + private final Date validBefore; + private final Map critOptions; + private final Map extensions; + private final byte[] signatureKey; + private final byte[] signature; + + Certificate(Builder builder) { + this.publicKey = builder.getPublicKey(); + this.nonce = builder.getNonce(); + this.serial = builder.getSerial(); + this.type = builder.getType(); + this.id = builder.getId(); + this.validPrincipals = builder.getValidPrincipals(); + this.validAfter = builder.getValidAfter(); + this.validBefore = builder.getValidBefore(); + this.critOptions = builder.getCritOptions(); + this.extensions = builder.getExtensions(); + this.signatureKey = builder.getSignatureKey(); + this.signature = builder.getSignature(); + } + + public static

Builder

getBuilder() { + return new Builder

(); + } + + public byte[] getNonce() { + return nonce; + } + + public BigInteger getSerial() { + return serial; + } + + public long getType() { + return type; + } + + public String getId() { + return id; + } + + public List getValidPrincipals() { + return validPrincipals; + } + + public Date getValidAfter() { + return validAfter; + } + + public Date getValidBefore() { + return validBefore; + } + + public Map getCritOptions() { + return critOptions; + } + + public Map getExtensions() { + return extensions; + } + + public byte[] getSignatureKey() { + return signatureKey; + } + + public byte[] getSignature() { + return signature; + } + + public T getKey() { + return publicKey; + } + + @Override + public byte[] getEncoded() { + return publicKey.getEncoded(); + } + + @Override + public String getAlgorithm() { + return publicKey.getAlgorithm(); + } + + @Override + public String getFormat() { + return publicKey.getFormat(); + } + + public static class Builder { + private T publicKey; + private byte[] nonce; + private BigInteger serial; + private long type; + private String id; + private List validPrincipals; + private Date validAfter; + private Date validBefore; + private Map critOptions; + private Map extensions; + private byte[] signatureKey; + private byte[] signature; + + public Certificate build() { + return new Certificate(this); + } + + public T getPublicKey() { + return publicKey; + } + + public Builder publicKey(T publicKey) { + this.publicKey = publicKey; + return this; + } + + public byte[] getNonce() { + return nonce; + } + + public Builder nonce(byte[] nonce) { + this.nonce = nonce; + return this; + } + + public BigInteger getSerial() { + return serial; + } + + public Builder serial(BigInteger serial) { + this.serial = serial; + return this; + } + + public long getType() { + return type; + } + + public Builder type(long type) { + this.type = type; + return this; + } + + public String getId() { + return id; + } + + public Builder id(String id) { + this.id = id; + return this; + } + + public List getValidPrincipals() { + return validPrincipals; + } + + public Builder validPrincipals(List validPrincipals) { + this.validPrincipals = validPrincipals; + return this; + } + + public Date getValidAfter() { + return validAfter; + } + + public Builder validAfter(Date validAfter) { + this.validAfter = validAfter; + return this; + } + + public Date getValidBefore() { + return validBefore; + } + + public Builder validBefore(Date validBefore) { + this.validBefore = validBefore; + return this; + } + + public Map getCritOptions() { + return critOptions; + } + + public Builder critOptions(Map critOptions) { + this.critOptions = critOptions; + return this; + } + + public Map getExtensions() { + return extensions; + } + + public Builder extensions(Map extensions) { + this.extensions = extensions; + return this; + } + + public byte[] getSignatureKey() { + return signatureKey; + } + + public Builder signatureKey(byte[] signatureKey) { + this.signatureKey = signatureKey; + return this; + } + + public byte[] getSignature() { + return signature; + } + + public Builder signature(byte[] signature) { + this.signature = signature; + return this; + } + } +} diff --git a/src/main/java/net/schmizz/sshj/common/Buffer.java b/src/main/java/net/schmizz/sshj/common/Buffer.java index 41bc9c1c..8cf35ae3 100644 --- a/src/main/java/net/schmizz/sshj/common/Buffer.java +++ b/src/main/java/net/schmizz/sshj/common/Buffer.java @@ -57,6 +57,11 @@ public class Buffer> { /** The maximum valid size of buffer (i.e. biggest power of two that can be represented as an int - 2^30) */ public static final int MAX_SIZE = (1 << 30); + /** Maximum size of a uint64 */ + private static final BigInteger MAX_UINT64_VALUE = BigInteger.ONE + .shiftLeft(64) + .subtract(BigInteger.ONE); + protected static int getNextPowerOf2(int i) { int j = 1; while (j < i) { @@ -343,10 +348,29 @@ public class Buffer> { return uint64; } - @SuppressWarnings("unchecked") + public BigInteger readUInt64AsBigInteger() + throws BufferException { + byte[] magnitude = new byte[8]; + readRawBytes(magnitude); + return new BigInteger(1, magnitude); + } + public T putUInt64(long uint64) { if (uint64 < 0) throw new IllegalArgumentException("Invalid value: " + uint64); + return putUInt64Unchecked(uint64); + } + + public T putUInt64(BigInteger uint64) { + if (uint64.compareTo(MAX_UINT64_VALUE) > 0 || + uint64.compareTo(BigInteger.ZERO) < 0) { + throw new IllegalArgumentException("Invalid value: " + uint64); + } + return putUInt64Unchecked(uint64.longValue()); + } + + @SuppressWarnings("unchecked") + private T putUInt64Unchecked(long uint64) { data[wpos++] = (byte) (uint64 >> 56); data[wpos++] = (byte) (uint64 >> 48); data[wpos++] = (byte) (uint64 >> 40); diff --git a/src/main/java/net/schmizz/sshj/common/KeyType.java b/src/main/java/net/schmizz/sshj/common/KeyType.java index a49b6cfe..9d2ea94d 100644 --- a/src/main/java/net/schmizz/sshj/common/KeyType.java +++ b/src/main/java/net/schmizz/sshj/common/KeyType.java @@ -15,12 +15,26 @@ */ package net.schmizz.sshj.common; -import com.hierynomus.sshj.secg.SecgUtils; -import com.hierynomus.sshj.signature.Ed25519PublicKey; -import net.i2p.crypto.eddsa.EdDSAPublicKey; -import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec; -import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; -import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.DSAPublicKeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + import org.bouncycastle.asn1.nist.NISTNamedCurves; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.jce.spec.ECParameterSpec; @@ -29,20 +43,19 @@ import org.bouncycastle.math.ec.ECPoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.math.BigInteger; -import java.security.GeneralSecurityException; -import java.security.Key; -import java.security.KeyFactory; -import java.security.PublicKey; -import java.security.interfaces.*; -import java.security.spec.DSAPublicKeySpec; -import java.security.spec.RSAPublicKeySpec; -import java.util.Arrays; +import com.hierynomus.sshj.secg.SecgUtils; +import com.hierynomus.sshj.signature.Ed25519PublicKey; +import com.hierynomus.sshj.userauth.certificate.Certificate; + +import net.i2p.crypto.eddsa.EdDSAPublicKey; +import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec; +import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; +import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec; +import net.schmizz.sshj.common.Buffer.BufferException; /** Type of key e.g. rsa, dsa */ public enum KeyType { - /** SSH identifier for RSA keys */ RSA("ssh-rsa") { @Override @@ -60,18 +73,16 @@ public enum KeyType { } @Override - public void putPubKeyIntoBuffer(PublicKey pk, Buffer buf) { + protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer buf) { final RSAPublicKey rsaKey = (RSAPublicKey) pk; - buf.putString(sType) - .putMPInt(rsaKey.getPublicExponent()) // e - .putMPInt(rsaKey.getModulus()); // n + buf.putMPInt(rsaKey.getPublicExponent()) // e + .putMPInt(rsaKey.getModulus()); // n } @Override protected boolean isMyType(Key key) { return (key instanceof RSAPublicKey || key instanceof RSAPrivateKey); } - }, /** SSH identifier for DSA keys */ @@ -93,10 +104,9 @@ public enum KeyType { } @Override - public void putPubKeyIntoBuffer(PublicKey pk, Buffer buf) { + protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer buf) { final DSAPublicKey dsaKey = (DSAPublicKey) pk; - buf.putString(sType) - .putMPInt(dsaKey.getParams().getP()) // p + buf.putMPInt(dsaKey.getParams().getP()) // p .putMPInt(dsaKey.getParams().getQ()) // q .putMPInt(dsaKey.getParams().getG()) // g .putMPInt(dsaKey.getY()); // y @@ -161,12 +171,11 @@ public enum KeyType { @Override - public void putPubKeyIntoBuffer(PublicKey pk, Buffer buf) { + protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer buf) { final ECPublicKey ecdsa = (ECPublicKey) pk; byte[] encoded = SecgUtils.getEncoded(ecdsa.getW(), ecdsa.getParams().getCurve()); - buf.putString(sType) - .putString(NISTP_CURVE) + buf.putString(NISTP_CURVE) .putBytes(encoded); } @@ -202,9 +211,9 @@ public enum KeyType { } @Override - public void putPubKeyIntoBuffer(PublicKey pk, Buffer buf) { + protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer buf) { EdDSAPublicKey key = (EdDSAPublicKey) pk; - buf.putString(sType).putBytes(key.getAbyte()); + buf.putBytes(key.getAbyte()); } @Override @@ -213,6 +222,44 @@ public enum KeyType { } }, + /** Signed rsa certificate */ + RSA_CERT("ssh-rsa-cert-v01@openssh.com") { + @Override + public PublicKey readPubKeyFromBuffer(Buffer buf) + throws GeneralSecurityException { + return CertUtils.readPubKey(buf, RSA); + } + + @Override + protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer buf) { + CertUtils.writePubKeyContentsIntoBuffer(pk, RSA, buf); + } + + @Override + protected boolean isMyType(Key key) { + return CertUtils.isCertificateOfType(key, RSA); + } + }, + + /** Signed dsa certificate */ + DSA_CERT("ssh-dss-cert-v01@openssh.com") { + @Override + public PublicKey readPubKeyFromBuffer(Buffer buf) + throws GeneralSecurityException { + return CertUtils.readPubKey(buf, DSA); + } + + @Override + protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer buf) { + CertUtils.writePubKeyContentsIntoBuffer(pk, DSA, buf); + } + + @Override + protected boolean isMyType(Key key) { + return CertUtils.isCertificateOfType(key, DSA); + } + }, + /** Unrecognized */ UNKNOWN("unknown") { @Override @@ -226,6 +273,11 @@ public enum KeyType { throw new UnsupportedOperationException("Don't know how to encode key: " + pk); } + @Override + protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer buf) { + throw new UnsupportedOperationException("Don't know how to encode key: " + pk); + } + @Override protected boolean isMyType(Key key) { return false; @@ -244,7 +296,11 @@ public enum KeyType { public abstract PublicKey readPubKeyFromBuffer(Buffer buf) throws GeneralSecurityException; - public abstract void putPubKeyIntoBuffer(PublicKey pk, Buffer buf); + protected abstract void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer buf); + + public void putPubKeyIntoBuffer(PublicKey pk, Buffer buf) { + writePubKeyContentsIntoBuffer(pk, buf.putString(sType)); + } protected abstract boolean isMyType(Key key); @@ -266,4 +322,129 @@ public enum KeyType { public String toString() { return sType; } + + static class CertUtils { + + @SuppressWarnings("unchecked") + static Certificate readPubKey(Buffer buf, KeyType innerKeyType) throws GeneralSecurityException { + Certificate.Builder builder = Certificate.getBuilder(); + + try { + builder.nonce(buf.readBytes()); + builder.publicKey((T) innerKeyType.readPubKeyFromBuffer(buf)); + builder.serial(buf.readUInt64AsBigInteger()); + builder.type(buf.readUInt32()); + builder.id(buf.readString()); + builder.validPrincipals(unpackList(buf.readBytes())); + builder.validAfter(dateFromEpoch(buf.readUInt64())); + builder.validBefore(dateFromEpoch(buf.readUInt64())); + builder.critOptions(unpackMap(buf.readBytes())); + builder.extensions(unpackMap(buf.readBytes())); + buf.readString(); // reserved + builder.signatureKey(buf.readBytes()); + builder.signature(buf.readBytes()); + } catch (Buffer.BufferException be) { + throw new GeneralSecurityException(be); + } + + return builder.build(); + } + + static void writePubKeyContentsIntoBuffer(PublicKey publicKey, KeyType innerKeyType, Buffer buf) { + Certificate certificate = toCertificate(publicKey); + buf.putBytes(certificate.getNonce()); + innerKeyType.writePubKeyContentsIntoBuffer(certificate.getKey(), buf); + buf.putUInt64(certificate.getSerial()) + .putUInt32(certificate.getType()) + .putString(certificate.getId()) + .putBytes(packList(certificate.getValidPrincipals())) + .putUInt64(epochFromDate(certificate.getValidAfter())) + .putUInt64(epochFromDate(certificate.getValidBefore())) + .putBytes(packMap(certificate.getCritOptions())) + .putBytes(packMap(certificate.getExtensions())) + .putString("") // reserved + .putBytes(certificate.getSignatureKey()) + .putBytes(certificate.getSignature()); + } + + static boolean isCertificateOfType(Key key, KeyType innerKeyType) { + if (!(key instanceof Certificate)) { + return false; + } + @SuppressWarnings("unchecked") + Key innerKey = ((Certificate) key).getKey(); + return innerKeyType.isMyType(innerKey); + } + + @SuppressWarnings("unchecked") + static Certificate toCertificate(PublicKey key) { + if (!(key instanceof Certificate)) { + throw new UnsupportedOperationException("Can't convert non-certificate key " + + key.getAlgorithm() + " to certificate"); + } + return ((Certificate) key); + } + + private static Date dateFromEpoch(long seconds) { + return new Date(seconds * 1000); + } + + private static long epochFromDate(Date date) { + return date.getTime() / 1000; + } + + private static String unpackString(byte[] packedString) throws BufferException { + if (packedString.length == 0) { + return ""; + } + return new Buffer.PlainBuffer(packedString).readString(); + } + + private static List unpackList(byte[] packedString) throws BufferException { + List list = new ArrayList(); + Buffer buf = new Buffer.PlainBuffer(packedString); + while (buf.available() > 0) { + list.add(buf.readString()); + } + return list; + } + + private static Map unpackMap(byte[] packedString) throws BufferException { + Map map = new LinkedHashMap(); + Buffer buf = new Buffer.PlainBuffer(packedString); + while (buf.available() > 0) { + String name = buf.readString(); + String data = unpackString(buf.readStringAsBytes()); + map.put(name, data); + } + return map; + } + + private static byte[] packString(String data) { + if (data == null || data.isEmpty()) { + return "".getBytes(); + } + return new Buffer.PlainBuffer().putString(data).getCompactData(); + } + + private static byte[] packList(Iterable strings) { + Buffer buf = new Buffer.PlainBuffer(); + for (String string : strings) { + buf.putString(string); + } + return buf.getCompactData(); + } + + private static byte[] packMap(Map map) { + Buffer buf = new Buffer.PlainBuffer(); + List keys = new ArrayList(map.keySet()); + Collections.sort(keys); + for (String key : keys) { + buf.putString(key); + String value = map.get(key); + buf.putString(packString(value)); + } + return buf.getCompactData(); + } + } } diff --git a/src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyProviderUtil.java b/src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyProviderUtil.java index 2459d83f..eb5246d4 100644 --- a/src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyProviderUtil.java +++ b/src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyProviderUtil.java @@ -34,7 +34,7 @@ public class KeyProviderUtil { public static KeyFormat detectKeyFileFormat(File location) throws IOException { return detectKeyFileFormat(new FileReader(location), - new File(location + ".pub").exists()); + new File(location + ".pub").exists() || new File(location + "-cert.pub").exists()); } /** diff --git a/src/main/java/net/schmizz/sshj/userauth/keyprovider/OpenSSHKeyFile.java b/src/main/java/net/schmizz/sshj/userauth/keyprovider/OpenSSHKeyFile.java index bf8f613e..39a9ec0c 100644 --- a/src/main/java/net/schmizz/sshj/userauth/keyprovider/OpenSSHKeyFile.java +++ b/src/main/java/net/schmizz/sshj/userauth/keyprovider/OpenSSHKeyFile.java @@ -57,10 +57,14 @@ public class OpenSSHKeyFile @Override public void init(File location) { - final File f = new File(location + ".pub"); - if (f.exists()) + // try cert key location first + File pubKey = new File(location + "-cert.pub"); + if (!pubKey.exists()) { + pubKey = new File(location + ".pub"); + } + if (pubKey.exists()) try { - initPubKey(new FileReader(f)); + initPubKey(new FileReader(pubKey)); } catch (IOException e) { // let super provide both public & private key log.warn("Error reading public key file: {}", e.toString()); diff --git a/src/test/java/net/schmizz/sshj/common/BufferTest.java b/src/test/java/net/schmizz/sshj/common/BufferTest.java index 1395bdd4..2d2de53c 100644 --- a/src/test/java/net/schmizz/sshj/common/BufferTest.java +++ b/src/test/java/net/schmizz/sshj/common/BufferTest.java @@ -15,10 +15,14 @@ */ package net.schmizz.sshj.common; +import net.schmizz.sshj.common.Buffer.BufferException; import net.schmizz.sshj.common.Buffer.PlainBuffer; -import org.junit.Test; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; + +import java.math.BigInteger; + +import org.junit.Test; public class BufferTest { @@ -44,4 +48,103 @@ public class BufferTest { // success } } + + @Test + public void shouldThrowOnPutNegativeLongUInt64() { + try { + new PlainBuffer().putUInt64(-1l); + fail("Added negative uint64 to buffer?"); + } catch (IllegalArgumentException e) { + // success + } + } + + @Test + public void shouldThrowOnReadNegativeLongUInt64() { + byte[] negativeLong = new byte[] { (byte) 0x80, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x01 }; + Buffer buff = new PlainBuffer(negativeLong); + + try { + buff.readUInt64(); + fail("Read negative uint64 from buffer?"); + } catch (BufferException e) { + // success + } + } + + @Test + public void shouldThrowOnPutNegativeBigIntegerUInt64() { + try { + new PlainBuffer().putUInt64(new BigInteger("-1")); + fail("Added negative uint64 to buffer?"); + } catch (IllegalArgumentException e) { + // success + } + } + + @Test + public void shouldHaveCorrectValueForMaxUInt64() { + byte[] maxUInt64InBytes = new byte[] { (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF }; + BigInteger maxUInt64 = new BigInteger(1, maxUInt64InBytes); + new PlainBuffer().putUInt64(maxUInt64); // no exception + + BigInteger tooBig = maxUInt64.add(BigInteger.ONE); + try { + new PlainBuffer().putUInt64(tooBig); + fail("Added 2^64 (too big) as uint64 to buffer?"); + } catch (IllegalArgumentException e) { + // success + } + } + + @Test + public void shouldCorrectlyEncodeAndDecodeUInt64Types() throws BufferException { + // This number fits into a unsigned 64 bit integer but not a signed one. + BigInteger bigUint64 = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE).add(BigInteger.ONE); + assertEquals(0x8000000000000001l, bigUint64.longValue()); + + Buffer buff = new PlainBuffer(); + buff.putUInt64(bigUint64); + byte[] data = buff.getCompactData(); + assertEquals(8, data.length); + assertEquals((byte) 0x80, data[0]); + assertEquals((byte) 0x00, data[1]); + assertEquals((byte) 0x00, data[2]); + assertEquals((byte) 0x00, data[3]); + assertEquals((byte) 0x00, data[4]); + assertEquals((byte) 0x00, data[5]); + assertEquals((byte) 0x00, data[6]); + assertEquals((byte) 0x01, data[7]); + + byte[] asBinary = new byte[] { (byte) 0x80, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x01 }; + buff = new PlainBuffer(asBinary); + assertEquals(bigUint64, buff.readUInt64AsBigInteger()); + } + + @Test + public void shouldHaveSameUInt64EncodingForBigIntegerAndLong() { + long[] values = { 0l, 1l, 232634978082517765l, Long.MAX_VALUE - 1, Long.MAX_VALUE }; + for (long value : values) { + byte[] bytesBigInt = new PlainBuffer().putUInt64(BigInteger.valueOf(value)).getCompactData(); + byte[] bytesLong = new PlainBuffer().putUInt64(value).getCompactData(); + assertArrayEquals("Value: " + value, bytesLong, bytesBigInt); + } + } } diff --git a/src/test/java/net/schmizz/sshj/keyprovider/KeyProviderUtilTest.java b/src/test/java/net/schmizz/sshj/keyprovider/KeyProviderUtilTest.java index a35bee77..3df8961b 100644 --- a/src/test/java/net/schmizz/sshj/keyprovider/KeyProviderUtilTest.java +++ b/src/test/java/net/schmizz/sshj/keyprovider/KeyProviderUtilTest.java @@ -57,4 +57,10 @@ public class KeyProviderUtilTest { KeyFormat format = KeyProviderUtil.detectKeyFileFormat(new File(ROOT, "pkcs8-blanks")); assertEquals(KeyFormat.PKCS8, format); } + + @Test + public void testOpenSshSigned() throws IOException { + KeyFormat format = KeyProviderUtil.detectKeyFileFormat(new File(ROOT, "signed")); + assertEquals(KeyFormat.OpenSSH, format); + } } diff --git a/src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java b/src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java index d39443b7..67e06411 100644 --- a/src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java +++ b/src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java @@ -15,32 +15,44 @@ */ package net.schmizz.sshj.keyprovider; -import net.schmizz.sshj.common.KeyType; -import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider; -import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile; -import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile; -import net.schmizz.sshj.userauth.password.PasswordFinder; -import net.schmizz.sshj.userauth.password.PasswordUtils; -import net.schmizz.sshj.userauth.password.Resource; -import net.schmizz.sshj.util.KeyUtil; -import org.apache.sshd.common.util.SecurityUtils; -import org.junit.Before; -import org.junit.Test; - -import java.io.File; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.security.GeneralSecurityException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.util.Arrays; -import java.util.Scanner; - import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.Map; +import java.util.Scanner; + +import org.apache.sshd.common.util.SecurityUtils; +import org.junit.Before; +import org.junit.Test; + +import com.hierynomus.sshj.userauth.certificate.Certificate; +import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile; + +import net.schmizz.sshj.common.KeyType; +import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider; +import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile; +import net.schmizz.sshj.userauth.password.PasswordFinder; +import net.schmizz.sshj.userauth.password.PasswordUtils; +import net.schmizz.sshj.userauth.password.Resource; +import net.schmizz.sshj.util.KeyUtil; public class OpenSSHKeyFileTest { @@ -161,6 +173,68 @@ public class OpenSSHKeyFileTest { assertThat(aPrivate.getAlgorithm(), equalTo("EdDSA")); } + @Test + public void shouldSuccessfullyLoadSignedRSAPublicKey() throws IOException { + FileKeyProvider keyFile = new OpenSSHKeyFile(); + keyFile.init(new File("src/test/resources/keytypes/certificate/test_rsa"), + PasswordUtils.createOneOff(correctPassphrase)); + assertNotNull(keyFile.getPrivate()); + PublicKey pubKey = keyFile.getPublic(); + assertEquals("RSA", pubKey.getAlgorithm()); + + @SuppressWarnings("unchecked") + Certificate certificate = (Certificate) pubKey; + + assertEquals(new BigInteger("9223372036854775809"), certificate.getSerial()); + assertEquals("testrsa", certificate.getId()); + + assertEquals(2, certificate.getValidPrincipals().size()); + assertTrue(certificate.getValidPrincipals().contains("jeroen")); + assertTrue(certificate.getValidPrincipals().contains("nobody")); + + assertEquals(parseDate("2017-04-11 17:38:00 -0400"), certificate.getValidAfter()); + assertEquals(parseDate("2017-04-11 18:09:27 -0400"), certificate.getValidBefore()); + + assertEquals(0, certificate.getCritOptions().size()); + + Map extensions = certificate.getExtensions(); + assertEquals(5, extensions.size()); + assertEquals("", extensions.get("permit-X11-forwarding")); + assertEquals("", extensions.get("permit-agent-forwarding")); + assertEquals("", extensions.get("permit-port-forwarding")); + assertEquals("", extensions.get("permit-pty")); + assertEquals("", extensions.get("permit-user-rc")); + + } + + @Test + public void shouldSuccessfullyLoadSignedDSAPublicKey() throws IOException { + FileKeyProvider keyFile = new OpenSSHKeyFile(); + keyFile.init(new File("src/test/resources/keytypes/certificate/test_dsa"), + PasswordUtils.createOneOff(correctPassphrase)); + assertNotNull(keyFile.getPrivate()); + PublicKey pubKey = keyFile.getPublic(); + assertEquals("DSA", pubKey.getAlgorithm()); + + @SuppressWarnings("unchecked") + Certificate certificate = (Certificate) pubKey; + + assertEquals(new BigInteger("123"), certificate.getSerial()); + assertEquals("testdsa", certificate.getId()); + + assertEquals(1, certificate.getValidPrincipals().size()); + assertTrue(certificate.getValidPrincipals().contains("jeroen")); + + assertEquals(parseDate("2017-04-11 17:37:00 -0400"), certificate.getValidAfter()); + assertEquals(parseDate("2017-04-12 03:38:49 -0400"), certificate.getValidBefore()); + + assertEquals(1, certificate.getCritOptions().size()); + assertEquals("10.0.0.0/8", certificate.getCritOptions().get("source-address")); + + assertEquals(1, certificate.getExtensions().size()); + assertEquals("", certificate.getExtensions().get("permit-pty")); + } + @Before public void setup() throws UnsupportedEncodingException, GeneralSecurityException { @@ -182,4 +256,13 @@ public class OpenSSHKeyFileTest { scanner.close(); } } + + private Date parseDate(String date) { + DateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"); + try { + return f.parse(date); + } catch (ParseException e) { + return null; + } + } } diff --git a/src/test/resources/keyformats/signed b/src/test/resources/keyformats/signed new file mode 100644 index 00000000..b5b30aaa --- /dev/null +++ b/src/test/resources/keyformats/signed @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,DEF5F558DB233F512527D38775CF90A6 + +EQb59FGxEYNaLoYZ1GRtLdQVYe3DtQyAq42OvJyPF2xFpiV+U63TDzHBeSJnf4yK +FWcWRbmFM5XL5jpuw7oUtg+bFOYsSjRMTGNpxcXDoByfRubLb3RPMlmVCENcwTXa +pF1QuKQYj2+DXRam5y2w7A6rznd5lFDRM57kApGSMcrWwNz2WDyvuqlPTo6Wsj1j +SWOQb9Te/ww1t8iEHryAITzUSRhbZG2epGh85QvuKhBebBd9TNRZwqwaZPx+j87/ +JGvq2RzttIydciLRBx3kYFI7JV1TGTbe+Hd10Yis9jBttqmEpB9Zyoug1Lubg3E2 +s45jk0CVAFp+44dKhk6K0uX4cjhC9uok6cAGZ7DYMokxEfCiJc7zJJgLvbil2lvK +fbewUoiXGLtCPaDe1UXhmkYXBL2BqrBa2PTYlB0JQzFn//9qWW6RVqLpltWSFcFT +nGQpRKZLSQhHLn+90X4lAuolUlrpWqgREiGSHlIgihv8mz9uAbHWSvSQE3q0dKSb +OgU1CDVsxd0mdkb6ZNeS1iT50uwCpwiUw4Cx9xZp0xdzjiN15ED8eLI/nDFCZXhA +jA0AK/cPzlO/Vc3uoM8+3PUkiMKd4glJzWkkE9pEiPlTQ3xivxUM4wQq6pgrjT13 +YI5PH5FkGNXYEeNxGnL+VXrWnxItd7ZVctG+3p6OKr9ShDxfYfw7WHk2n2o/s9rP +j8eSq0G/Dr5ZoaMipPX0aP/BXzZZVVsnFc0SmGfcuIGDug+hjs5OKcrvi6QteJ6u +dlsZJUy1YYnc/7T43TMllnouCHQ4TN01JTJSFS0IuKUrDoXI2DBSf2nE4J+04Cno +bC5WZCmThM2tWdFiqsRn4I5oZ8vEl6ffhzgwLs/8fJSwzwCwLraMSMWJMJibnG/8 +cn3/Mwzm6aDMpRqu7h6s2tDctdZJEdRcwjD5tdPg09CLsNvG7nfJWi8RL/PxSuC1 +m5KKK9rbXVRzg011QELrxTBUAGcH/YHEsOZNrIexyWG99eJ5Y3tEpyaxHVVIsT/o ++bsC8SEhADWKmfQmzZz8UbUQLs5SOxa6mutxudzmvdLnGmHk8fsBO7MbxRyBjqau ++o5/ClbNzwSUSQQ8W3dpEpU/7udYAtHjwIWwVk7lwUqe/s7p2G9f5LDegJfJAXiU +zGetpnYYFd1n4xQs22UPHS0+RaFLsYszvSv+LUEpVJ+zIWSB5hp7OrWLiQpGnQVH +YydQUrxt8AYnhdrBbsxk652XFhBZzzbA9AlEHLhiMXDIh7XamFNk/S6fVGgsACGo +hu2Ui50lHIRgNKds2tp41G74Vgv20lu3htU0wN9nDwjxATu+sX/0IaWwZIj1iuFf +8YK6P0yP5rWyzAfDQWnh15SHE6zAvKYwyZtG7OWBYmd3whyR+VGuzCKw2uLh6JBx +5GdNScf5szD1KSxqWwfY5tVLSn/gsSgCAptp5tiIdazOID1OkuM24yYRWoCvxT52 +qlfG5LHIhYUCzOdRK9DDSgSBqXCaiN3VD3KLOBfeSKSoen0h+CsIz9kmL73liisM ++V8knyffjXfb/yCtV1b2xD9bds2si49Mif4aS1SX6bnBT+A5z/f/N3BGrdtIaMFl +-----END RSA PRIVATE KEY----- diff --git a/src/test/resources/keyformats/signed-cert.pub b/src/test/resources/keyformats/signed-cert.pub new file mode 100644 index 00000000..b08514dd --- /dev/null +++ b/src/test/resources/keyformats/signed-cert.pub @@ -0,0 +1 @@ +ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg3ZotKIydji2P4WBzJjEHH1+n0VBVEyeZDb1AHj4HbUoAAAADAQABAAABAQDu1ngN8Oe+N32oDQ9CSw59fEM4Xo2HaAM/LFZffSj6gwS+BrKVYcupZCoUsLjNaOXudeivrI7+MTtfpPeCXKfNw6Bhmh16OXDdkFuEraLotSkibqNleGPrJW5KB6OBgTv7bSx249oobPLZ9Xog2fO888lsCFMCLMuoiEQM1Y3ZDcoqVRGBSAjki/QLtqWFeouiYdfCdzk80TccxORqNanK6ePQ1pTcOR/OtGToXeJEqqxX51wdSvWjCHGXmjjuQSM/Eznb86LbQtG79koqL4tuDVYvtrnIXUX7/aXicVmCT8gNFxZBP3uX6OJLT0CCZol2F/mu6pq7JLbhhfRCv6/NgAAAAAAAAAEAAAABAAAADHVzZXJfamVyb2VucwAAABYAAAAHamVyb2VuMQAAAAdqZXJvZW4yAAAAAFjtLVAAAAAAWO00lQAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQDZ0a09cp+hsK7F5eg4etwemWyJjA97LlSxAsWOxNNOskNi2FDrhYCpMejr1rdrB1yHy3UYlG0AG3bmzX10uyad17/AHlKvNMQh6rysbe6DDgdPOVQtZv5UCCuvPDnnUAn++SXqxYbvVFSK48BJXeRk2mKrnC2iWsnJCW81j9ICA2S4LEtYE0DiYRrM2UT9lUgmcwxLGqL6JkWbJTF+5KLyRvPGtb06Uo5KOdFlyjEVZ437j/wNTrn2tbQJaMT5qaNuh4Py8WV7aCnX73YfJHdrnCbhOP1MBX9nT+dpMsLYXnCi0K/LLCKJIWn8yNwxPmrUc0OkqOYQWbjGkKn2dt/3AAABDwAAAAdzc2gtcnNhAAABACvwMQl9HsmjpLEt2MMhwyyTcwYsy6lUNa0lWs/YJlR70e/EzriZZVwXGpNYnXW5KgXOA020bhXgpPijBqWOxOAoHyE1CpLAuMDpYAxjnlNy391GzcUrQM74nPeBuE1TGpatS314Gx+iv98EaPdlvtommgh/Ggsb48n9xNrOuonYXwgUOpjvPYlDWvB3klUea4qvhru/23xzKf7DuIGSffB++IANkm1+TJ8vskE44F/VvVo4CCKEY7HaRHTSvfQ4yaNJCEWg0KcFbI79ICbB3mpHRKeDaqjJj4+6858D4/SYrBPOoCr8QNWR/kvYjrWD5qvHZMLO6x+3lEDuh76MNbk= choover@ma-lt-choover diff --git a/src/test/resources/keytypes/certificate/test_dsa b/src/test/resources/keytypes/certificate/test_dsa new file mode 100644 index 00000000..b7fd06c4 --- /dev/null +++ b/src/test/resources/keytypes/certificate/test_dsa @@ -0,0 +1,15 @@ +-----BEGIN DSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,F30B96BBE72D14E7E408E43D484642E1 + +A+fs86aamKouxGIQLbJc8dF6wzUqXo5stco6SjGFA78mutESj6EWWnU49/JAyWmK +t20qKnnOlRNVVGw8h+FoRR1ukA9hkcc4Yg8bvHw21B45bswd165gJPLoOsacocr+ +487GztRao44+bT5tzkS/pCo0ianjJpfmlRPr8tVkrM0lA9SYWuVjhzm20mKfW8Q0 +iQk4xZMDS01BZ2BM1cEs8YsR5xXwV84i9iS9Evr5J3+V3xhilZiNSiYLT2kqQ+u7 +ccqVgybUb7OF2nd1GDY75E3hY0V+pXjPzFn0Er2hK8o76W61s52baVr2xOTq/wmH +Ra3FCzj8M7xagprOYsVqza7oLt6lOK4VJQzFntoCDNpAqZDL77vFJz+0E2ZI/+cG +1HSt889w0obu6D1XorsBx+LuNJZqwMtwYQMbjr1fXvRLktM4E0gUfyFgeGYJqvl+ +4AV24MII/+D1K5pnA3Q0Ban+dpLUqH9dGd7dplol12gzSpRtLHRgjv/GggZUIUjh +MBTGdLkMHjteph0VFxeNiahydV707Gz9oc35e1MzeAi8dDqPNM7T1XDLV6Tqm2+x +j2KBlXpkVhHEJ3IvDxO+1g== +-----END DSA PRIVATE KEY----- diff --git a/src/test/resources/keytypes/certificate/test_dsa-cert.pub b/src/test/resources/keytypes/certificate/test_dsa-cert.pub new file mode 100644 index 00000000..90d5fd67 --- /dev/null +++ b/src/test/resources/keytypes/certificate/test_dsa-cert.pub @@ -0,0 +1 @@ +ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAguS/sL4az6garEmUIM9ELqcaEfRJlPICG3lGthEJsWwEAAACBAJuvlcNNkgWfJV8y4HWxzith+6EZLGfd3jYqfXmITYDW8830cAmU7xC/aXK5r0LaSKxpyW/G/Z1396j69yxN1R1EC4fDvcEjTzmkcxKTrm8FQzFew7rkpm5H6MZq7PfrA/ph1nrDNLzO8Pzbw4trrr5yHuh3pQHt/WBSz+PiZPULAAAAFQDyrWY0qq7RR2NOslTkL7iBRVihKwAAAIA68Qp50ZqMvlGbnQQdYlH5HG1+tTs56Arc1Dgau8npyH9kTb0txpdijIwXhbwRN2eq0KQ3iF1XOzJSI5nWH2ONaaxK3Da4o8yt7/PQUFBDYqDoE+59XGOsupVKwpFiRPJURigoT943XdYaTRP5lX9nztVb/lFqppG/hdH8iMVJVwAAAIAbgIwWCMroqlEdsXKyM3wzYEHj8jTPTdr00WpV/WBghYittcfV3Cwp8HNSe1OyiA240CMFVLaKGr9PdoqU/an9WHb1skTuz2UNBs8uKJY3pISAZXHiOkza07iwTUcvQTZS+CctIlL1kxj2LTkI/Auy+Eiup40lrbIm87F6+LwSXgAAAAAAAAB7AAAAAQAAAAd0ZXN0ZHNhAAAACgAAAAZqZXJvZW4AAAAAWO1MfAAAAABY7dmJAAAAJAAAAA5zb3VyY2UtYWRkcmVzcwAAAA4AAAAKMTAuMC4wLjAvOAAAABIAAAAKcGVybWl0LXB0eQAAAAAAAAAAAAABsgAAAAdzc2gtZHNzAAAAgQCVc14O81iWe8XfsffXLYwzGr39QrlPQum2WLr3TfRCT+yKkyu3sLBO+3d25XpD1U2MQ1RJ7aJGET0m3QrO3U4CZGV2Fl3e6aLVrzvppR+LHoZa+kOl1bHfiCJ6NLib2bYNa1lIJ5L74lwYK9ZZ85M0Sun0DbNyNOgUX3OcG7oZiQAAABUA1x8Y8ZPR70C/BtQDnjq5Lx+p/cMAAACAGcSOjhD111FJMmi2T1nqyAjMreZx7CfQyfmg+s3dsePm8qsBZNiGRUVgCen14293O1AcMiBsGxI2a2+Kb4V3VzuT64zucrw51ZuqXu79T+KXDdTifgNoNFVPg+sorXyuzc0Z33BTdY8NAkpjJbjhKCYs3FVa4ygGNDC9pyh7nHsAAACBAIxQmlDKKcu0chmM9WjDqSosKJxADRtLmD1Drv1ag2DF3cKFPH5xtFqSpF9bsKeuhIhWeXiwytfeeHufdvno2VTvBJkOFFj5b4jsB2s3GyyJT9Z9TWFYecIj3t8t3QLlmDnGr8cHwmHpcbZmPBnm1hM9DA9OWkQaJWHccsjwSLI0AAAANwAAAAdzc2gtZHNzAAAAKDyWWSqjzoS2RmaBcm1CXVU7ZIx4yg3SAJEGP+ss0Jw27PjDhe54OJ4= choover@ma-lt-choover diff --git a/src/test/resources/keytypes/certificate/test_rsa b/src/test/resources/keytypes/certificate/test_rsa new file mode 100644 index 00000000..2800c8a7 --- /dev/null +++ b/src/test/resources/keytypes/certificate/test_rsa @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,5F1AEDBE1E9E4D83EBD9C7B71CD84DB5 + +N8SuKdWK3dEA7K6dNodjE++qqXPpVXJlDhiJbrXm1vbs2u+hckzZflK9OQZU1SsY +hs6ZyFg/jagdMNEKKrCEK60QMcMg1iPlkMvTwEvQmdWSWtMiTFes9Ec4njUbcbgN +qHzixGfWjpTXCRq3QC2Bydq7+njvIEUeLIjTaCIXqwoZoMcBc0N6Aj529gbgDD/i +JC0auaSfejSZQm4Ppn+OuO1JKgNkwsjoTrrZjbKHuayYQaioaR5OcAKgSSs5YDdo +SJI+PDeIOVb6aMcXwYP5J7C9zzkZU1Ml3dGHk2JMs0Omu2gICRm3mXXmoHRkiBKj +2h7EsghiV/Be4lkOF+T3HN19F4G44EIUj7DotbtqNPEFRZa+SSpN3OZmLJQSwBXD +A0zek5BxDu7M4VfbLryxNWcHinLe8fBKLQJe3F2/c5ZbMA4Z9098FIL1xWOqvbzS +SjiuWhIDxdYVeVe579mUlWjPrMF3NnD4BP9oQlYmbSTxL7B486Ckh7ACFzQhUXVV +t2JNZC2FcxM2WU7cHABvGUQNeq/Y2pB5Xq8AmzdpdAs2VZLHtgOvmnPjfo+Q3s1Y +rlRe5sCkyn0Ju4M09sMBIQfwszVKa3/l/ZVrG5LCOEHkF+35ex6Gz8ePRlm5jhnU +ZQVuLjxbnjnDMaJ0c0IoW7s44cdEDkv3fDzfQHrPzM50oFUN5WOKKWFnT4V1DBLJ +9YW8AcNL6bSlgZNkLntn5Wvl3BBKbf5SMmqegfR3eqz50KNwzKKQU8dcIwkJsK2s +Z5fNWbydgNDZhrebJL/jpuXpXcvfO0cVMja7y/O0bQ6M37Arpk8bQhTBKZZSaXeF +I0Bx3IOxsodWpA9O3Yum8fqqPGrCxsAsP/mWNG0Ov29Myi3MeZ0zgQH283En0Pnx +8hvDlw8vNcFe22Jycgg4846FlIWzkT7VfDVxDoYCyjlMTZ2ASys8llH5in4i1w4m +j0ZREJE/+evCXBHLoTO96Rgnjt7hp9g62FHJ+ivRlCQVY6sTB03GNv//4v7xGMPF +S4eBB9gnGKEEe8zRcOPgUEhUOrFv9cUpdhYz/SLuTZIPPiNwkAMZ6zM77FMsrdWw +18wiemOhizCd/JZDlH9COue6EXnr7rexmTp7rUsJOTq8q3rpYmz2s0rGJbqxyxlq +BiCjJqN004ZmtFCTD0wCGuNsVLiNyWSspIfzWXkfCyO0SbiH8QjlkUZVr456/5sI +cvCQ3ltAFfxR8wMZlfgtT3mEu8JAQCml89yMbttisdfz48XnLeXAzZuZzEr4OllN +AMQ8RINlZC2fxqV25jJi+E1da0yvwM9x0NPaM/ZUQqGzMf+dGldcVWdlNFBsthx0 +wULaGfTYmmn6rBdbeGlt0JKGGL8Ak8+adNSHHxaJuL9W/5wLH41HsE89ZldlTHuI +GeHM1lDA/DwO85c4Fk7Ai0Ny44PjdGn27pLNhAfoT2HivF7zMNV+SUXU57iL/qdR +yJYGZJyXdreK4qaSCx7BdaK0AFvhBTXW/uRXJCX/XW6zdzdqy5/wkqWt1sWHKTxf +Z0CBKWd/se6JCQoixG2Cpo87SeLZsJEscK8eDdLDQwJdKdmIqgw6LddF7RPpq/5D +-----END RSA PRIVATE KEY----- diff --git a/src/test/resources/keytypes/certificate/test_rsa-cert.pub b/src/test/resources/keytypes/certificate/test_rsa-cert.pub new file mode 100644 index 00000000..33c172bb --- /dev/null +++ b/src/test/resources/keytypes/certificate/test_rsa-cert.pub @@ -0,0 +1 @@ +ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgb0+Llm+3BKq6n5YoMepI1/Iqp4WnSFYYbpm9Y0jLbJMAAAADAQABAAABAQDF9lt1iAGZWGqNtKR05HRMSyRSG2li0Hq732U2yQ9MmWSAEwltBXILCUrTnkJOWIMYyKY4Y22K+aIWMmnJdE8sehfZ6d+gz20yZ8kHndB7CnKn6oxh6kW5NAGye3kDR808L836U2VxMMgpTH/lBi4909tKf6vAY2qoG/LW4ftFWcf0jU7U8lwlvJ4mjJ9Ld5ObaJOa1h3URHWpiXuSa/JFVTMVAz8Z7h6hXpwruv2HQlKJGs2axP71pGR6Vni2fDZ4kWn5dObv2OA5VLiTD+YZtQ0edAEKORyETaCDwgCgX4qNwdGE/A37c1B6K6tGZrWGjXaPACpOFjwjVVhEI8TPgAAAAAAAAAEAAAABAAAAB3Rlc3Ryc2EAAAAUAAAABmplcm9lbgAAAAZub2JvZHkAAAAAWO1MuAAAAABY7VQXAAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAARcAAAAHc3NoLXJzYQAAAAMBAAEAAAEBANnRrT1yn6GwrsXl6Dh63B6ZbImMD3suVLECxY7E006yQ2LYUOuFgKkx6OvWt2sHXIfLdRiUbQAbdubNfXS7Jp3Xv8AeUq80xCHqvKxt7oMOB085VC1m/lQIK688OedQCf75JerFhu9UVIrjwEld5GTaYqucLaJayckJbzWP0gIDZLgsS1gTQOJhGszZRP2VSCZzDEsaovomRZslMX7kovJG88a1vTpSjko50WXKMRVnjfuP/A1Oufa1tAloxPmpo26Hg/LxZXtoKdfvdh8kd2ucJuE4/UwFf2dP52kywthecKLQr8ssIokhafzI3DE+atRzQ6So5hBZuMaQqfZ23/cAAAEPAAAAB3NzaC1yc2EAAAEA0uyAwWCFNFEZXLuy1+lwd9VtgCcC50HKMyHywKzkyKlDIbsKbCLcQG74f0nDP7c+8jAFRCxLfaGZ55SYXkPoXMOPqFsln7YvidC7nlKhF2Q7FgOBd04SoriAvi1M24EAE+Y9LUz6idLEuegXt32cobv+fqVKRBZ0V6UpDc5W58/6lDk2YMNOIbQQNy34Lf1HqIhxaWC6pmnT3rPcZylvZI7wP58DdhInWoEVMZawZ0m0Py2C2Pb7zOwFY81nXucCHUfCL4UngN1QOLg9/0vwGZmUVkTnPsbeH6gcBoQY6XdjbPB8HP/a1Ugr2wsTyFJKdc1+5r/KtcCLiXe1SmmHQA== choover@ma-lt-choover diff --git a/src/test/resources/keytypes/certificate/test_rsa.pub b/src/test/resources/keytypes/certificate/test_rsa.pub new file mode 100644 index 00000000..0c054c16 --- /dev/null +++ b/src/test/resources/keytypes/certificate/test_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDF9lt1iAGZWGqNtKR05HRMSyRSG2li0Hq732U2yQ9MmWSAEwltBXILCUrTnkJOWIMYyKY4Y22K+aIWMmnJdE8sehfZ6d+gz20yZ8kHndB7CnKn6oxh6kW5NAGye3kDR808L836U2VxMMgpTH/lBi4909tKf6vAY2qoG/LW4ftFWcf0jU7U8lwlvJ4mjJ9Ld5ObaJOa1h3URHWpiXuSa/JFVTMVAz8Z7h6hXpwruv2HQlKJGs2axP71pGR6Vni2fDZ4kWn5dObv2OA5VLiTD+YZtQ0edAEKORyETaCDwgCgX4qNwdGE/A37c1B6K6tGZrWGjXaPACpOFjwjVVhEI8TP choover@ma-lt-choover