This is an automated email from the ASF dual-hosted git repository. twolf pushed a commit to branch dev_3.0 in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
commit dd654d89dcf4817a7c64beb804c02f861ad63e14 Merge: bb9ac2069 362758d2d Author: Thomas Wolf <[email protected]> AuthorDate: Wed Sep 10 22:52:53 2025 +0200 Merge branch 'master' into 3.0.0 .../security/eddsa/generic/SignatureEd25519.java | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --cc sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/SignatureEd25519.java index 3e7e1eb1d,2eccf3a19..afbf4a076 --- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/SignatureEd25519.java +++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/generic/SignatureEd25519.java @@@ -16,37 -16,57 +16,78 @@@ * specific language governing permissions and limitations * under the License. */ -package org.apache.sshd.common.util.security.eddsa; +package org.apache.sshd.common.util.security.eddsa.generic; + import java.security.SignatureException; +import java.util.Map; ++import java.util.Objects; -import net.i2p.crypto.eddsa.EdDSAEngine; -import org.apache.sshd.common.util.security.eddsa.generic.GenericSignatureEd25519; +import org.apache.sshd.common.keyprovider.KeyPairProvider; +import org.apache.sshd.common.session.SessionContext; +import org.apache.sshd.common.signature.AbstractSignature; +import org.apache.sshd.common.util.ValidateUtils; +import org.apache.sshd.common.util.security.SecurityUtils; /** - * An implementation of {@link GenericSignatureEd25519} tied to the {@code net.i2p.crypto} EdDSA security provider. + * An ed25519 signature. * * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> */ -public class SignatureEd25519 extends GenericSignatureEd25519 { +public class SignatureEd25519 extends AbstractSignature { + // See https://www.rfc-editor.org/rfc/rfc7748.html#section-4.1 + // 2^252 + 0x14def9dea2f79cd65812631a5cf5d3ed; little-endian + private static final int[] ED25519_ORDER = { // + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, // + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, // + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 // + }; + public SignatureEd25519() { - super(EdDSAEngine.SIGNATURE_ALGORITHM); + super(SecurityUtils.ED25519, KeyPairProvider.SSH_ED25519); + } + + @Override + public boolean verify(SessionContext session, byte[] sig) throws Exception { + byte[] data = sig; + Map.Entry<String, byte[]> encoding = extractEncodedSignature(data, KeyPairProvider.SSH_ED25519::equalsIgnoreCase); + if (encoding != null) { + String keyType = encoding.getKey(); + ValidateUtils.checkTrue(KeyPairProvider.SSH_ED25519.equals(keyType), "Mismatched key type: %s", keyType); + data = encoding.getValue(); + } + + return doVerify(data); } + + @Override + protected boolean doVerify(byte[] data) throws SignatureException { - // Fix CVE 2020-36843 in net.i2p.crypto.eddsa 0.3.0: check that s is in the range [0 .. L), where - // L is the order. - // - // Note: Wikipedia says 0 < S < L. https://en.wikipedia.org/w/index.php?title=EdDSA&oldid=1304068429 - // RFC 8032 says 0 <= S < L. https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.7 - // - // We stick to RFC 8032 here. - if (data.length != 64 || !isValidFactor(data)) { - return false; ++ java.security.Signature verifier = Objects.requireNonNull(getSignature(), "Signature not initialized"); ++ if (SecurityUtils.EDDSA.equals(verifier.getProvider().getName())) { ++ // Fix CVE 2020-36843 in net.i2p.crypto.eddsa 0.3.0: check that s is in the range [0 .. L), where ++ // L is the order. ++ // ++ // Note: Wikipedia says 0 < S < L. https://en.wikipedia.org/w/index.php?title=EdDSA&oldid=1304068429 ++ // RFC 8032 says 0 <= S < L. https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.7 ++ // ++ // We stick to RFC 8032 here. ++ if (data.length != 64 || !isValidFactor(data)) { ++ return false; ++ } + } - return super.doVerify(data); ++ return verifier.verify(data); + } + + private static boolean isValidFactor(byte[] sig) { + // Must be strictly smaller than the field order (little-endian). + for (int i = 31; i >= 0; i--) { + int y = (sig[i + 32] & 0xFF) - ED25519_ORDER[i]; + if (y != 0) { + return y < 0; + } + } + return false; + } + }
