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 2015/07/09 08:53:51 UTC

mina-sshd git commit: [SSHD-523] Add support for 'copy-data' SFTP extension

Repository: mina-sshd
Updated Branches:
  refs/heads/master 5cd057a72 -> 515427faa


[SSHD-523] Add support for 'copy-data' SFTP extension


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/515427fa
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/515427fa
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/515427fa

Branch: refs/heads/master
Commit: 515427faa988ebe6d6c221b0e7ce3b1369544da5
Parents: 5cd057a
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Thu Jul 9 09:53:40 2015 +0300
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Thu Jul 9 09:53:40 2015 +0300

----------------------------------------------------------------------
 .../agent/local/ChannelAgentForwarding.java     |   5 -
 .../sshd/client/auth/UserAuthPassword.java      |   2 +-
 .../sshd/client/auth/UserAuthPublicKey.java     |   6 +-
 .../channel/PtyCapableChannelSession.java       |   8 +-
 .../subsystem/sftp/AbstractSftpClient.java      |   1 -
 .../sshd/client/subsystem/sftp/SftpCommand.java |  29 +++
 .../extensions/BuiltinSftpClientExtensions.java |   7 +
 .../sftp/extensions/CopyDataExtension.java      |  33 +++
 .../extensions/impl/CopyDataExtensionImpl.java  |  59 ++++++
 .../org/apache/sshd/common/channel/PtyMode.java |  21 +-
 .../common/subsystem/sftp/SftpConstants.java    |   1 +
 .../common/util/buffer/ByteArrayBuffer.java     |   1 -
 .../sshd/server/auth/UserAuthPublicKey.java     |   2 +-
 .../server/session/ServerUserAuthService.java   |   2 +-
 .../server/subsystem/sftp/SftpSubsystem.java    | 151 ++++++++++++--
 .../sshd/client/subsystem/sftp/SftpTest.java    |  20 --
 .../extensions/CopyDataExtensionImplTest.java   | 203 +++++++++++++++++++
 .../apache/sshd/deprecated/UserAuthAgent.java   |   7 +-
 .../sshd/deprecated/UserAuthPassword.java       |   2 +-
 .../sshd/deprecated/UserAuthPublicKey.java      |   6 +-
 20 files changed, 497 insertions(+), 69 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java b/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java
index c5c39ec..82c67f3 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java
@@ -37,11 +37,6 @@ import org.apache.sshd.server.channel.AbstractServerChannel;
  * The client side channel that will receive requests forwards by the SSH server.
  */
 public class ChannelAgentForwarding extends AbstractServerChannel {
-
-    private String authSocket;
-    private long pool;
-    private long handle;
-    private Thread thread;
     private OutputStream out;
     private SshAgent agent;
     private AgentClient client;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
index 7ca3170..3a43362 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
@@ -68,7 +68,7 @@ public class UserAuthPassword extends AbstractLoggingBean implements UserAuth {
                 buffer.putString(session.getUsername());
                 buffer.putString(service);
                 buffer.putString("password");
-                buffer.putByte((byte) 0);
+                buffer.putBoolean(false);
                 buffer.putString(current);
                 session.writePacket(buffer);
                 return true;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
index 4a8b881..712a84a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
@@ -103,7 +103,7 @@ public class UserAuthPublicKey extends AbstractLoggingBean implements UserAuth {
                 buffer.putString(session.getUsername());
                 buffer.putString(service);
                 buffer.putString(UserAuthPublicKeyFactory.NAME);
-                buffer.putByte((byte) 0);
+                buffer.putBoolean(false);
                 buffer.putString(algo);
                 buffer.putPublicKey(key);
                 session.writePacket(buffer);
@@ -123,7 +123,7 @@ public class UserAuthPublicKey extends AbstractLoggingBean implements UserAuth {
             buffer.putString(session.getUsername());
             buffer.putString(service);
             buffer.putString(UserAuthPublicKeyFactory.NAME);
-            buffer.putByte((byte) 1);
+            buffer.putBoolean(true);
             buffer.putString(algo);
             buffer.putPublicKey(key);
 
@@ -133,7 +133,7 @@ public class UserAuthPublicKey extends AbstractLoggingBean implements UserAuth {
             bs.putString(session.getUsername());
             bs.putString(service);
             bs.putString(UserAuthPublicKeyFactory.NAME);
-            bs.putByte((byte) 1);
+            bs.putBoolean(true);
             bs.putString(algo);
             bs.putPublicKey(key);
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java
index 8c9b3a4..d3eee76 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java
@@ -23,10 +23,6 @@ import java.util.Collections;
 import java.util.EnumMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.sshd.client.SshClient;
-import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.channel.PtyMode;
 import org.apache.sshd.common.channel.SttySupport;
@@ -225,14 +221,14 @@ public class PtyCapableChannelSession extends ChannelSession {
             buffer.putInt(ptyHeight);
             buffer.putInt(ptyWidth);
 
-            Buffer modes = new ByteArrayBuffer();
+            Buffer modes = new ByteArrayBuffer(GenericUtils.size(ptyModes) * (1 + (Integer.SIZE / Byte.SIZE)) + Byte.SIZE);
             for (Map.Entry<PtyMode,? extends Number> modeEntry : ptyModes.entrySet()) {
                 PtyMode mode = modeEntry.getKey();
                 Number value = modeEntry.getValue();
                 modes.putByte((byte) mode.toInt());
                 modes.putInt(value.longValue());
             }
-            modes.putByte((byte) 0);
+            modes.putByte(PtyMode.TTY_OP_END);    
             buffer.putBytes(modes.getCompactData());
             writePacket(buffer);
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
index 8d9705a..2dd3589 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
@@ -89,7 +89,6 @@ import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IFREG;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
 import java.nio.file.attribute.FileTime;
 import java.util.ArrayList;
 import java.util.Collection;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java
index c0d7edd..4a7f783 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java
@@ -32,8 +32,10 @@ import java.util.TreeMap;
 import org.apache.sshd.client.SshClient;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.subsystem.sftp.extensions.ParserUtils;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.buffer.BufferUtils;
 import org.apache.sshd.common.util.io.NoCloseInputStream;
 
 /**
@@ -78,6 +80,33 @@ public class SftpCommand implements Channel {
                                 new CommandExecutor() {
                                         @Override
                                         public String getName() {
+                                            return "info";
+                                        }
+    
+                                        @Override
+                                        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+                                            ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args);
+                                            SftpClient sftp = getClient();
+                                            Map<String,byte[]> extensions = sftp.getServerExtensions();
+                                            Map<String,?> parsed = ParserUtils.parse(null);
+                                            for (Map.Entry<String,byte[]> ee : extensions.entrySet()) {
+                                                String name = ee.getKey();
+                                                byte[] value = ee.getValue();
+                                                Object info  = parsed.get(name);
+
+                                                stdout.append('\t').append(name).append(": ");
+                                                if (info == null) {
+                                                    stdout.println(BufferUtils.printHex(value));
+                                                } else {
+                                                    stdout.println(info);
+                                                }
+                                            }
+                                            return false;
+                                        }
+                                    },
+                                new CommandExecutor() {
+                                        @Override
+                                        public String getName() {
                                             return "version";
                                         }
     

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/BuiltinSftpClientExtensions.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/BuiltinSftpClientExtensions.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/BuiltinSftpClientExtensions.java
index 7a23f13..467ef78 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/BuiltinSftpClientExtensions.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/BuiltinSftpClientExtensions.java
@@ -28,6 +28,7 @@ import org.apache.sshd.client.subsystem.sftp.RawSftpClient;
 import org.apache.sshd.client.subsystem.sftp.SftpClient;
 import org.apache.sshd.client.subsystem.sftp.extensions.impl.CheckFileHandleExtensionImpl;
 import org.apache.sshd.client.subsystem.sftp.extensions.impl.CheckFileNameExtensionImpl;
+import org.apache.sshd.client.subsystem.sftp.extensions.impl.CopyDataExtensionImpl;
 import org.apache.sshd.client.subsystem.sftp.extensions.impl.CopyFileExtensionImpl;
 import org.apache.sshd.client.subsystem.sftp.extensions.impl.MD5FileExtensionImpl;
 import org.apache.sshd.client.subsystem.sftp.extensions.impl.MD5HandleExtensionImpl;
@@ -45,6 +46,12 @@ public enum BuiltinSftpClientExtensions implements SftpClientExtensionFactory {
                 return new CopyFileExtensionImpl(client, raw, ParserUtils.supportedExtensions(parsed));
             }
         },
+    COPY_DATA(SftpConstants.EXT_COPYDATA, CopyDataExtension.class) {
+            @Override   // co-variant return
+            public CopyDataExtension create(SftpClient client, RawSftpClient raw, Map<String,byte[]> extensions, Map<String,?> parsed) {
+                return new CopyDataExtensionImpl(client, raw, ParserUtils.supportedExtensions(parsed));
+            }
+        },
     MD5_FILE(SftpConstants.EXT_MD5HASH, MD5FileExtension.class) {
             @Override   // co-variant return
             public MD5FileExtension create(SftpClient client, RawSftpClient raw, Map<String,byte[]> extensions, Map<String,?> parsed) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/CopyDataExtension.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/CopyDataExtension.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/CopyDataExtension.java
new file mode 100644
index 0000000..64025bc
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/CopyDataExtension.java
@@ -0,0 +1,33 @@
+/*
+ * 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.client.subsystem.sftp.extensions;
+
+import java.io.IOException;
+
+import org.apache.sshd.client.subsystem.sftp.SftpClient.Handle;
+
+/**
+ * Implements the &quot;copy-data&quot; extension
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="http://tools.ietf.org/id/draft-ietf-secsh-filexfer-extensions-00.txt">DRAFT 00 section 7</A>
+ */
+public interface CopyDataExtension extends SftpClientExtension {
+    void copyData(Handle readHandle, long readOffset, long readLength, Handle writeHandle, long writeOffset) throws IOException;
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyDataExtensionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyDataExtensionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyDataExtensionImpl.java
new file mode 100644
index 0000000..8d28bbb
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyDataExtensionImpl.java
@@ -0,0 +1,59 @@
+/*
+ * 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.client.subsystem.sftp.extensions.impl;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import org.apache.sshd.client.subsystem.sftp.RawSftpClient;
+import org.apache.sshd.client.subsystem.sftp.SftpClient;
+import org.apache.sshd.client.subsystem.sftp.SftpClient.Handle;
+import org.apache.sshd.client.subsystem.sftp.extensions.CopyDataExtension;
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class CopyDataExtensionImpl extends AbstractSftpClientExtension implements CopyDataExtension {
+    public CopyDataExtensionImpl(SftpClient client, RawSftpClient raw, Collection<String> extra) {
+        super(SftpConstants.EXT_COPYDATA, client, raw, extra);
+    }
+
+    @Override
+    public void copyData(Handle readHandle, long readOffset, long readLength, Handle writeHandle, long writeOffset) throws IOException {
+        byte[] srcId = readHandle.getIdentifier(), dstId = writeHandle.getIdentifier();
+        String opcode = getName();
+        Buffer buffer = new ByteArrayBuffer((Integer.SIZE / Byte.SIZE) + GenericUtils.length(opcode)
+                                          + (Integer.SIZE / Byte.SIZE) + GenericUtils.length(srcId)
+                                          + (Integer.SIZE / Byte.SIZE) + GenericUtils.length(dstId)
+                                          + (3 * (Long.SIZE + (Integer.SIZE / Byte.SIZE)))
+                                          + Byte.SIZE);
+        buffer.putString(opcode);
+        buffer.putBytes(srcId);
+        buffer.putLong(readOffset);
+        buffer.putLong(readLength);
+        buffer.putBytes(dstId);
+        buffer.putLong(writeOffset);
+        sendAndCheckExtendedCommandStatus(buffer);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/main/java/org/apache/sshd/common/channel/PtyMode.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/PtyMode.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/PtyMode.java
index 72e40b3..b320482 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/channel/PtyMode.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/PtyMode.java
@@ -18,6 +18,7 @@
  */
 package org.apache.sshd.common.channel;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -60,14 +61,18 @@ public enum PtyMode {
         return v;
     }
 
-    static Map<Integer, PtyMode> commands;
-
-    static {
-        commands = new HashMap<Integer, PtyMode>();
-        for (PtyMode c : PtyMode.values()) {
-            commands.put(Integer.valueOf(c.toInt()), c);
-        }
-    }
+    public static final byte TTY_OP_END = 0x00;
+    
+    private static final Map<Integer, PtyMode> commands = 
+            Collections.unmodifiableMap(new HashMap<Integer, PtyMode>() {
+                    private static final long serialVersionUID = 1L;    // we're not serializing it
+                    
+                    {
+                        for (PtyMode c : PtyMode.values()) {
+                            put(Integer.valueOf(c.toInt()), c);
+                        }
+                    }
+            });
 
     public static PtyMode fromInt(int b) {
         return commands.get(Integer.valueOf(0x00FF & (b + 256)));

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
index 92be24e..e719de5 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
@@ -236,6 +236,7 @@ public final class SftpConstants {
     public static final String EXT_CHKFILE_NAME = "check-file-name";
         public static final int MIN_CHKFILE_BLOCKSIZE = 256;
         public static final String EXT_CHKFILE_RESPONSE = "check-file";
+    public static final String EXT_COPYDATA = "copy-data";
 
     private SftpConstants() {
         throw new UnsupportedOperationException("No instance");

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java
index e41447c..19cc401 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java
@@ -19,7 +19,6 @@
 
 package org.apache.sshd.common.util.buffer;
 
-import java.nio.BufferUnderflowException;
 import java.nio.charset.Charset;
 
 import org.apache.sshd.common.util.Int2IntFunction;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java
index fcbc421..8c58463 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java
@@ -81,7 +81,7 @@ public class UserAuthPublicKey extends AbstractUserAuth {
             buf.putString(username);
             buf.putString(service);
             buf.putString(UserAuthPublicKeyFactory.NAME);
-            buf.putByte((byte) 1);
+            buf.putBoolean(true);
             buf.putString(alg);
             buffer.rpos(oldPos);
             buffer.wpos(oldPos + 4 + len);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
index 7f64dce..39c2d16 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
@@ -220,7 +220,7 @@ public class ServerUserAuthService extends CloseableUtils.AbstractCloseable impl
                     }
                 }
                 buffer.putString(sb.toString());
-                buffer.putByte((byte) 1);
+                buffer.putBoolean(true);
                 session.writePacket(buffer);
             }
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
index 41b9cf3..3f1bb4c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
@@ -180,7 +180,8 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
                                         SftpConstants.EXT_MD5HASH,
                                         SftpConstants.EXT_MD5HASH_HANDLE,
                                         SftpConstants.EXT_CHKFILE_HANDLE,
-                                        SftpConstants.EXT_CHKFILE_NAME
+                                        SftpConstants.EXT_CHKFILE_NAME,
+                                        SftpConstants.EXT_COPYDATA
                                 )));
 
     static {
@@ -691,6 +692,9 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
             case SftpConstants.EXT_COPYFILE:
                 doCopyFile(buffer, id);
                 break;
+            case SftpConstants.EXT_COPYDATA:
+                doCopyData(buffer, id);
+                break;
             case SftpConstants.EXT_MD5HASH:
             case SftpConstants.EXT_MD5HASH_HANDLE:
                 doMD5Hash(buffer, id, extension);
@@ -808,21 +812,29 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
     protected void doCheckFileHash(int id, Path file, NamedFactory<? extends Digest> factory,
                                    long startOffset, long length, int blockSize, Buffer buffer)
                            throws Exception {
+        ValidateUtils.checkTrue(startOffset >= 0L, "Invalid start offset: %d", startOffset);
+        ValidateUtils.checkTrue(length >= 0L, "Invalid length: %d", length);
         ValidateUtils.checkTrue((blockSize == 0) || (blockSize >= SftpConstants.MIN_CHKFILE_BLOCKSIZE), "Invalid block size: %d", blockSize);
         ValidateUtils.checkNotNull(factory, "No digest factory provided", GenericUtils.EMPTY_OBJECT_ARRAY);
         buffer.putString(factory.getName());
         
         long effectiveLength = length;
+        long totalLength = Files.size(file);
         if (effectiveLength == 0L) {
-            long totalLength = Files.size(file);
-            effectiveLength = totalLength - startOffset;    
+            effectiveLength = totalLength - startOffset;
+        } else {
+            long maxRead = startOffset + length;
+            if (maxRead > totalLength) {
+                effectiveLength = totalLength - startOffset;
+            }
         }
+        ValidateUtils.checkTrue(effectiveLength > 0L, "Non-positive effective hash data length: %d", effectiveLength);
 
-        byte[] workBuf = (blockSize == 0)
+        byte[] digestBuf = (blockSize == 0)
                        ? new byte[Math.min((int) effectiveLength, IoUtils.DEFAULT_COPY_SIZE)]
                        : new byte[Math.min((int) effectiveLength, blockSize)]
                        ;
-        ByteBuffer bb = ByteBuffer.wrap(workBuf);
+        ByteBuffer wb = ByteBuffer.wrap(digestBuf);
         try(FileChannel channel = FileChannel.open(file, IoUtils.EMPTY_OPEN_OPTIONS)) {
             channel.position(startOffset);
 
@@ -831,6 +843,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
 
             if (blockSize == 0) {
                 while(effectiveLength > 0L) {
+                    int remainLen = Math.min(digestBuf.length, (int) effectiveLength);
+                    ByteBuffer bb = wb;
+                    if (remainLen < digestBuf.length) {
+                        bb = ByteBuffer.wrap(digestBuf, 0, remainLen);
+                    }
                     bb.clear(); // prepare for next read
 
                     int readLen = channel.read(bb);
@@ -839,7 +856,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
                     }
 
                     effectiveLength -= readLen;
-                    digest.update(workBuf, 0, readLen);
+                    digest.update(digestBuf, 0, readLen);
                 }
                 
                 byte[] hashValue = digest.digest();
@@ -851,6 +868,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
                 buffer.putBytes(hashValue);
             } else {
                 for (int count=0; effectiveLength > 0L; count++) {
+                    int remainLen = Math.min(digestBuf.length, (int) effectiveLength);
+                    ByteBuffer bb = wb;
+                    if (remainLen < digestBuf.length) {
+                        bb = ByteBuffer.wrap(digestBuf, 0, remainLen);
+                    }
                     bb.clear(); // prepare for next read
 
                     int readLen = channel.read(bb);
@@ -859,7 +881,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
                     }
 
                     effectiveLength -= readLen;
-                    digest.update(workBuf, 0, readLen);
+                    digest.update(digestBuf, 0, readLen);
 
                     byte[] hashValue = digest.digest(); // NOTE: this also resets the hash for the next read
                     if (log.isTraceEnabled()) {
@@ -935,21 +957,29 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
          *
          *      If both start-offset and length are zero, the entire file should be included
          */
-        long effectiveLength = length;
+        long effectiveLength = length, totalSize = Files.size(path);
         if ((startOffset == 0L) && (length == 0L)) {
-            effectiveLength = Files.size(path);
+            effectiveLength = totalSize;
+        } else {
+            long maxRead = startOffset + effectiveLength;
+            if (maxRead > totalSize) {
+                effectiveLength = totalSize - startOffset;
+            }
         }
 
         return doMD5Hash(id, path, startOffset, effectiveLength, quickCheckHash);
     }
 
     protected byte[] doMD5Hash(int id, Path path, long startOffset, long length, byte[] quickCheckHash) throws Exception {
+        ValidateUtils.checkTrue(startOffset >= 0L, "Invalid start offset: %d", startOffset);
+        ValidateUtils.checkTrue(length > 0L, "Invalid length: %d", length);
+
         Digest digest = BuiltinDigests.md5.create();
         digest.init();
 
         long effectiveLength = length;
         byte[] digestBuf = new byte[(int) Math.min(effectiveLength, SftpConstants.MD5_QUICK_HASH_SIZE)];
-        ByteBuffer bb = ByteBuffer.wrap(digestBuf);
+        ByteBuffer wb = ByteBuffer.wrap(digestBuf);
         boolean hashMatches = false;
         byte[] hashValue = null;
 
@@ -968,7 +998,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
                 // TODO consider limiting it - e.g., if the requested effective length is <= than some (configurable) threshold
                 hashMatches = true;
             } else {
-                int readLen = channel.read(bb);
+                int readLen = channel.read(wb);
                 if (readLen < 0) {
                     throw new EOFException("EOF while read initial buffer from " + path);
                 }
@@ -1002,6 +1032,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
 
             if (hashMatches) {
                 while(effectiveLength > 0L) {
+                    int remainLen = Math.min(digestBuf.length, (int) effectiveLength);
+                    ByteBuffer bb = wb;
+                    if (remainLen < digestBuf.length) {
+                        bb = ByteBuffer.wrap(digestBuf, 0, remainLen);
+                    }
                     bb.clear(); // prepare for next read
 
                     int readLen = channel.read(bb);
@@ -1298,6 +1333,96 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
         Files.move(o, n, GenericUtils.isEmpty(opts) ? IoUtils.EMPTY_COPY_OPTIONS : opts.toArray(new CopyOption[opts.size()]));
     }
 
+    // see https://tools.ietf.org/html/draft-ietf-secsh-filexfer-extensions-00#section-7
+    protected void doCopyData(Buffer buffer, int id) throws IOException {
+        String readHandle = buffer.getString();
+        long readOffset = buffer.getLong();
+        long readLength = buffer.getLong();
+        String writeHandle = buffer.getString();
+        long writeOffset = buffer.getLong();
+        try {
+            doCopyData(id, readHandle, readOffset, readLength, writeHandle, writeOffset);
+        } catch (IOException | RuntimeException e) {
+            sendStatus(BufferUtils.clear(buffer), id, e);
+            return;
+        }
+
+        sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OK, "");
+    }
+
+    @SuppressWarnings("resource")
+    protected void doCopyData(int id, String readHandle, long readOffset, long readLength, String writeHandle, long writeOffset) throws IOException {
+        boolean inPlaceCopy = readHandle.equals(writeHandle);
+        Handle rh = handles.get(readHandle);
+        Handle wh = inPlaceCopy ? rh : handles.get(writeHandle);
+        if (log.isDebugEnabled()) {
+            log.debug("SSH_FXP_EXTENDED[{}] read={}[{}], read-offset={}, read-length={}, write={}[{}], write-offset={})",
+                      SftpConstants.EXT_COPYDATA,
+                      readHandle, rh, Long.valueOf(readOffset), Long.valueOf(readLength),
+                      writeHandle, wh, Long.valueOf(writeOffset));
+        }
+
+        FileHandle srcHandle = validateHandle(readHandle, rh, FileHandle.class);
+        Path srcPath = srcHandle.getFile();
+        int srcAccess = srcHandle.getAccessMask();
+        if ((srcAccess & ACE4_READ_DATA) != ACE4_READ_DATA) {
+            throw new AccessDeniedException("File not opened for read: " + srcPath);
+        }
+
+        ValidateUtils.checkTrue(readLength >= 0L, "Invalid read length: %d", readLength);
+        ValidateUtils.checkTrue(readOffset >= 0L, "Invalid read offset: %d", readOffset);
+
+        long totalSize = Files.size(srcHandle.getFile());
+        long effectiveLength = readLength;
+        if (effectiveLength == 0L) {
+            effectiveLength = totalSize - readOffset;
+        } else {
+            long maxRead = readOffset + effectiveLength;
+            if (maxRead > totalSize) {
+                effectiveLength = totalSize - readOffset;
+            }
+        }
+        ValidateUtils.checkTrue(effectiveLength > 0L, "Non-positive effective copy data length: %d", effectiveLength);
+
+        FileHandle dstHandle = inPlaceCopy ? srcHandle : validateHandle(writeHandle, wh, FileHandle.class);
+        int dstAccess = dstHandle.getAccessMask();
+        if ((dstAccess & ACE4_WRITE_DATA) != ACE4_WRITE_DATA) {
+            throw new AccessDeniedException("File not opened for write: " + srcHandle);
+        }
+
+        ValidateUtils.checkTrue(writeOffset >= 0L, "Invalid write offset: %d", writeOffset);
+        // check if overlapping ranges as per the draft
+        if (inPlaceCopy) {
+            long maxRead = readOffset + effectiveLength;
+            if (maxRead > totalSize) {
+                maxRead = totalSize;
+            }
+            
+            long maxWrite = writeOffset + effectiveLength;
+            if (maxWrite > readOffset) {
+                throw new IllegalArgumentException("Write range end [" + writeOffset + "-" + maxWrite + "]"
+                                                 + " overlaps with read range [" + readOffset + "-" +  maxRead + "]");
+            } else if (maxRead > writeOffset) {
+                throw new IllegalArgumentException("Read range end [" + readOffset + "-" +  maxRead + "]"
+                                                 + " overlaps with write range [" + writeOffset + "-" + maxWrite + "]");
+            }
+        }
+        
+        byte[] copyBuf = new byte[Math.min(IoUtils.DEFAULT_COPY_SIZE, (int) effectiveLength)];
+        while(effectiveLength > 0L) {
+            int remainLength = Math.min(copyBuf.length, (int) effectiveLength);
+            int readLen = srcHandle.read(copyBuf, 0, remainLength, readOffset);
+            if (readLen < 0) {
+                throw new EOFException("Premature EOF while still remaining " + effectiveLength + " bytes");
+            }
+            dstHandle.write(copyBuf, 0, readLen, writeOffset);
+
+            effectiveLength -= readLen;
+            readOffset += readLen;
+            writeOffset += readLen;
+        }
+    }
+
     // see https://tools.ietf.org/html/draft-ietf-secsh-filexfer-extensions-00#section-6
     protected void doCopyFile(Buffer buffer, int id) throws IOException {
         String srcFile = buffer.getString();
@@ -1317,7 +1442,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
     protected void doCopyFile(int id, String srcFile, String dstFile, boolean overwriteDestination) throws IOException {
         if (log.isDebugEnabled()) {
             log.debug("SSH_FXP_EXTENDED[{}] (src={}, dst={}, overwrite=0x{})",
-                       SftpConstants.EXT_COPYFILE, srcFile, dstFile, Boolean.valueOf(overwriteDestination));
+                      SftpConstants.EXT_COPYFILE, srcFile, dstFile, Boolean.valueOf(overwriteDestination));
         }
         
         doCopyFile(id, srcFile, dstFile,
@@ -2951,6 +3076,8 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
             return SSH_FX_LOCK_CONFLICT;
         } else if (e instanceof UnsupportedOperationException) {
             return SSH_FX_OP_UNSUPPORTED;
+        } else if (e instanceof IllegalArgumentException) {
+            return SSH_FX_INVALID_PARAMETER;
         } else {
             return SSH_FX_FAILURE;
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
index d1e200a..8f37d39 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
@@ -31,13 +31,10 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.URI;
 import java.nio.charset.StandardCharsets;
-import java.nio.file.FileSystem;
 import java.nio.file.Files;
 import java.nio.file.LinkOption;
 import java.nio.file.Path;
-import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.EnumSet;
 import java.util.Iterator;
 import java.util.List;
@@ -50,38 +47,21 @@ import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.sshd.client.SftpException;
 import org.apache.sshd.client.SshClient;
 import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.client.subsystem.sftp.SftpClient.CloseableHandle;
 import org.apache.sshd.client.subsystem.sftp.extensions.BuiltinSftpClientExtensions;
 import org.apache.sshd.client.subsystem.sftp.extensions.CopyFileExtension;
-import org.apache.sshd.client.subsystem.sftp.extensions.MD5FileExtension;
-import org.apache.sshd.client.subsystem.sftp.extensions.MD5HandleExtension;
 import org.apache.sshd.client.subsystem.sftp.extensions.SftpClientExtension;
 import org.apache.sshd.common.Factory;
 import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.digest.BuiltinDigests;
-import org.apache.sshd.common.digest.Digest;
-import org.apache.sshd.common.file.FileSystemFactory;
-import org.apache.sshd.common.file.root.RootedFileSystemProvider;
 import org.apache.sshd.common.random.Random;
-import org.apache.sshd.common.session.Session;
 import org.apache.sshd.common.subsystem.sftp.SftpConstants;
 import org.apache.sshd.common.subsystem.sftp.extensions.ParserUtils;
 import org.apache.sshd.common.subsystem.sftp.extensions.Supported2Parser.Supported2;
 import org.apache.sshd.common.subsystem.sftp.extensions.SupportedParser.Supported;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.OsUtils;
-import org.apache.sshd.common.util.buffer.BufferUtils;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
 import org.apache.sshd.common.util.io.IoUtils;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.SshServer;
-import org.apache.sshd.server.command.ScpCommandFactory;
 import org.apache.sshd.server.subsystem.sftp.SftpSubsystem;
-import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory;
-import org.apache.sshd.util.BaseTestSupport;
-import org.apache.sshd.util.BogusPasswordAuthenticator;
-import org.apache.sshd.util.EchoShellFactory;
 import org.apache.sshd.util.JSchLogger;
 import org.apache.sshd.util.SimpleUserInfo;
 import org.apache.sshd.util.Utils;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/CopyDataExtensionImplTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/CopyDataExtensionImplTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/CopyDataExtensionImplTest.java
new file mode 100644
index 0000000..419e326
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/CopyDataExtensionImplTest.java
@@ -0,0 +1,203 @@
+/*
+ * 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.client.subsystem.sftp.extensions;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.client.subsystem.sftp.AbstractSftpClientTestSupport;
+import org.apache.sshd.client.subsystem.sftp.SftpClient;
+import org.apache.sshd.client.subsystem.sftp.SftpClient.CloseableHandle;
+import org.apache.sshd.common.Factory;
+import org.apache.sshd.common.random.Random;
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RunWith(Parameterized.class)   // see https://github.com/junit-team/junit/wiki/Parameterized-tests
+public class CopyDataExtensionImplTest extends AbstractSftpClientTestSupport {
+    private static final List<Object[]> PARAMETERS =
+            Collections.unmodifiableList(
+                    Arrays.<Object[]>asList(
+                                new Object[] {
+                                        Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE),
+                                        Integer.valueOf(0),
+                                        Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE),
+                                        Long.valueOf(0L)
+                                    },
+                                new Object[] {
+                                        Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE),
+                                        Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE / 2),
+                                        Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE / 4),
+                                        Long.valueOf(0L)
+                                    },
+                                new Object[] {
+                                        Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE),
+                                        Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE / 2),
+                                        Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE / 4),
+                                        Long.valueOf(IoUtils.DEFAULT_COPY_SIZE / 2)
+                                    },
+                                new Object[] {
+                                        Integer.valueOf(Byte.MAX_VALUE),
+                                        Integer.valueOf(Byte.MAX_VALUE / 2),
+                                        Integer.valueOf(Byte.MAX_VALUE),    // attempt to read more than available
+                                        Long.valueOf(0L)
+                                    }
+                            ));
+
+    @Parameters(name = "size={0}, readOffset={1}, readLength={2}, writeOffset={3}")
+    public static Collection<Object[]> parameters() {
+        return PARAMETERS;
+    }
+
+    private int size, srcOffset, length;
+    private long dstOffset;
+
+    public CopyDataExtensionImplTest(int size, int srcOffset, int length, long dstOffset) throws IOException {
+        this.size = size;
+        this.srcOffset = srcOffset;
+        this.length = length;
+        this.dstOffset = dstOffset;
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        setupServer();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        tearDownServer();
+    }
+
+    @Test
+    public void testCopyDataExtension() throws Exception {
+        testCopyDataExtension(size, srcOffset, length, dstOffset);
+    }
+
+    private void testCopyDataExtension(int dataSize, int readOffset, int readLength, long writeOffset) throws Exception {
+        byte[] seed = (getClass().getName() + "#" + getCurrentTestName()
+                     + "-" + dataSize
+                     + "-" + readOffset + "/" + readLength + "/" + writeOffset
+                     + System.getProperty("line.separator"))
+                .getBytes(StandardCharsets.UTF_8)
+                ;
+        try(ByteArrayOutputStream baos=new ByteArrayOutputStream(dataSize + seed.length)) {
+            while (baos.size() < dataSize) {
+                baos.write(seed);
+            }
+            
+            testCopyDataExtension(baos.toByteArray(), readOffset, readLength, writeOffset);
+        }
+    }
+
+    private void testCopyDataExtension(byte[] data, int readOffset, int readLength, long writeOffset) throws Exception {
+        Path targetPath = detectTargetFolder().toPath();
+        Path parentPath = targetPath.getParent();
+        Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName());
+        Utils.deleteRecursive(lclSftp);
+        LinkOption[] options = IoUtils.getLinkOptions(false);
+        assertHierarchyTargetFolderExists(lclSftp, options);
+
+        String baseName = getCurrentTestName() + "-" + readOffset + "-" + readLength + "-" + writeOffset;
+        Path srcFile = lclSftp.resolve(baseName + "-src.txt");
+        Files.write(srcFile, data, IoUtils.EMPTY_OPEN_OPTIONS);
+        String srcPath = Utils.resolveRelativeRemotePath(parentPath, srcFile);
+
+        Path dstFile = srcFile.getParent().resolve(baseName + "-dst.txt");
+        if (Files.exists(dstFile, options)) {
+            Files.delete(dstFile);
+        }
+        String dstPath = Utils.resolveRelativeRemotePath(parentPath, dstFile);
+
+        try(SshClient client = SshClient.setUpDefaultClient()) {
+            client.start();
+
+            if (writeOffset > 0L) {
+                Factory<? extends Random> factory = client.getRandomFactory();
+                Random randomizer = factory.create();
+                long totalLength = writeOffset + readLength;
+                byte[] workBuf = new byte[(int) Math.min(totalLength, IoUtils.DEFAULT_COPY_SIZE)];
+                try(OutputStream output = Files.newOutputStream(dstFile, IoUtils.EMPTY_OPEN_OPTIONS)) {
+                    while(totalLength > 0L) {
+                        randomizer.fill(workBuf);
+                        output.write(workBuf);
+                        totalLength -= workBuf.length;
+                    }
+                }
+            }
+
+            try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).verify(7L, TimeUnit.SECONDS).getSession()) {
+                session.addPasswordIdentity(getCurrentTestName());
+                session.auth().verify(5L, TimeUnit.SECONDS);
+                
+                try(SftpClient sftp = session.createSftpClient()) {
+                    CopyDataExtension ext = assertExtensionCreated(sftp, CopyDataExtension.class);
+                    try(CloseableHandle readHandle = sftp.open(srcPath, SftpClient.OpenMode.Read);
+                        CloseableHandle writeHandle = sftp.open(dstPath, SftpClient.OpenMode.Write, SftpClient.OpenMode.Create)) {
+                        ext.copyData(readHandle, readOffset, readLength, writeHandle, writeOffset);
+                    }
+                }
+            } finally {
+                client.stop();
+            }
+        }
+        
+        int available = data.length, required = readOffset + readLength;
+        if (required > available) {
+            required = available; 
+        }
+        byte[] expected = new byte[required - readOffset];
+        System.arraycopy(data, readOffset, expected, 0, expected.length);
+        
+        byte[] actual = new byte[expected.length];
+        try(FileChannel channel = FileChannel.open(dstFile, IoUtils.EMPTY_OPEN_OPTIONS)) {
+            int readLen = channel.read(ByteBuffer.wrap(actual), writeOffset);
+            assertEquals("Mismatched read data size", expected.length, readLen);
+        }
+        assertArrayEquals("Mismatched copy data", expected, actual);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthAgent.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthAgent.java b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthAgent.java
index e0f0b12..74e1935 100644
--- a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthAgent.java
+++ b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthAgent.java
@@ -52,23 +52,20 @@ public class UserAuthAgent extends AbstractUserAuth {
         try {
             log.debug("Send SSH_MSG_USERAUTH_REQUEST for publickey");
             Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST);
-            int pos1 = buffer.wpos() - 1;
             buffer.putString(session.getUsername());
             buffer.putString(service);
             buffer.putString(UserAuthPublicKeyFactory.NAME);
-            buffer.putByte((byte) 1);
+            buffer.putBoolean(true);
             buffer.putString(KeyUtils.getKeyType(key));
-            int pos2 = buffer.wpos();
             buffer.putPublicKey(key);
 
-
             Buffer bs = new ByteArrayBuffer();
             bs.putBytes(session.getKex().getH());
             bs.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
             bs.putString(session.getUsername());
             bs.putString(service);
             bs.putString(UserAuthPublicKeyFactory.NAME);
-            bs.putByte((byte) 1);
+            bs.putBoolean(true);
             bs.putString(KeyUtils.getKeyType(key));
             bs.putPublicKey(key);
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPassword.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPassword.java b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPassword.java
index 53a77c8..26cefa4 100644
--- a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPassword.java
+++ b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPassword.java
@@ -45,7 +45,7 @@ public class UserAuthPassword extends AbstractUserAuth {
             buffer.putString(session.getUsername());
             buffer.putString(service);
             buffer.putString("password");
-            buffer.putByte((byte) 0);
+            buffer.putBoolean(false);
             buffer.putString(password);
             session.writePacket(buffer);
             return Result.Continued;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/515427fa/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPublicKey.java b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPublicKey.java
index c3fbae7..e90a33a 100644
--- a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPublicKey.java
+++ b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPublicKey.java
@@ -51,14 +51,12 @@ public class UserAuthPublicKey extends AbstractUserAuth {
             try {
                 log.debug("Send SSH_MSG_USERAUTH_REQUEST for publickey");
                 buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST);
-                int pos1 = buffer.wpos() - 1;
                 buffer.putString(session.getUsername());
                 buffer.putString(service);
                 buffer.putString(UserAuthPublicKeyFactory.NAME);
-                buffer.putByte((byte) 1);
+                buffer.putBoolean(true);
                 String alg = KeyUtils.getKeyType(key);
                 buffer.putString(alg);
-                int pos2 = buffer.wpos();
                 buffer.putPublicKey(key.getPublic());
 
                 FactoryManager manager = session.getFactoryManager();
@@ -74,7 +72,7 @@ public class UserAuthPublicKey extends AbstractUserAuth {
                 bs.putString(session.getUsername());
                 bs.putString(service);
                 bs.putString(UserAuthPublicKeyFactory.NAME);
-                bs.putByte((byte) 1);
+                bs.putBoolean(true);
                 bs.putString(alg);
                 bs.putPublicKey(key.getPublic());
                 verif.update(bs.array(), bs.rpos(), bs.available());