diff --git a/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/KexExtensions.java b/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/KexExtensions.java index f275227e1..c5f8dae3e 100644 --- a/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/KexExtensions.java +++ b/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/KexExtensions.java @@ -39,6 +39,7 @@ import org.apache.sshd.common.NamedResource; import org.apache.sshd.common.kex.extension.parser.DelayCompression; import org.apache.sshd.common.kex.extension.parser.Elevation; +import org.apache.sshd.common.kex.extension.parser.ExtInfoInAuth; import org.apache.sshd.common.kex.extension.parser.NoFlowControl; import org.apache.sshd.common.kex.extension.parser.ServerSignatureAlgorithms; import org.apache.sshd.common.util.GenericUtils; @@ -84,7 +85,8 @@ public final class KexExtensions { ServerSignatureAlgorithms.INSTANCE, NoFlowControl.INSTANCE, Elevation.INSTANCE, - DelayCompression.INSTANCE) + DelayCompression.INSTANCE, + ExtInfoInAuth.INSTANCE) .collect(Collectors.toMap( NamedResource::getName, Function.identity(), MapEntryUtils.throwingMerger(), () -> new TreeMap<>(String.CASE_INSENSITIVE_ORDER))); diff --git a/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/parser/ExtInfoInAuth.java b/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/parser/ExtInfoInAuth.java new file mode 100644 index 000000000..19dde8c36 --- /dev/null +++ b/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/parser/ExtInfoInAuth.java @@ -0,0 +1,55 @@ +/* + * 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.common.kex.extension.parser; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import org.apache.sshd.common.util.buffer.Buffer; + +/** + * @author Apache MINA SSHD Project + * @see ext-info-in-auth@openssh.com + */ +public class ExtInfoInAuth extends AbstractKexExtensionParser { + + public static final String NAME = "ext-info-in-auth@openssh.com"; + + public static final ExtInfoInAuth INSTANCE = new ExtInfoInAuth(); + + public ExtInfoInAuth() { + super(NAME); + } + + @Override + protected void encode(String value, Buffer buffer) throws IOException { + buffer.putString(value); + } + + @Override + public String parseExtension(byte[] data, int off, int len) throws IOException { + return (len <= 0) ? "" : new String(data, off, len, StandardCharsets.UTF_8); + } + + @Override + public String parseExtension(Buffer buffer) throws IOException { + return parseExtension(buffer.array(), buffer.rpos(), buffer.available()); + } +} diff --git a/sshd-core/src/main/java/org/apache/sshd/common/kex/extension/DefaultClientKexExtensionHandler.java b/sshd-core/src/main/java/org/apache/sshd/common/kex/extension/DefaultClientKexExtensionHandler.java index f70128e40..04753b05c 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/kex/extension/DefaultClientKexExtensionHandler.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/kex/extension/DefaultClientKexExtensionHandler.java @@ -23,16 +23,21 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.function.BiConsumer; import org.apache.sshd.common.AttributeRepository.AttributeKey; import org.apache.sshd.common.NamedFactory; +import org.apache.sshd.common.kex.extension.parser.ExtInfoInAuth; import org.apache.sshd.common.kex.extension.parser.HostBoundPubkeyAuthentication; import org.apache.sshd.common.kex.extension.parser.ServerSignatureAlgorithms; import org.apache.sshd.common.session.Session; import org.apache.sshd.common.signature.Signature; +import org.apache.sshd.common.util.buffer.Buffer; import org.apache.sshd.common.util.logging.AbstractLoggingBean; /** @@ -133,4 +138,35 @@ protected void handleServerSignatureAlgorithms(Session session, Collection extensions = new LinkedHashMap<>(); + collectExtensions(session, phase, extensions::put); + if (!extensions.isEmpty()) { + Buffer buffer = session.createBuffer(KexExtensions.SSH_MSG_EXT_INFO); + KexExtensions.putExtensions(extensions.entrySet(), buffer); + if (log.isDebugEnabled()) { + log.debug("sendKexExtensions({})[{}]: sending SSH_MSG_EXT_INFO with {} info records", session, phase, + extensions.size()); + } + session.writePacket(buffer); + } + } + + /** + * Collects extension info records, handing them off to the given {@code marshaller} for writing into an + * {@link KexExtensions#SSH_MSG_EXT_INFO} message. + *

+ * This default implementation does not marshal any extension. + *

+ * + * @param session {@link Session} to send the KEX extension information for + * @param phase {@link KexPhase} of the SSH protocol + * @param marshaller {@link BiConsumer} writing the extensions into an SSH message + */ + public void collectExtensions(Session session, KexPhase phase, BiConsumer marshaller) { + // ext-info-in-auth@openssh.com + marshaller.accept(ExtInfoInAuth.NAME, ""); + } }