我已阅读RFC并尝试在我的FTP服务器中实现SSL连接。
我已使用javax.net.ssl.SSLSocket将所有套接字切换为SSLServer套接字和SSL套接字; javax.net.ssl.SSLSocketFactory;
使用FileZilla使用SSL显式加密时,我收到一条消息说, "与127.0.0.1连接,协商SSL连接"
它会被卡在那里。
如何对服务器进行编程以协商SSL连接?
以下代码是ServerSocket启动的位置,等待连接。
// Starts a server Socket to listen to new clients
System.setProperty("javax.net.ssl.trustStore","ServerFiles\\default_KeyStore\\server.keystore");
SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
this.entryPortSock = (SSLServerSocket)sslserversocketfactory.createServerSocket((Integer) st.getValue("CMDPort"));
SSLSocket scCMDPort;
// Initiates the Rolling Log
RollingLog rollingLog = new RollingLog((String) st.getValue("LOGfiledirectory"), st);
Runnable RunnableRollingLog = rollingLog;
Thread logger = new Thread(RunnableRollingLog);
logger.start();
// Continues to listen to new clients and connect to them when
// available.
while (true) {
scCMDPort =(SSLSocket) this.entryPortSock.accept();
System.out.println("System accepted a new friend!");
// Starting the service for the client
Runnable ftpService = new FTPService(rollingLog, (String) st.getValue("ROOT"), scCMDPort, st);
Thread service = new Thread(ftpService);
service.start();
}
以下是我可以从客户端接受的服务器支持的命令。
private void action(ServerCmd command) {
// Process of logging in, Must pass this boundary before any other
// command can be given.
if (DEBUG_INCOMING) {
System.out.println("Client: " + command.cmdType + " " + reJoinString(command.args));
}
printLog("Client: " + command.cmdType + " " + reJoinString(command.args));
if (command.cmdType.equals(ServerCommands.AUTH)) {
if(command.args.get(0).equalsIgnoreCase("SSL")){
this.sendOut("334 Yo homie we can start that SSL connection!");
}
}
else if (command.cmdType.equals(ServerCommands.USER)) {
this.User(command);
}
else if (command.cmdType.equals(ServerCommands.PASS)) {
this.Pass(command.args.get(0));
}
// After login in, all of these commands can be read.
else if (this.Status == 1) {
if (command.cmdType.equals(ServerCommands.SYST)) {
// Reads a request for the operating system of the Server.
this.Syst();
}
else if (command.cmdType.equals(ServerCommands.FEAT)) {
// Reads a request FEAT
this.Feat();
} else if (command.cmdType.equals(ServerCommands.PWD)) {
// Reads a request to print the working directory
this.Pwd();
}
else if (command.cmdType.equals(ServerCommands.TYPE)) {
// Read a request Type
this.Type(command.args.get(0));
}
else if (command.cmdType.equals(ServerCommands.PASV)) {
// Request PASV connection
this.Pasv();
} else if (command.cmdType.equals(ServerCommands.LIST)) {
// Request directory listing
this.List();
}
else if (command.cmdType.equals(ServerCommands.CWD)) {
//
String temp = this.reJoinString((command.args));
this.Cwd(temp);
}
else if (command.cmdType.equals(ServerCommands.CDUP)) {
this.Cdup();
}
else if (command.cmdType.equals(ServerCommands.STOR)) {
this.Stor(this.reJoinString(command.args));
} else if (command.cmdType.equals(ServerCommands.RETR)) {
this.Retr(this.reJoinString(command.args));
} else if (command.cmdType.equals(ServerCommands.QUIT)) {
System.exit(0);
} else if (command.cmdType.equals(ServerCommands.HELP)) {
sendOut("214 Help: Connect to FileZilla, the older version without caching to use this FTP Server. Or, a command prompt client would work as well.\n"
+ "Accepted FTP Commands: USER, PASS, SYST, FEAT, PWD, TYPE, PASV, LIST, CWD, CDUP, EPSV, STOR, RETR, QUIT");
} else if (command.cmdType.equals((ServerCommands.PORT))) {
if (((String) (this.settings.getValue("PORTmode"))).equalsIgnoreCase("YES")) {
this.Port(this.reJoinString(command.args));
} else {
sendOut("522 This command is not supported");
}
} else if (command.cmdType.equals(ServerCommands.EPRT)) {
if (((String) (this.settings.getValue("PORTmode"))).equalsIgnoreCase("YES")) {
this.EPRT(this.reJoinString(command.args));
} else {
sendOut("522 This command is not supported");
}
} else if (command.cmdType.equals((ServerCommands.EPSV))) {
// Turn true to support EPSV
if (((String) (this.settings.getValue("PASVmode"))).equalsIgnoreCase("YES")) {
this.EPSV();
} else {
sendOut("522 This command is not supported");
}
}
}
更新: 一旦从客户端发送了AUTH SSL命令,我就实现了从Socket到SSL套接字的升级。这是我的代码:
SSLSocketFactory sslsocketfactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
this.clientSocket1 = sslsocketfactory.createSocket(serverSocket.getInetAddress().getHostAddress(), serverSocket.getLocalPort());
((SSLSocket)this.clientSocket1).setUseClientMode(false);
this.sendOut("334 Yo homie we can start that SSL connection!");
客户对此的回应:客户:€j Q [] 9 8 5 [] [] 类似的东西。如何解密消息?
为了尝试回应上面的问题,我重新实例化了我的缓冲区读取器,它从常规Socket读取到SSLSocket的流,下面的代码如下:
SSLSocketFactory sslsocketfactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
this.clientSocket1 = sslsocketfactory.createSocket(serverSocket.getInetAddress().getHostAddress(), serverSocket.getLocalPort());
((SSLSocket)this.clientSocket1).setUseClientMode(false);
((SSLSocket)this.clientSocket1).startHandshake();
cipher =sslsocketfactory.getDefaultCipherSuites();
this.encrypted = true;
this.sendOut("334 Yo homie we can start that SSL connection!");
this.in = new BufferedReader(new InputStreamReader(((SSLSocket)this.clientSocket1).getInputStream()));
this.out = new PrintWriter(((SSLSocket)this.clientSocket1).getOutputStream());
可能握手崩溃的整个堆栈跟踪。
javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
at sun.security.ssl.InputRecord.handleUnknownRecord(Unknown Source)
at sun.security.ssl.InputRecord.read(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readDataRecord(Unknown Source)
at sun.security.ssl.AppInputStream.read(Unknown Source)
at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
at sun.nio.cs.StreamDecoder.read(Unknown Source)
at java.io.InputStreamReader.read(Unknown Source)
at java.io.BufferedReader.fill(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at FTPServer.FTPService.run(FTPService.java:100)
at java.lang.Thread.run(Unknown Source)
客户的日志:< ---文件zilla 回复:220 IiiiDeentiffy YouuurSelf !!! 命令:AUTH SSL 回复:234哟我们可以启动SSL连接了!
服务器的日志< ---我编程的那个
javax.net.ssl.SSLException: Connection has been shutdown: javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
at sun.security.ssl.SSLSocketImpl.checkEOF(Unknown Source)
at sun.security.ssl.AppInputStream.read(Unknown Source)
at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
at sun.nio.cs.StreamDecoder.read(Unknown Source)
at java.io.InputStreamReader.read(Unknown Source)
at java.io.BufferedReader.fill(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at FTPServer.FTPService.run(FTPService.java:100)
at java.lang.Thread.run(Unknown Source)
Caused by: javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
at sun.security.ssl.InputRecord.handleUnknownRecord(Unknown Source)
at sun.security.ssl.InputRecord.read(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.getSession(Unknown Source)
at FTPServer.FTPService.action(FTPService.java:143)
at FTPServer.FTPService.run(FTPService.java:102)
... 1 more
服务线程已停止?!
更短的版本
package testServer;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
public class driverServerTest {
public static void main(String args[]) {
try {
ServerSocket Ssc = new ServerSocket(21);
Socket sc;
sc = Ssc.accept();
PrintWriter out = new PrintWriter(sc.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(sc.getInputStream()));
out.println("220 The connection succeeded");
out.flush();
String temp;
while (true) {
temp = in.readLine();
System.out.println(temp);
if (temp.equalsIgnoreCase("AUTH SSL")) {
out.println("334 Yo homie we can start that SSL connection!");
out.flush();
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
sc = sslsocketfactory.createSocket(Ssc.getInetAddress().getHostAddress(), Ssc.getLocalPort());
((SSLSocket) sc).setUseClientMode(false);
in = new BufferedReader(new InputStreamReader(((SSLSocket) sc).getInputStream()));
out = new PrintWriter(((SSLSocket) sc).getOutputStream());
out.println("234 request login information");
out.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
客户回复:
Status: Connecting to 127.0.0.1 ...
Status: Connected with 127.0.0.1, negotiating SSL connection...
Response: 220 The connection succeeded
Command: AUTH SSL
Response: 334 Yo homie we can start that SSL connection!
答案 0 :(得分:1)
如果收到AUTH TLS命令,则需要以普通ServerSocket
开头并使用SSLSocketFactory.createSocket(Socket, ...)
将普通Socket
升级为SSL。
在使用它进行任何I / O之前,不要忘记致电SSLSocket.setUseClientMode(false);
。