Skip to content

Commit 07a377c

Browse files
committed
Merge branch 'master' into 3.0.0
2 parents 5d5a65a + 3ccf910 commit 07a377c

22 files changed

Lines changed: 418 additions & 53 deletions

File tree

pom.xml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,12 @@
114114
<mockito.version>4.11.0</mockito.version>
115115
<bytebuddy.version>1.17.5</bytebuddy.version>
116116
<testcontainers.version>1.21.0</testcontainers.version>
117-
<grpc.version>1.72.0</grpc.version> <!-- Used only in tests -->
117+
<grpc.version>1.73.0</grpc.version> <!-- Used only in tests -->
118118

119119
<maven.archiver.version>3.6.3</maven.archiver.version>
120120
<plexus.archiver.version>4.10.0</plexus.archiver.version>
121121
<!-- See https://pmd.github.io/ for available latest version -->
122-
<pmd.version>7.13.0</pmd.version>
122+
<pmd.version>7.14.0</pmd.version>
123123
<japicmp.version>0.23.1</japicmp.version>
124124
<sshd.tests.timeout.factor>1.0</sshd.tests.timeout.factor>
125125
<sshd.tests.rerun.count>2</sshd.tests.rerun.count>
@@ -559,7 +559,7 @@
559559
<dependency>
560560
<groupId>com.github.mwiede</groupId>
561561
<artifactId>jsch</artifactId>
562-
<version>0.2.26</version>
562+
<version>2.27.2</version>
563563
</dependency>
564564

565565
<!-- Transitive dependencies by various 3rd party packages -->
@@ -703,7 +703,7 @@
703703
<dependency>
704704
<groupId>org.junit.jupiter</groupId>
705705
<artifactId>junit-jupiter</artifactId>
706-
<version>5.12.2</version>
706+
<version>5.13.3</version>
707707
</dependency>
708708
<dependency>
709709
<groupId>org.mockito</groupId>
@@ -984,7 +984,7 @@
984984
<plugin>
985985
<groupId>org.apache.maven.plugins</groupId>
986986
<artifactId>maven-pmd-plugin</artifactId>
987-
<version>3.26.0</version>
987+
<version>3.27.0</version>
988988
<configuration>
989989
<targetJdk>${javac.target}</targetJdk>
990990
<printFailingErrors>true</printFailingErrors>

sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/SkED25519PublicKeyEntryDecoder.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,23 @@
2323
import java.io.InputStream;
2424
import java.io.OutputStream;
2525
import java.security.GeneralSecurityException;
26+
import java.security.InvalidKeyException;
2627
import java.security.KeyFactory;
2728
import java.security.KeyPair;
2829
import java.security.KeyPairGenerator;
2930
import java.security.PrivateKey;
31+
import java.security.PublicKey;
3032
import java.security.spec.InvalidKeySpecException;
3133
import java.util.Collections;
3234
import java.util.Map;
3335
import java.util.Objects;
3436

35-
import net.i2p.crypto.eddsa.EdDSAPublicKey;
3637
import org.apache.sshd.common.config.keys.KeyEntryResolver;
3738
import org.apache.sshd.common.config.keys.u2f.SkED25519PublicKey;
3839
import org.apache.sshd.common.keyprovider.KeyPairProvider;
3940
import org.apache.sshd.common.session.SessionContext;
40-
import org.apache.sshd.common.util.security.eddsa.Ed25519PublicKeyDecoder;
41+
import org.apache.sshd.common.util.security.SecurityUtils;
42+
import org.apache.sshd.common.util.security.eddsa.generic.EdDSAUtils;
4143

4244
/**
4345
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -63,18 +65,22 @@ public SkED25519PublicKey decodePublicKey(
6365
}
6466

6567
boolean noTouchRequired = parseBooleanHeader(headers, NO_TOUCH_REQUIRED_HEADER, false);
66-
EdDSAPublicKey edDSAPublicKey
67-
= Ed25519PublicKeyDecoder.INSTANCE.decodePublicKey(session, KeyPairProvider.SSH_ED25519, keyData, headers);
68+
PublicKey pk = SecurityUtils.getEDDSAPublicKeyEntryDecoder().decodePublicKey(session, KeyPairProvider.SSH_ED25519,
69+
keyData, headers);
6870
String appName = KeyEntryResolver.decodeString(keyData, MAX_APP_NAME_LENGTH);
69-
return new SkED25519PublicKey(appName, noTouchRequired, edDSAPublicKey);
71+
return new SkED25519PublicKey(appName, noTouchRequired, pk);
7072
}
7173

7274
@Override
7375
public String encodePublicKey(OutputStream s, SkED25519PublicKey key) throws IOException {
7476
Objects.requireNonNull(key, "No public key provided");
7577
KeyEntryResolver.encodeString(s, KEY_TYPE);
76-
byte[] seed = Ed25519PublicKeyDecoder.getSeedValue(key.getDelegatePublicKey());
77-
KeyEntryResolver.writeRLEBytes(s, seed);
78+
try {
79+
byte[] keyData = EdDSAUtils.getBytes(key.getDelegatePublicKey());
80+
KeyEntryResolver.writeRLEBytes(s, keyData);
81+
} catch (InvalidKeyException e) {
82+
throw new IOException(e.getMessage(), e);
83+
}
7884
KeyEntryResolver.encodeString(s, key.getAppName());
7985
return KEY_TYPE;
8086
}

sshd-common/src/main/java/org/apache/sshd/common/config/keys/u2f/SkED25519PublicKey.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,29 @@
1818
*/
1919
package org.apache.sshd.common.config.keys.u2f;
2020

21+
import java.security.PublicKey;
2122
import java.util.Objects;
2223

23-
import net.i2p.crypto.eddsa.EdDSAPublicKey;
24+
import org.apache.sshd.common.config.keys.KeyUtils;
2425
import org.apache.sshd.common.config.keys.impl.SkED25519PublicKeyEntryDecoder;
26+
import org.apache.sshd.common.keyprovider.KeyPairProvider;
27+
import org.apache.sshd.common.util.ValidateUtils;
2528

26-
public class SkED25519PublicKey implements SecurityKeyPublicKey<EdDSAPublicKey> {
29+
public class SkED25519PublicKey implements SecurityKeyPublicKey<PublicKey> {
2730

2831
public static final String ALGORITHM = "ED25519-SK";
2932

30-
private static final long serialVersionUID = 4587115316266869640L;
33+
private static final long serialVersionUID = -3947776805731312115L;
3134

3235
private final String appName;
3336
private final boolean noTouchRequired;
34-
private final EdDSAPublicKey delegatePublicKey;
37+
private final PublicKey delegatePublicKey;
3538

36-
public SkED25519PublicKey(String appName, boolean noTouchRequired, EdDSAPublicKey delegatePublicKey) {
39+
public SkED25519PublicKey(String appName, boolean noTouchRequired, PublicKey delegatePublicKey) {
3740
this.appName = appName;
3841
this.noTouchRequired = noTouchRequired;
42+
ValidateUtils.checkTrue(KeyPairProvider.SSH_ED25519.equals(KeyUtils.getKeyType(delegatePublicKey)),
43+
"Key is not an ed25519 key");
3944
this.delegatePublicKey = delegatePublicKey;
4045
}
4146

@@ -70,7 +75,7 @@ public boolean isNoTouchRequired() {
7075
}
7176

7277
@Override
73-
public EdDSAPublicKey getDelegatePublicKey() {
78+
public PublicKey getDelegatePublicKey() {
7479
return delegatePublicKey;
7580
}
7681

sshd-common/src/main/java/org/apache/sshd/common/util/buffer/keys/SkED25519BufferPublicKeyParser.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import java.security.GeneralSecurityException;
2323
import java.security.PublicKey;
2424

25-
import net.i2p.crypto.eddsa.EdDSAPublicKey;
2625
import org.apache.sshd.common.config.keys.impl.SkED25519PublicKeyEntryDecoder;
2726
import org.apache.sshd.common.config.keys.u2f.SkED25519PublicKey;
2827
import org.apache.sshd.common.keyprovider.KeyPairProvider;
@@ -44,6 +43,6 @@ public SkED25519PublicKey getRawPublicKey(String keyType, Buffer buffer) throws
4443
// the end
4544
PublicKey publicKey = ED25519BufferPublicKeyParser.INSTANCE.getRawPublicKey(KeyPairProvider.SSH_ED25519, buffer);
4645
String appName = buffer.getString();
47-
return new SkED25519PublicKey(appName, false, (EdDSAPublicKey) publicKey);
46+
return new SkED25519PublicKey(appName, false, publicKey);
4847
}
4948
}

sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderUtils.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,6 @@ private EdDSASecurityProviderUtils() {
5555
throw new UnsupportedOperationException("No instance");
5656
}
5757

58-
public static Class<? extends PublicKey> getEDDSAPublicKeyType() {
59-
return EdDSAPublicKey.class;
60-
}
61-
62-
public static Class<? extends PrivateKey> getEDDSAPrivateKeyType() {
63-
return EdDSAPrivateKey.class;
64-
}
65-
6658
public static boolean isEDDSAKey(Key key) {
6759
return getEDDSAKeySize(key) == KEY_SIZE;
6860
}

sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/NetI2pCryptoEdDSASupport.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,13 @@ public int getEDDSAKeySize(Key key) {
6464
}
6565

6666
@Override
67-
public Class<? extends PublicKey> getEDDSAPublicKeyType() {
68-
return EdDSASecurityProviderUtils.getEDDSAPublicKeyType();
67+
public Class<EdDSAPublicKey> getEDDSAPublicKeyType() {
68+
return EdDSAPublicKey.class;
6969
}
7070

7171
@Override
72-
public Class<? extends PrivateKey> getEDDSAPrivateKeyType() {
73-
return EdDSASecurityProviderUtils.getEDDSAPrivateKeyType();
72+
public Class<EdDSAPrivateKey> getEDDSAPrivateKeyType() {
73+
return EdDSAPrivateKey.class;
7474
}
7575

7676
@Override

sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/bouncycastle/BouncyCastleEdDSASupport.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,12 @@ public int getEDDSAKeySize(Key key) {
7575
}
7676

7777
@Override
78-
public Class<? extends PublicKey> getEDDSAPublicKeyType() {
78+
public Class<EdDSAPublicKey> getEDDSAPublicKeyType() {
7979
return EdDSAPublicKey.class;
8080
}
8181

8282
@Override
83-
public Class<? extends PrivateKey> getEDDSAPrivateKeyType() {
83+
public Class<EdDSAPrivateKey> getEDDSAPrivateKeyType() {
8484
return EdDSAPrivateKey.class;
8585
}
8686

sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/EdDSASupport.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,12 @@ static PrivateKey decodeEdDSAPrivateKey(byte[] keyData) throws IOException, Gene
108108
/**
109109
* @return the public key class type associated with the security provider.
110110
*/
111-
Class<? extends PublicKey> getEDDSAPublicKeyType();
111+
Class<PUB> getEDDSAPublicKeyType();
112112

113113
/**
114114
* @return the private key class type associated with the security provider.
115115
*/
116-
Class<? extends PrivateKey> getEDDSAPrivateKeyType();
116+
Class<PRV> getEDDSAPrivateKeyType();
117117

118118
/**
119119
* @param k1 the first key
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.sshd.common.util.security.eddsa.generic;
20+
21+
import java.security.InvalidKeyException;
22+
import java.security.PublicKey;
23+
import java.util.Arrays;
24+
25+
/**
26+
* Utilities to extract the raw key bytes from ed25519 or ed448 public keys, in a manner that is independent of the
27+
* actual concrete key implementation classes.
28+
*
29+
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
30+
*/
31+
public final class EdDSAUtils {
32+
33+
private static final int ED25519_LENGTH = 32; // bytes
34+
35+
private static final int ED448_LENGTH = 57; // bytes
36+
37+
// These are the constant prefixes of X.509 encodings of ed25519 and ed448 keys. Appending the actual 32
38+
// or 57 key bytes yields valid encodings.
39+
40+
// Sequence, length 42, Sequence, length 5, OID, length 3, O, I, D, Bit String, length 33, zero unused bits
41+
private static final byte[] ED25519_X509_PREFIX = {
42+
0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00 };
43+
// Sequence, length 67, Sequence, length 5, OID, length 3, O, I, D, Bit String, length 58, zero unused bits
44+
private static final byte[] ED448_X509_PREFIX = {
45+
0x30, 0x43, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x71, 0x03, 0x3a, 0x00 };
46+
47+
private EdDSAUtils() {
48+
throw new IllegalStateException("No instantiation");
49+
}
50+
51+
private static boolean startsWith(byte[] data, byte[] prefix) {
52+
if (data == null || prefix == null || prefix.length == 0 || data.length < prefix.length) {
53+
return false;
54+
}
55+
int unequal = 0;
56+
int length = prefix.length;
57+
for (int i = 0; i < length; i++) {
58+
unequal |= data[i] ^ prefix[i];
59+
}
60+
return unequal == 0;
61+
}
62+
63+
/**
64+
* Retrieves the raw key bytes from an ed25519 or ed448 {@link PublicKey}.
65+
*
66+
* @param key {@link PublicKey} to get the bytes of
67+
* @return the raw key bytes
68+
* @throws InvalidKeyException if the key is not an ed25519 or ed448 key, or if it doesn't use X.509 encoding
69+
*/
70+
public static byte[] getBytes(PublicKey key) throws InvalidKeyException {
71+
// Extract the public key bytes from the X.509 encoding (last n bytes, depending on the OID).
72+
if (!"X.509".equalsIgnoreCase(key.getFormat())) {
73+
throw new InvalidKeyException("Cannot extract public key bytes from a non-X.509 encoding");
74+
}
75+
byte[] encoded = key.getEncoded();
76+
if (encoded == null) {
77+
throw new InvalidKeyException("Public key " + key.getClass().getCanonicalName() + " does not support encoding");
78+
}
79+
int n;
80+
if (encoded.length == ED25519_LENGTH + ED25519_X509_PREFIX.length && startsWith(encoded, ED25519_X509_PREFIX)) {
81+
n = ED25519_LENGTH;
82+
} else if (encoded.length == ED448_LENGTH + ED448_X509_PREFIX.length && startsWith(encoded, ED448_X509_PREFIX)) {
83+
n = ED448_LENGTH;
84+
} else {
85+
throw new InvalidKeyException("Public key is neither ed25519 nor ed448");
86+
}
87+
return Arrays.copyOfRange(encoded, encoded.length - n, encoded.length);
88+
}
89+
}

sshd-core/src/test/java/org/apache/sshd/common/signature/KnownHostsCertificateTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class KnownHostsCertificateTest extends BaseTestSupport {
6464
private KeyPair caKey;
6565

6666
@BeforeAll
67-
private static void setupClientAndServer() throws Exception {
67+
static void setupClientAndServer() throws Exception {
6868
sshd = CoreTestSupportUtils.setupTestFullSupportServer(KnownHostsCertificateTest.class);
6969
sshd.start();
7070
port = sshd.getPort();

0 commit comments

Comments
 (0)