This is an automated email from the ASF dual-hosted git repository.
twolf pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
The following commit(s) were added to refs/heads/master by this push:
new d4b951a10 GH-364: Use flags for RSA signature requests in
AbstractAgentClient
d4b951a10 is described below
commit d4b951a100889ac5db351a4bb109a9a301a322ad
Author: Thomas Wolf <[email protected]>
AuthorDate: Mon May 1 21:48:33 2023 +0200
GH-364: Use flags for RSA signature requests in AbstractAgentClient
Respect the flags in OpenSSH signing requests. These flags tell what
kind of signature should be produced for an RSA key: ssh-rsa,
rsa-sha2-256, or rsa-sha2-512.
Previous code only set the flags on the client side, but ignored
them in the server side and thus always answered with an ssh-rsa
signature.
Bug: https://github.com/apache/mina-sshd/issues/364
---
CHANGES.md | 3 +-
.../sshd/agent/common/AbstractAgentClient.java | 19 ++-
.../java/org/apache/sshd/agent/AgentUnitTest.java | 134 +++++++++++++++++++++
3 files changed, 154 insertions(+), 2 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index 0d241ef4b..9ac705e6e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -37,7 +37,8 @@
* [GH-300](https://github.com/apache/mina-sshd/issues/300) Read the channel id
in `SSH_MSG_CHANNEL_OPEN_CONFIRMATION` as unsigned int.
* [GH-313](https://github.com/apache/mina-sshd/issues/313) Log exceptions in
the SFTP subsystem before sending a failure status reply.
* [GH-322](https://github.com/apache/mina-sshd/issues/322) Add basic Android
O/S awareness.
-* [GH-325](https://github.com/apache/mina-sshd/issues/325)
SftpFileSystemProvider: fix deletions of symlinks through `Files.delete()`.
+* [GH-325](https://github.com/apache/mina-sshd/issues/325)
`SftpFileSystemProvider`: fix deletions of symlinks through `Files.delete()`.
+* [GH-364](https://github.com/apache/mina-sshd/issues/364)
`AbstractAgentClient`: respect flags for RSA signature requests.
* [SSHD-1295](https://issues.apache.org/jira/browse/SSHD-1295) Fix
cancellation of futures and add options to cancel futures on time-outs.
diff --git
a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
index 970c86ed6..cf2cc8a02 100644
---
a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
+++
b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
@@ -29,6 +29,7 @@ import java.util.Map;
import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.agent.SshAgentConstants;
import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.BufferUtils;
@@ -130,7 +131,23 @@ public abstract class AbstractAgentClient extends
AbstractLoggingBean {
KeyUtils.getKeyType(signingKey),
"Cannot resolve key type of %s",
signingKey.getClass().getSimpleName());
- Map.Entry<String, byte[]> result = agent.sign(null,
signingKey, keyType, data);
+ String signatureAlgorithm = keyType;
+ if (KeyPairProvider.SSH_RSA.equals(keyType)) {
+ switch (flags) {
+ case 4:
+ signatureAlgorithm =
KeyUtils.RSA_SHA512_KEY_TYPE_ALIAS;
+ break;
+ case 2:
+ signatureAlgorithm =
KeyUtils.RSA_SHA256_KEY_TYPE_ALIAS;
+ break;
+ case 0:
+ break;
+ default:
+ throw new
IllegalArgumentException("SSH2_AGENTC_SIGN_REQUEST: Unknown flag value 0x"
+ +
Integer.toHexString(flags) + ", only 0, 2, or 4 are allowed.");
+ }
+ }
+ Map.Entry<String, byte[]> result = agent.sign(null,
signingKey, signatureAlgorithm, data);
String algo = result.getKey();
byte[] signature = result.getValue();
Buffer sig = new ByteArrayBuffer(algo.length() +
signature.length + Long.SIZE, false);
diff --git a/sshd-core/src/test/java/org/apache/sshd/agent/AgentUnitTest.java
b/sshd-core/src/test/java/org/apache/sshd/agent/AgentUnitTest.java
new file mode 100644
index 000000000..29223f49c
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/agent/AgentUnitTest.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.sshd.agent;
+
+import java.io.IOException;
+import java.security.KeyPair;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sshd.agent.common.AbstractAgentClient;
+import org.apache.sshd.agent.common.AbstractAgentProxy;
+import org.apache.sshd.agent.local.AgentImpl;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.signature.BuiltinSignatures;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.security.SecurityUtils;
+import org.apache.sshd.util.test.BaseTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/**
+ * Simple short-circuited test for {@link AbstractAgentClient} and {@link
AbstractAgentProxy}.
+ */
+@Category(NoIoTestCase.class)
+@RunWith(Parameterized.class)
+public class AgentUnitTest extends BaseTestSupport {
+
+ private String algorithm;
+
+ private BuiltinSignatures factory;
+
+ public AgentUnitTest(String algorithm, BuiltinSignatures factory) {
+ this.algorithm = algorithm;
+ this.factory = factory;
+ }
+
+ @Parameterized.Parameters(name = "{0}")
+ public static List<Object[]> getParameters() {
+ return Arrays.asList(new Object[] {
KeyUtils.RSA_SHA512_KEY_TYPE_ALIAS, BuiltinSignatures.rsaSHA512 },
+ new Object[] { KeyUtils.RSA_SHA256_KEY_TYPE_ALIAS,
BuiltinSignatures.rsaSHA256 },
+ new Object[] { KeyPairProvider.SSH_RSA, BuiltinSignatures.rsa
});
+ }
+
+ @Test
+ public void testRsaSignature() throws Exception {
+ SshAgent agent = new AgentImpl();
+ KeyPair pair =
SecurityUtils.getKeyPairGenerator(KeyUtils.RSA_ALGORITHM).generateKeyPair();
+ agent.addIdentity(pair, "test key");
+ Server server = new Server(agent);
+ Client client = new Client(server);
+ server.setClient(client);
+ byte[] data = { 'd', 'a', 't', 'a' };
+ Map.Entry<String, byte[]> result = client.sign(null, pair.getPublic(),
algorithm, data);
+ assertEquals("Unexpected signature algorithm", algorithm,
result.getKey());
+ byte[] signature = result.getValue();
+ Signature verifier = factory.get();
+ verifier.initVerifier(null, pair.getPublic());
+ verifier.update(null, data);
+ assertTrue("Signature should validate", verifier.verify(null,
signature));
+ }
+
+ private static class Server extends AbstractAgentClient {
+
+ private Client client;
+
+ protected Server(SshAgent agent) {
+ super(agent);
+ }
+
+ @Override
+ protected void reply(Buffer buf) throws IOException {
+ client.setResult(buf.getCompactData());
+ }
+
+ void setClient(Client client) {
+ this.client = client;
+ }
+
+ void request(byte[] data) throws IOException {
+ messageReceived(ByteArrayBuffer.getCompactClone(data));
+ }
+ }
+
+ private static class Client extends AbstractAgentProxy {
+
+ private final Server server;
+
+ private byte[] result;
+
+ protected Client(Server server) {
+ super(null);
+ this.server = server;
+ }
+
+ @Override
+ protected Buffer request(Buffer buffer) throws IOException {
+ server.request(buffer.getCompactData());
+ Buffer received = ByteArrayBuffer.getCompactClone(result);
+ return new ByteArrayBuffer(received.getBytes());
+ }
+
+ @Override
+ public boolean isOpen() {
+ return true;
+ }
+
+ void setResult(byte[] data) {
+ result = data;
+ }
+ }
+}