You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2020/05/22 16:46:37 UTC
[mina-sshd] 02/02: [SSHD-989] Fixed parsing of PKCS8 encoded PEM
private key files
This is an automated email from the ASF dual-hosted git repository.
lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
commit d14a99bb5504198111cbe5514063747a98e8d2f5
Author: Lyor Goldstein <lg...@apache.org>
AuthorDate: Fri May 22 16:08:28 2020 +0300
[SSHD-989] Fixed parsing of PKCS8 encoded PEM private key files
---
CHANGES.md | 2 +-
.../loader/pem/ECDSAPEMResourceKeyPairParser.java | 113 ++++++++++++++-------
.../loader/pem/PKCS8PEMResourceKeyPairParser.java | 15 ++-
.../keys/loader/pem/PKCS8PrivateKeyInfo.java | 39 ++++++-
.../apache/sshd/common/util/io/der/DERParser.java | 6 ++
.../sshd/common/config/keys/KeyUtilsCloneTest.java | 1 -
.../pem/PKCS8PEMResourceKeyPairParserTest.java | 40 ++++----
.../common/config/keys/loader/pem/pkcs8-ec-256.pem | 5 +
.../common/config/keys/loader/pem/pkcs8-ec-384.pem | 6 ++
.../common/config/keys/loader/pem/pkcs8-ec-521.pem | 8 ++
.../config/keys/loader/pem/pkcs8-rsa-1024.pem | 16 +++
.../config/keys/loader/pem/pkcs8-rsa-2048.pem | 28 +++++
.../config/keys/loader/pem/pkcs8-rsa-3072.pem | 40 ++++++++
.../config/keys/loader/pem/pkcs8-rsa-4096.pem | 52 ++++++++++
14 files changed, 307 insertions(+), 64 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index 1495950..001985f 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -57,4 +57,4 @@ as much of the available functionality as possible.
* [SSHD-998](https://issues.apache.org/jira/browse/SSHD-998) - Take into account SFTP version preference when establishing initial channel
-* [SSHD-989](https://issues.apache.org/jira/browse/SSHD-989) - Implement ECDSA public key recovery for PKCS8 encoded data
+* [SSHD-989](https://issues.apache.org/jira/browse/SSHD-989) - Read correctly ECDSA key pair from PKCS8 encoded data
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/ECDSAPEMResourceKeyPairParser.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/ECDSAPEMResourceKeyPairParser.java
index 0fe9b15..08fe839 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/ECDSAPEMResourceKeyPairParser.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/ECDSAPEMResourceKeyPairParser.java
@@ -87,14 +87,23 @@ public class ECDSAPEMResourceKeyPairParser extends AbstractPEMResourceKeyPairPar
InputStream inputStream, boolean okToClose)
throws IOException, GeneralSecurityException {
try (DERParser parser = new DERParser(NoCloseInputStream.resolveInputStream(inputStream, okToClose))) {
- return parseECKeyPair(parser);
+ return parseECKeyPair(null, parser);
}
}
- public static KeyPair parseECKeyPair(DERParser parser)
+ /**
+ * @param curve The {@link ECCurves curve} represented by this data (in case it was optional and
+ * somehow known externally) if {@code null} then it is assumed to be part of the
+ * parsed data. then it is assumed to be part of the data.
+ * @param parser The {@link DERParser} for the data
+ * @return The parsed {@link KeyPair}
+ * @throws IOException If failed to parse the data
+ * @throws GeneralSecurityException If failed to generate the keys
+ */
+ public static KeyPair parseECKeyPair(ECCurves curve, DERParser parser)
throws IOException, GeneralSecurityException {
ASN1Object sequence = parser.readObject();
- Map.Entry<ECPublicKeySpec, ECPrivateKeySpec> spec = decodeECPrivateKeySpec(sequence);
+ Map.Entry<ECPublicKeySpec, ECPrivateKeySpec> spec = decodeECPrivateKeySpec(curve, sequence);
if (!SecurityUtils.isECCSupported()) {
throw new NoSuchProviderException("ECC not supported");
}
@@ -136,12 +145,14 @@ public class ECDSAPEMResourceKeyPairParser extends AbstractPEMResourceKeyPairPar
* </CODE>
* </PRE>
*
+ * @param curve The {@link ECCurves curve} represented by this data (in case it was optional and somehow
+ * known externally) if {@code null} then it is assumed to be part of the parsed data.
* @param sequence The {@link ASN1Object} sequence containing the DER encoded data
* @return The decoded {@link SimpleImmutableEntry} of {@link ECPublicKeySpec} and
* {@link ECPrivateKeySpec}
* @throws IOException If failed to to decode the DER stream
*/
- public static SimpleImmutableEntry<ECPublicKeySpec, ECPrivateKeySpec> decodeECPrivateKeySpec(ASN1Object sequence)
+ public static Map.Entry<ECPublicKeySpec, ECPrivateKeySpec> decodeECPrivateKeySpec(ECCurves curve, ASN1Object sequence)
throws IOException {
ASN1Type objType = (sequence == null) ? null : sequence.getObjType();
if (!ASN1Type.SEQUENCE.equals(objType)) {
@@ -149,13 +160,10 @@ public class ECDSAPEMResourceKeyPairParser extends AbstractPEMResourceKeyPairPar
}
try (DERParser parser = sequence.createParser()) {
- ECPrivateKeySpec prvSpec = decodeECPrivateKeySpec(parser);
- ECCurves curve = ECCurves.fromCurveParameters(prvSpec.getParams());
- if (curve == null) {
- throw new StreamCorruptedException("Unknown curve");
- }
-
- ECPoint w = decodeECPublicKeyValue(curve, parser);
+ Map.Entry<ECPrivateKeySpec, ASN1Object> result = decodeECPrivateKeySpec(curve, parser);
+ ECPrivateKeySpec prvSpec = result.getKey();
+ ASN1Object publicData = result.getValue();
+ ECPoint w = (publicData == null) ? decodeECPublicKeyValue(parser) : decodeECPointData(publicData);
ECPublicKeySpec pubSpec = new ECPublicKeySpec(w, prvSpec.getParams());
return new SimpleImmutableEntry<>(pubSpec, prvSpec);
}
@@ -171,7 +179,8 @@ public class ECDSAPEMResourceKeyPairParser extends AbstractPEMResourceKeyPairPar
* publicKey [1] BIT STRING OPTIONAL
* }
*/
- public static final ECPrivateKeySpec decodeECPrivateKeySpec(DERParser parser) throws IOException {
+ public static Map.Entry<ECPrivateKeySpec, ASN1Object> decodeECPrivateKeySpec(ECCurves curve, DERParser parser)
+ throws IOException {
// see openssl asn1parse -inform PEM -in ...file... -dump
ASN1Object versionObject = parser.readObject();
if (versionObject == null) {
@@ -208,12 +217,36 @@ public class ECDSAPEMResourceKeyPairParser extends AbstractPEMResourceKeyPairPar
* curve domain parameters. Though the ASN.1 indicates that the parameters field is OPTIONAL, implementations
* that conform to this document MUST always include the parameters field.
*/
- ASN1Object paramsObject = parser.readObject();
+ Map.Entry<ECCurves, ASN1Object> result = parseCurveParameter(parser);
+ ECCurves namedParam = (result == null) ? null : result.getKey();
+ if (namedParam == null) {
+ if (curve == null) {
+ throw new StreamCorruptedException("Cannot determine curve type");
+ }
+ } else if (curve == null) {
+ curve = namedParam;
+ } else if (namedParam != curve) {
+ throw new StreamCorruptedException("Mismatched provide (" + curve + ") vs. parsed curve (" + namedParam + ")");
+ }
+
+ BigInteger s = ECCurves.octetStringToInteger(keyObject.getPureValueBytes());
+ ECPrivateKeySpec keySpec = new ECPrivateKeySpec(s, curve.getParameters());
+ return new SimpleImmutableEntry<>(keySpec, (result == null) ? null : result.getValue());
+ }
+
+ public static Map.Entry<ECCurves, ASN1Object> parseCurveParameter(DERParser parser) throws IOException {
+ return parseCurveParameter(parser.readObject());
+ }
+
+ public static Map.Entry<ECCurves, ASN1Object> parseCurveParameter(ASN1Object paramsObject) throws IOException {
if (paramsObject == null) {
- throw new StreamCorruptedException("No parameters value");
+ return null;
}
- // TODO make sure params object tag is 0xA0
+ ASN1Type objType = paramsObject.getObjType();
+ if (objType == ASN1Type.NULL) {
+ return null;
+ }
List<Integer> curveOID;
try (DERParser paramsParser = paramsObject.createParser()) {
@@ -223,10 +256,13 @@ public class ECDSAPEMResourceKeyPairParser extends AbstractPEMResourceKeyPairPar
}
/*
- * SSHD-989 - if object type is BIT STRING then this is the public
- * key - in which case we need to figure out some other way to recover
- * the curve parameters
+ * The curve OID is OPTIONAL - if it is not there then the
+ * public key data replaces it
*/
+ objType = namedCurve.getObjType();
+ if (objType == ASN1Type.BIT_STRING) {
+ return new SimpleImmutableEntry<>(null, namedCurve);
+ }
curveOID = namedCurve.asOID();
}
@@ -236,8 +272,7 @@ public class ECDSAPEMResourceKeyPairParser extends AbstractPEMResourceKeyPairPar
throw new StreamCorruptedException("Unknown curve OID: " + curveOID);
}
- BigInteger s = ECCurves.octetStringToInteger(keyObject.getPureValueBytes());
- return new ECPrivateKeySpec(s, curve.getParameters());
+ return new SimpleImmutableEntry<>(curve, null);
}
/**
@@ -252,14 +287,16 @@ public class ECDSAPEMResourceKeyPairParser extends AbstractPEMResourceKeyPairPar
* </code>
* </pre>
*
- * @param curve The {@link ECCurves} curve
* @param parser The {@link DERParser} assumed to be positioned at the start of the data
* @return The encoded {@link ECPoint}
* @throws IOException If failed to create the point
*/
- public static final ECPoint decodeECPublicKeyValue(ECCurves curve, DERParser parser) throws IOException {
+ public static final ECPoint decodeECPublicKeyValue(DERParser parser) throws IOException {
+ return decodeECPublicKeyValue(parser.readObject());
+ }
+
+ public static final ECPoint decodeECPublicKeyValue(ASN1Object dataObject) throws IOException {
// see openssl asn1parse -inform PEM -in ...file... -dump
- ASN1Object dataObject = parser.readObject();
if (dataObject == null) {
throw new StreamCorruptedException("No public key data bytes");
}
@@ -267,24 +304,26 @@ public class ECDSAPEMResourceKeyPairParser extends AbstractPEMResourceKeyPairPar
/*
* According to https://tools.ietf.org/html/rfc5915
*
- * Though the ASN.1 indicates publicKey is OPTIONAL, implementations that conform to this document SHOULD always
- * include the publicKey field
+ * Though the ASN.1 indicates publicKey is OPTIONAL, implementations
+ * that conform to this document SHOULD always include the publicKey field
*/
try (DERParser dataParser = dataObject.createParser()) {
- ASN1Object pointData = dataParser.readObject();
- if (pointData == null) {
- throw new StreamCorruptedException("Missing public key data parameter");
- }
+ return decodeECPointData(dataParser.readObject());
+ }
+ }
- ASN1Type objType = pointData.getObjType();
- if (!ASN1Type.BIT_STRING.equals(objType)) {
- throw new StreamCorruptedException("Non-matching public key object type: " + objType);
- }
+ public static final ECPoint decodeECPointData(ASN1Object pointData) throws IOException {
+ if (pointData == null) {
+ throw new StreamCorruptedException("Missing public key data parameter");
+ }
- // see https://tools.ietf.org/html/rfc5480#section-2.2
- byte[] octets = pointData.getValue();
- return ECCurves.octetStringToEcPoint(octets);
+ ASN1Type objType = pointData.getObjType();
+ if (!ASN1Type.BIT_STRING.equals(objType)) {
+ throw new StreamCorruptedException("Non-matching public key object type: " + objType);
}
- }
+ // see https://tools.ietf.org/html/rfc5480#section-2.2
+ byte[] octets = pointData.getValue();
+ return ECCurves.octetStringToEcPoint(octets);
+ }
}
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParser.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParser.java
index f871a3a..3207c38 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParser.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParser.java
@@ -34,6 +34,7 @@ import java.util.List;
import java.util.Map;
import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.cipher.ECCurves;
import org.apache.sshd.common.config.keys.FilePasswordProvider;
import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.session.SessionContext;
@@ -41,6 +42,7 @@ import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.common.util.io.der.ASN1Object;
+import org.apache.sshd.common.util.io.der.ASN1Type;
import org.apache.sshd.common.util.io.der.DERParser;
import org.apache.sshd.common.util.security.SecurityUtils;
@@ -91,8 +93,19 @@ public class PKCS8PEMResourceKeyPairParser extends AbstractPEMResourceKeyPairPar
if (SecurityUtils.isECCSupported()
&& ECDSAPEMResourceKeyPairParser.ECDSA_OID.equals(oid)) {
ASN1Object privateKeyBytes = pkcs8Info.getPrivateKeyBytes();
+ ASN1Object extraInfo = pkcs8Info.getAlgorithmParameter();
+ ASN1Type objType = (extraInfo == null) ? ASN1Type.NULL : extraInfo.getObjType();
+ List<Integer> oidCurve = (objType == ASN1Type.NULL) ? Collections.emptyList() : extraInfo.asOID();
+ ECCurves curve = null;
+ if (GenericUtils.isNotEmpty(oidCurve)) {
+ curve = ECCurves.fromOIDValue(oidCurve);
+ if (curve == null) {
+ throw new NoSuchAlgorithmException("Cannot match EC curve OID=" + oidCurve);
+ }
+ }
+
try (DERParser parser = privateKeyBytes.createParser()) {
- kp = ECDSAPEMResourceKeyPairParser.parseECKeyPair(parser);
+ kp = ECDSAPEMResourceKeyPairParser.parseECKeyPair(curve, parser);
}
} else {
PrivateKey prvKey = decodePEMPrivateKeyPKCS8(oidAlgorithm, encBytes);
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PrivateKeyInfo.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PrivateKeyInfo.java
index 48917a5..b8732b5 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PrivateKeyInfo.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PrivateKeyInfo.java
@@ -55,6 +55,7 @@ import org.apache.sshd.common.util.io.der.DERParser;
public class PKCS8PrivateKeyInfo /* TODO Cloneable */ {
private BigInteger version;
private List<Integer> algorithmIdentifier;
+ private ASN1Object algorithmParameter;
private ASN1Object privateKeyBytes;
public PKCS8PrivateKeyInfo() {
@@ -89,6 +90,14 @@ public class PKCS8PrivateKeyInfo /* TODO Cloneable */ {
this.algorithmIdentifier = algorithmIdentifier;
}
+ public ASN1Object getAlgorithmParameter() {
+ return algorithmParameter;
+ }
+
+ public void setAlgorithmParameter(ASN1Object algorithmParameter) {
+ this.algorithmParameter = algorithmParameter;
+ }
+
public ASN1Object getPrivateKeyBytes() {
return privateKeyBytes;
}
@@ -115,6 +124,21 @@ public class PKCS8PrivateKeyInfo /* TODO Cloneable */ {
* @throws IOException If failed to parse the encoding
*/
public void decode(ASN1Object privateKeyInfo) throws IOException {
+ /*
+ * SEQUENCE {
+ * INTEGER 0x00 (0 decimal)
+ * SEQUENCE {
+ * OBJECTIDENTIFIER encryption type
+ * OBJECTIDENTIFIER extra info - may be NULL
+ * }
+ * OCTETSTRING private key
+ * }
+ */
+ ASN1Type objType = privateKeyInfo.getObjType();
+ if (objType != ASN1Type.SEQUENCE) {
+ throw new StreamCorruptedException("Not a top level sequence: " + objType);
+ }
+
try (DERParser parser = privateKeyInfo.createParser()) {
ASN1Object versionObject = parser.readObject();
if (versionObject == null) {
@@ -128,10 +152,21 @@ public class PKCS8PrivateKeyInfo /* TODO Cloneable */ {
throw new StreamCorruptedException("No private key algorithm");
}
+ objType = privateKeyInfo.getObjType();
+ if (objType != ASN1Type.SEQUENCE) {
+ throw new StreamCorruptedException("Not an algorithm parameters sequence: " + objType);
+ }
+
try (DERParser oidParser = privateKeyAlgorithm.createParser()) {
ASN1Object oid = oidParser.readObject();
setAlgorithmIdentifier(oid.asOID());
- // TODO add optional algorithm identifier parameters parsing
+
+ // Extra information is OPTIONAL
+ ASN1Object extraInfo = oidParser.readObject();
+ objType = (extraInfo == null) ? ASN1Type.NULL : extraInfo.getObjType();
+ if (objType != ASN1Type.NULL) {
+ setAlgorithmParameter(extraInfo);
+ }
}
ASN1Object privateKeyData = parser.readObject();
@@ -139,7 +174,7 @@ public class PKCS8PrivateKeyInfo /* TODO Cloneable */ {
throw new StreamCorruptedException("No private key data");
}
- ASN1Type objType = privateKeyData.getObjType();
+ objType = privateKeyData.getObjType();
if (objType != ASN1Type.OCTET_STRING) {
throw new StreamCorruptedException("Private key data not an " + ASN1Type.OCTET_STRING + ": " + objType);
}
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/io/der/DERParser.java b/sshd-common/src/main/java/org/apache/sshd/common/util/io/der/DERParser.java
index 4a4536e..a9fde49 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/io/der/DERParser.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/io/der/DERParser.java
@@ -27,6 +27,7 @@ import java.io.StreamCorruptedException;
import java.math.BigInteger;
import java.util.Arrays;
+import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.NumberUtils;
import org.apache.sshd.common.util.buffer.BufferUtils;
@@ -122,6 +123,11 @@ public class DERParser extends FilterInputStream {
return null;
}
+ ASN1Type objType = ASN1Type.fromDERValue(tag);
+ if (objType == ASN1Type.NULL) {
+ return new ASN1Object((byte) tag, 0, GenericUtils.EMPTY_BYTE_ARRAY);
+ }
+
int length = readLength();
byte[] value = new byte[length];
int n = read(value);
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsCloneTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsCloneTest.java
index 0b64d08..5b3e9e6 100644
--- a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsCloneTest.java
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsCloneTest.java
@@ -116,5 +116,4 @@ public class KeyUtilsCloneTest extends JUnitTestSupport {
assertTrue(prefix + ": Cloned private key not equals", KeyUtils.compareKeys(k1, k2));
}
}
-
}
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java
index 6d62616..76b9224 100644
--- a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java
+++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java
@@ -26,7 +26,6 @@ import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
-import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -43,7 +42,6 @@ import org.apache.sshd.util.test.JUnitTestSupport;
import org.apache.sshd.util.test.NoIoTestCase;
import org.junit.Assume;
import org.junit.FixMethodOrder;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
@@ -81,6 +79,11 @@ public class PKCS8PEMResourceKeyPairParserTest extends JUnitTestSupport {
}
if (SecurityUtils.isECCSupported()) {
for (ECCurves curve : ECCurves.VALUES) {
+ if (!curve.isSupported()) {
+ outputDebugMessage("Skip unsupported curve=%s", curve);
+ continue;
+ }
+
params.add(new Object[] { KeyUtils.EC_ALGORITHM, curve.getKeySize() });
}
}
@@ -88,7 +91,7 @@ public class PKCS8PEMResourceKeyPairParserTest extends JUnitTestSupport {
}
@Test // see SSHD-760
- public void testPkcs8() throws IOException, GeneralSecurityException {
+ public void testLocallyGeneratedPkcs8() throws IOException, GeneralSecurityException {
KeyPairGenerator generator = SecurityUtils.getKeyPairGenerator(algorithm);
if (keySize > 0) {
generator.initialize(keySize);
@@ -114,14 +117,18 @@ public class PKCS8PEMResourceKeyPairParserTest extends JUnitTestSupport {
}
}
- // see https://gist.github.com/briansmith/2ee42439923d8e65a266994d0f70180b
- // openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -pkeyopt ec_param_enc:named_curve -out pkcs8-ecdsa-256.pem
- // openssl ecparam -genkey -name prime256v1 -noout -out pkcs8-ec-256.key
- // openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in pkcs8-ec-256.key -out pkcs8-ec-256.pem
- // openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:1024 -out pkcs8-rsa-1024.pem
- // openssl asn1parse -inform PEM -in ...file... -dump
+ /*
+ * See https://gist.github.com/briansmith/2ee42439923d8e65a266994d0f70180b
+ *
+ * openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:1024 -out pkcs8-rsa-1024.pem
+ * openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -pkeyopt ec_param_enc:named_curve -out pkcs8-ecdsa-256.pem
+ *
+ * openssl ecparam -genkey -name prime256v1 -noout -out pkcs8-ec-256.key
+ * openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in pkcs8-ec-256.key -out pkcs8-ec-256.pem
+ *
+ * openssl asn1parse -inform PEM -in ...file... -dump
+ */
@Test // see SSHD-989
- @Ignore("WIP")
public void testPKCS8FileParsing() throws Exception {
String resourceKey = "pkcs8-" + algorithm.toLowerCase() + "-" + keySize + ".pem";
URL url = getClass().getResource(resourceKey);
@@ -129,18 +136,7 @@ public class PKCS8PEMResourceKeyPairParserTest extends JUnitTestSupport {
Collection<KeyPair> pairs = PKCS8PEMResourceKeyPairParser.INSTANCE.loadKeyPairs(null, url, null);
assertEquals("Mismatched extract keys count", 1, GenericUtils.size(pairs));
-
- assertSignatureMatch("Cannot sign with recovered key pair", GenericUtils.head(pairs));
- }
-
- private static void assertSignatureMatch(String message, KeyPair kp) throws GeneralSecurityException {
- assertSignatureMatch(message, kp.getPrivate(), kp.getPublic());
- }
-
- private static void assertSignatureMatch(
- String message, PrivateKey privateKey, PublicKey publicKey)
- throws GeneralSecurityException {
- // TODO
+ validateKeyPairSignable(algorithm + "/" + keySize, GenericUtils.head(pairs));
}
@Override
diff --git a/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-ec-256.pem b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-ec-256.pem
new file mode 100644
index 0000000..d7727e1
--- /dev/null
+++ b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-ec-256.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgs6QE06EskVFA/o7i
+HrNnF9In14QcJC9EgkXsVFk+SWWhRANCAAT8lGjPLQVdmwglhBP9refqp9Mrr7AN
+pGSOy3cCDtG4JeRr25s+EXavossaZ9U8MWe39wWUV7yvz5BT5hA3HSig
+-----END PRIVATE KEY-----
diff --git a/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-ec-384.pem b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-ec-384.pem
new file mode 100644
index 0000000..e552dfa
--- /dev/null
+++ b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-ec-384.pem
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAKagn5+JY4/pjeHLUX
+IORdDtAd8l//84hnzxiWR80AHLnyI8N4YUp7zPGUY0n5/VehZANiAAQacLGO21zt
+XkO/jijS+1BMxfuZyvtDE0fyENi6FNsYz92s+szssUxLl1XPO1Bv7+xdX/nkqjbi
+V26a3G8VzoNUl8KNrYUfH+fcukhVKCU3A9VP8u1HZBhOIn+ouKUSj5E=
+-----END PRIVATE KEY-----
diff --git a/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-ec-521.pem b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-ec-521.pem
new file mode 100644
index 0000000..4281d87
--- /dev/null
+++ b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-ec-521.pem
@@ -0,0 +1,8 @@
+-----BEGIN PRIVATE KEY-----
+MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAliKmTYJEBwcWV4a+
+nbS69ht7d3mvUrp60m7T+gAXxUpb5XNWwaxa3PxRY9Mm4Or8mOfPa8d6rSlNARFP
+mU/zOFuhgYkDgYYABAAmm+nrn29TxAonRop25S9DFRX30ci2E+b3qDBy94N+A06n
+Q+wLo+vK95KbG461R9JUXBlH2qLQnLhUle5KpNw9nwAy5vZgrwqmCB1cdDarkTGr
+FpkVsrovB6mD7nxY/13wws1Ll1or3Bsb6ZQfnZ9VloaEVnnc0QLeO8HaRxif865D
+tA==
+-----END PRIVATE KEY-----
diff --git a/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-rsa-1024.pem b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-rsa-1024.pem
new file mode 100644
index 0000000..6f6df20
--- /dev/null
+++ b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-rsa-1024.pem
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALpizZejDUx5l83q
+I9Kg75KhYvj5mRVBdTRS8aN/bjiDNOn+yXeRVIB5Vw/r+V6N+1UzTcD+t4sC1b61
+mFgOqn5d9adDWw//zROovmCujqvJCDWTZPpuj/05u2BzlDzrkgTXQ/k4Owu9SjQQ
+hcrbkaHtvc1/Cfi1DfEv+n7FxABRAgMBAAECgYB9t9ku99cnhziittSU5OLTh7IH
+d+wOz0ksEupUOsbwrWeKkcX4tXlG8xGLdsKMSb6GWIWQsP7CcBYWfcyVUMckL4HP
+0jx+6hx7Y3uFtM1/MkucM0D+UAB6cQXHRr2xoRqpiQWBcOAL7dT7IBRMaB4iOGyI
+sDnsrucoX2hQU6kXQQJBAO8M4+XZgH2t/4HHA3Upmi5j0L7JmWusnq5Lhf8Va8mO
+fLIO0AuKuUtvhWlne3cyUZbaSBOE13DTwNn57LcGjikCQQDHmfpOXDrJCcOjKjQ5
+9g6oVWwU9SgZ51J3lVr83GaMCBdx0zMz5V7eGRsXudAHk6iVHdrznZBEdzWHAlmX
+8VXpAkEA1TqwRiQ+wtxj3wUABpA3YU3Ts3rsCOmPGXVwbtpSrRUWEVW5KbJyGeG+
+JQkTTn1p3Z+TTyXdblzT1xthlNiaEQJABHlaF/mPQ8RZQ0YF56qxR2qqwomAPZxm
+x9FsObDDB66CwAVo52fjyXysk8qRdCoGJFmH99/3ROGbLIyL75D0SQJBAI/EHfWS
+n3+A/S0R+rQ9GIKXa1Y5wEgVPYKk+YPLfxdOUEj5ZLI5jrE2mHn7ILFnyZpgci6l
+wxLeAa68VX4lp7g=
+-----END PRIVATE KEY-----
diff --git a/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-rsa-2048.pem b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-rsa-2048.pem
new file mode 100644
index 0000000..4942fb1
--- /dev/null
+++ b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-rsa-2048.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDJqeUR4mteSX3c
+UuZdaYOwdVcck2X9Ce02wxrUM/xa3NokhjQ+tNJY9FU8/fEYRASHMtUm3lBtnJkV
+XWHlA2BKl8oUbkFzfDCk3B1iXGjAZTVkSzImmhhqtgWcKZmGoL5Irf+8w4jHf8rQ
+5mp9hK3nQkTiAlELhAP2cEdDQcmynxN7zFkY0sMZQUeEQO1hHo+plwn3H33Cxq87
+XiyFKAJArqPmOEVkl/6oUY4MX5DRCPaYXGnINsAFY0PfmSPk1iV8HlevaeeiOmx2
+MNKiOw+PtlCr97QymmcdxKJzwmVKTLXrK9NHC8A/SJD6WUdY1aF1mjSVqeo/1y3f
+GfUF9MKZAgMBAAECggEBAKFhon1DcqTLrzsH5G5QqCAoZwPpOS7cKMcwL2IuD/8u
+yit8cobT8ZlaPnRGzA+dLvp6xXULZ9WwAhnE1ziMERzgh8j9ysb+VXc45xL13KZK
+2AVg38tgebW74JVt/Pxt2pkTFZsb53OvYsD2A7Za3Ug6EiHDtNPAW+N1SrIaDa0w
+kB+VMVVnaua+OuNBkrXEbhB14CJG/DGNiMvm6PkVNd9oQkbxykp1c6PU2ZQ4jJos
+6oKeqMwXSSvwWhen9YoYtSaff2bJRy6HWaPiRAHKFw1WQMoAksmAvBsU/nwA6c/t
+AOpzKcvX8b/VFlZpY9vdylXS/2ysK5lDTmXX9FWjhRkCgYEA73V7fnXJ10avbd85
+2/oTFmTB4rOg4a5VBqSy/AZiOwlLUyadUkyLR8gF7vsVB7PSnwH5HlGRORC+COnH
+GVj+44gq3EbjwucqeYlSizW8hjLFOpYcm0AP1naQCiiBG0xUxFwc8xyE0zu+V9KX
+8uHQTGejMEnz7Nx7j+LWxJchsEcCgYEA15gNeCaPb6TMR7LtUxtZ5+Rt0zLdG44Q
+yMmrReT79via7HkFyxOZaO+8tk6APBNGx1mU8IXYpZWK0CPIHeKlqI8roqlfWQdp
+XzQ7Zz1A4f02/o6DQtZthhTSg5K/iZ6Tb3KrKTuh0EO7yUfG+ybzfszwz8GJGdGt
+uIOY4gNrRh8CgYA2qwmgm1+TSE3wtY/OCs+kwygIi53lKBm9RIigRQzUEZEi0KQG
+D/eUUbQZFTV95q3lI1wucczHzGy2ODj+LnUymPnABGcnLgNib9lqcsAxmxGwCGlL
+gFqdScAksY6YHtsTYTwyvIYOe4s/HZMXHjqh1t9IvPl1T/jdppoFk8NbLQKBgQDU
+JymiAXgGqgnnyFgn/vNC8ZNtUFEqq2sy2tky53lW+B8j8pfT1c6R59AxKiCgfWua
+AjpBUcT2dKjr1zo2xnCz5WdQIxHTvype6DxIhItTl2TFrKHYZL/UQKtDlGXtW+HD
+uvhZk/fQxMaG9J4HSbY1IiEaoF10zdQAjWclia3HiwKBgQDX1piVYGI4c5HtC50h
+NXdbPH+jxgdr3Hj43cki4OaXTg5drX8ZVFc0/fUhASAEG6WbFg9nDU0mH8o+5zoJ
+JehiL/RQOK2s70fitgBYF6RBc+znBp5OEqdQiWn1UlTZ/CdSPfR4vkMADzFEYGxZ
+YVsrUwMSVO65vmGmyfvmIL682g==
+-----END PRIVATE KEY-----
diff --git a/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-rsa-3072.pem b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-rsa-3072.pem
new file mode 100644
index 0000000..9d6a219
--- /dev/null
+++ b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-rsa-3072.pem
@@ -0,0 +1,40 @@
+-----BEGIN PRIVATE KEY-----
+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
+uvn49/VWU7/8Ppw/Wg7C+L0B
+-----END PRIVATE KEY-----
diff --git a/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-rsa-4096.pem b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-rsa-4096.pem
new file mode 100644
index 0000000..f625c8e
--- /dev/null
+++ b/sshd-common/src/test/resources/org/apache/sshd/common/config/keys/loader/pem/pkcs8-rsa-4096.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+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
+18uzMDlMbqOoq+IErsvMbHs/fl8GtJ5S
+-----END PRIVATE KEY-----