How to implement a ftp over tls client by qsslsocket? - qt

In FTPS, the client connect to the server, the server sending a welcome message; thus, then client send command "AUTH TLS",the server set Certificate态PrivateKey and startServerEncryption; what should the client do to finish this ssl handshake?
Server:
if ("AUTH" == command && "TLS" == commandParameters.toUpper())
{
auth();
}
void FtpControlConnection::auth()
{
reply("234 Initializing SSL connection.");
SslServer::setLocalCertificateAndPrivateKey(socket);
socket->startServerEncryption();
}
void SslServer::setLocalCertificateAndPrivateKey(QSslSocket *socket)
{
socket->setPrivateKey(":/ssl/server.key", QSsl::Rsa, QSsl::Pem, "1234");
Q_ASSERT(!socket->privateKey().isNull());
socket->setLocalCertificate(":/ssl/server.crt");
Q_ASSERT(!socket->localCertificate().isNull());
}
void SslServer::incomingConnection(PortableSocketDescriptorType socketDescriptor)
{
QSslSocket *socket = new QSslSocket(this);
if (socket->setSocketDescriptor(socketDescriptor)) {
addPendingConnection(socket);
} else {
delete socket;
}
}
client
socket->connectToHost(hostNameEdit->text(), portBox->value());
socket->write("AUTH TLS\r\n");
socket->waitForConnected();
socket->startClientEncryption();
socket->waitForEncrypted();
I wish the client finish the ssl shakehand by using startClientEncryption, and then I can use the client socket to send command or file; but it does not work; I know the client socket and the server socket already connect, but how to add ssl on this?

Related

How to reuse session and the port number in TCP-TLS communication using Cloudbees- TcpSyslogMessageSender

We have a syslog client in our application and it is implemented using Cloudbees- TcpSyslogMessageSender. We are creating the context and connHow to reuse the session and port number in TCP-TLS communication using Cloudbees- TcpSyslogMessageSender.
Will it be handled by Cloudbees or we have to configure any settings explicitly. Here is our code.
With this code, it is using a new port everytime.
TcpSyslogMessageSender messageSendertcp = new TcpSyslogMessageSender();
messageSendertcp.setSyslogServerHostname("localhost");
messageSendertcp.setSyslogServerPort("6514");
messageSendertcp.setMessageFormat(MessageFormat.RFC_5425);
messageSendertcp.setDefaultMessageHostname(this.getHostName());
messageSendertcp.setDefaultAppName("test");
messageSendertcp.setDefaultFacility("local0"));
messageSendertcp.setDefaultSeverity("notice");
logger.info("entering getsslcontext");
SSLContext context = getSSLContext(); //SSLContext is formed using client keystore and trustores
logger.info("context object");
messageSendertcp.setSSLContext(context);
messageSendertcp.setSsl(true);
}
try {
logger.info("sending message tcp");
messageSendertcp.sendMessage(syslogMessage);
} catch (IOException e) {
return false;
} finally {
try {
if (messageSendertcp != null)
messageSendertcp.close();
} catch (IOException e) {
return false;
}
}
Here Every Time your code is closing TCP object and and whenever new message comes it is again creating and using new socket. So in order to send the message on same port do not close the socket(TCP object) and use the Server details cache. For example this cache implemented using map that contains Server Details as the map and TCP object as key. And do not close the TCP object.

Does QNetworkAccessManager support HTTPS proxy?

I compiled OpenSSL on my Windows machine and was able to do HTTPS queries with QNetworkAccessManager, but when I try to add HTTPS proxy
QNetworkAccessManager m_nm;
connect(&m_nm, &QNetworkAccessManager::proxyAuthenticationRequired, this, &BinanceReceiver::onProxyAuthenticationRequired);
connect(&m_nm, &QNetworkAccessManager::sslErrors, this, &BinanceReceiver::onSslErrors);
QNetworkProxy m_proxy(QNetworkProxy::HttpProxy, "host.com", 3129, "user", "password");
m_nm.setProxy(m_proxy);
QNetworkRequest request;
request.setUrl(MakeUrl(url));
QNetworkReply* reply = m_nm.get(request);
QObject::connect(reply, &QNetworkReply::finished, [this, reply]()
{
if (reply->error())
{
netLogger.error(reply->errorString());
}
else
{
//...
}
//Ensure it is deleted after this handler is called, but not before.
delete reply;
});
it stops working, I do not get the reply at all and neither proxyAuthenticationRequired nore sslErrors is triggered.
It is a Squid HTTPS proxy with the authentication.
Does QNetworkAccessManager support HTTPS proxy?

Java gRPC: exception from client to server

Is it's possible to throw an exception from the client to the server?
We have an open stream from the server to the client:
rpc addStream(Request) returns (stream StreamMessage) {}
When i try something like this:
throw Status.INTERNAL.withDescription(e.getMessage()).withCause(e.getCause()).asRuntimeException();
I got the exception in the StreamObserver.onError on the client, but there is no exception on the server-side.
Servers can respond with a "status" that the stub API exposes as a StatusRuntimeException. Clients, however, can only "cancel" the RPC. Servers will not know the source of the cancellation; it could be because the client cancelled or maybe the TCP connection broke.
In a client-streaming or bidi-streaming call, the client can cancel by calling observer.onError() (without ever calling onCompleted()). However, if the client called onCompleted() or the RPC has a unary request, then you need to use ClientCallStreamObserver or Context:
stub.someRpc(request, new ClientResponseObserver<Request, Response>() {
private ClientCallStreamObserver<Request> requestStream;
#Override public void beforeStart(ClientCallStreamObserver<Request> requestStream) {
this.requestStream = requestStream;
}
...
});
// And then where you want to cancel
// RequestStream is non-thread-safe. For unary requests, wait until
// stub.someRpc() returns, since it uses the stream internally.
// The string is not sent to the server. It is just "echoed"
// back to the client's `onError()` to make clear that the
// cancellation was locally caused.
requestStream.cancel("some message for yourself", null);
// For thread-safe cancellation (e.g., for client-streaming)
CancellableContext ctx = Context.current().withCancellation();
StreamObserver requestObserver = ctx.call(() ->
stub.someRpc(new StreamObserver<Response>() {
#Override public void onCompleted() {
// The ctx must be closed when done, to avoid leaks
ctx.cancel(null);
}
#Override public void onError() {
ctx.cancel(null);
}
}));
// The place you want to cancel
ctx.cancel(ex);

Qt with QSslSocket not connecting properly

I have a Client-Server application that was working with QTcpSocket. Now I would like to use an encrypted SSL connection instead, therefore I tried to switch to QSslSocket. But I can't establish a connection to server.
Here is the code for the client:
ConnectionHandler::ConnectionHandler(QString ip, int port, QObject *parent) : QObject(parent) {
// connect(this->socket, SIGNAL(connected()), this, SLOT(connected()));
connect(this->socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
connect(this->socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(this->socket, SIGNAL(encrypted()), this, SLOT(encryptedReady()));
connect(this->socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(SSLerrorOccured(const QList<QSslError> &)));
connect(this->socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
connect(this->socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));
this->ip = ip;
this->port = port;
}
void ConnectionHandler::socketStateChanged(QAbstractSocket::SocketState state) {
qDebug() << state;
}
void ConnectionHandler::socketError(QAbstractSocket::SocketError) {
qDebug() << this->socket->errorString();
}
void ConnectionHandler::encryptedReady() {
qDebug() << "READY";
}
void ConnectionHandler::SSLerrorOccured(const QList<QSslError> &) {
qDebug() << "EEROR";
}
void ConnectionHandler::connectToServer() {
// this->socket->connectToHost(this->ip, this->port);
this->socket->connectToHostEncrypted(this->ip, this->port);
if (!this->socket->waitForConnected(5000)) {
this->socket->close();
this->errorMsg = this->socket->errorString();
}
}
void ConnectionHandler::connected() {
qDebug() << "connected";
this->connectedHostAddress = this->socket->peerAddress().toString();
this->connectionEstablished = true;
this->localIP = this->socket->localAddress().toString();
this->localPort = this->socket->localPort();
}
Here the one for the server:
ClientHandler::ClientHandler() {
this->socket->setProtocol(QSsl::SslV3);
this->socket->setSocketOption(QAbstractSocket::KeepAliveOption, true);
}
void ClientHandler::run() {
if (!this->fd)
return;
connect(this->socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(this->socket, SIGNAL(disconnected()), this, SLOT(disconnected()), Qt::DirectConnection);
connect(this->socket, SIGNAL(encrypted()), this, SLOT(encryptedReady()));
connect(this->socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrorOccured(const QList<QSslError> &)));
connect(this->socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
connect(this->socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));
if (!this->socket->setSocketDescriptor(this->fd)) {
emit error(socket->error());
return;
} else {
connect(this->socket, SIGNAL(encrypted()), this, SLOT(ready()));
this->socket->startServerEncryption();
}
this->peerIP = socket->peerAddress().toString();
QString tmp;
tmp.append(QString("%1").arg(socket->peerPort()));
this->peerPort = tmp;
QHostInfo::lookupHost(this->peerIP, this, SLOT(lookedUp(QHostInfo)));
}
void ClientHandler::socketStateChanged(QAbstractSocket::SocketState state) {
qDebug() << state;
}
void ClientHandler::socketError(QAbstractSocket::SocketError) {
qDebug() << this->socket->errorString();
}
void ClientHandler::setFileDescriptor(int fd) {
this->fd = fd;
}
void ClientHandler::ready() {
qDebug() << "READY";
}
void ClientHandler::sslErrorOccured(const QList<QSslError> &) {
qDebug() << "EEROR";
}
void ClientHandler::encryptedReady() {
qDebug() << "READY";
}
The output for the client I receive is:
QAbstractSocket::HostLookupState
QAbstractSocket::ConnectingState
QAbstractSocket::ConnectedState
"The remote host closed the connection"
QAbstractSocket::ClosingState
QAbstractSocket::UnconnectedState
and for the server:
QAbstractSocket::ConnectedState
"Error during SSL handshake: error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher"
QAbstractSocket::UnconnectedState
Does anyone know how to fix this?
I assume that with non encrypted sockets everything is fine. So let's focus only on peculiarities of detailing with QSslSocket. I can share larger pieces or working code if needed. There is also a large story regarding SSL certificates that I will touch briefly here.
To start let's check you client on some external HTTP SSL servers, for example:
socket->connectToHostEncrypted("gmail.com", 443);
It should work immediately with default SSL protocol (without any setProtocol()). On the signal encrypted() you can write HTTP GET header and on the readyRead() the reply will come.
Now try to set socket->setProtocol(QSsl::SslV3); for "gmail.com". Expected result:
sslErrorOccured: ("The host name did not match any of the valid hosts for this certificate")
Note that it is not the error() signal but the sslErrors() signal notifying about certificate issues that can be ignored by client.
So, for simplicity let's work with default SSL protocol without using setProtocol().
Since the client is in working state we can move to the server. You were interrupted on the first level of SSL certification challenge. To start initializing SSL connection by the server you have to provide at least private encryption key and public certificate. That is your error:
"Error during SSL handshake: error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher"
In the perfect case your certificate should be signed by an authentication authority company. In that case any client that has a list of such root certificates is able to check that your certificate is valid. However that service is paid and it may take few weeks. We can start with self signed certificate.
You can find various recipes for generating certificates, for example: "How to create a self-signed SSL Certificate which can be used for testing purposes or internal usage"
Short extract:
#Step 1: Generate a Private Key
openssl genrsa -des3 -out server.key 1024
#Step 2: Generate a CSR (Certificate Signing Request)
#Common Name (eg, your name or your server's hostname) []:example.com
openssl req -new -key server.key -out server.csr
#Step 3: Remove Passphrase from Key
cp server.key server.key.org
openssl rsa -in server.key.org -out server.key
#Step 4: Generating a Self-Signed Certificate
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
Now there are server.key and server.crt files. Those files should be passed by the server to QSslSocket before startServerEncryption():
socket->setPrivateKey("c:/test/ssl/cert/server.key", QSsl::Rsa);
socket->setLocalCertificate("c:/test/ssl/cert/server.crt");
Now the server can start SSL connection. You can test it with a browser. Typically browser will raise alarm that the connection is not trusted. That is because the certificate is self signed and it cannot protect from "man in the middle" attack. However, you can ask your browser to continue with that connection. So, on the server side you will have the HTTP GET header on the signalreadyRead().
Try to connect with the Qt client to that server. Now the error is raised by the client:
sslErrorOccured: ("The certificate is self-signed, and untrusted")
The server says in error(): "The remote host closed the connection". The client raised the SSL certificate error, but as with browsers we can continue with that connection. Put socket->ignoreSslErrors() in the sslErrors() signal handler:
void Client::sslErrorOccured(const QList<QSslError> & error) {
qDebug() << "sslErrorOccured:" << error;
socket->ignoreSslErrors(error);
}
That's it. Of course, your client should not accept all SSL certificate errors from all servers, since such errors mean that the connection is not really secure and can be hacked. It is just for testing. The object QSslError contains the certificate data, so it possible on your client side to accept only one specific self-signed certificate from your server and ignore all other such errors.
It is also possible to create your own 'authority root certificate' that you can manually write to your system. Then that certificate can be used for signing your server certificate. Your client will think that it is trusted connection, since it will be able to validate it by system root certificates.
Note that you can also have some issue with OpenSSL library. On Linux or OS X OpenSSL is in default setup, however for Windows it should be installed manually. Some compilation of OpenSSL may be already present in Windows system PATH, for example CMake has some limited OpenSSL library. However in general for Windows you should deploy OpenSSL together with your application.

xampp/wamp based Apache server custom reply

How can I send a custom response upon a custom request on a xampp/wamp based Apache server upon a connection to a specific port?
I'm trying to reply to the \0 a flash app is requesting in order to allow a crossdomain http GET request.
The flash policy request, is made to port 843 by default and i'd like to keep it that way.
The port should get a \0 (ending with a null char,\0 is just for the reference) and replying with something like:
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<site-control permitted-cross-domain-policies="master-only"/>
<allow-http-request-headers-from domain="*" headers="*" secure="true" />
<allow-access-from domain="*" to-ports="*" />
</cross-domain-policy>
As far as i know, the request should be return as a plain text, although Content-type, might be needed as well.
I've tried using the following: http://socketpolicyserver.com/ and although it listens to the port and accepts connections, it doesn't reply with the specified xml upon request.
Any methods / ways of achieving a proper reply will be appreciated,
with regards,
Mike.
!---UPDATE--->
I wrote a simple C# web server which listens to port 843, and serves the aforementioned policy - it worked out just fine, however, when using a SecureSocket connection for a secure connection (i.e opening a socket to a HTTPS/SSL protocol) - the request that is sent is encrypted using the hosts certificate. As far as i know, there's no way of listening or acquiring the servers certificate and decrypting the data via an external app hence, the only way is to somehow 'teach' Apache to respond with the crossdomain policy after a proper request is sent via an appropriate port.
Another idea i have is to read the server's certificate file stored in the Apache directory regardless of what happens on the server itself, though imo it's an overkill.
Would love to hear your comments,
Mike.
So here's how i eventually solved it:
I've used this guys code with some modifications: http://www.switchonthecode.com/tutorials/csharp-tutorial-simple-threaded-tcp-server
and created a simple multithreaded web server that listens to port 843, and provides a somewhat general policy upon the appropriate flash request.
There were several examples provided by Adobe, but for some reason, windows didn't like those.
Also note that if you're using the SecureSocket object of flash it should allegedly use the target servers (IIS'/Apaches'/Tomcats' etc..) SSL credentials and will initiate a client Authentication using the public key of the target servers certificate, then again, it might not so this code doesn't have SSL support, although i've started implementing one using C#'s SSL Streams, so far without any luck. If you can make it work via SSL, please let me know.
Hope this code will help,
Mike.
using System;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.IO;
namespace TCPSexyServer
{
class Server
{
private TcpListener tcpListener;
private Thread listenThread;
private void ListenForClients(int p)
{
throw new NotImplementedException();
}
public Server()
{
this.tcpListener = new TcpListener(IPAddress.Any, 843);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
private void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
while (true)
{
bytesRead = 0;
try
{
//blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
//a socket error has occured
break;
}
if (bytesRead == 0)
{
//the client has disconnected from the server
break;
}
//message has successfully been received
UTF8Encoding encoder = new UTF8Encoding();
string sentData = encoder.GetString(message, 0, bytesRead);
Console.WriteLine(sentData);
if (sentData == "<policy-file-request/>\0")
{
String policy = "<?xml version=\"1.0\"?>\n" +
"<!DOCTYPE cross-domain-policy SYSTEM \"/xml/dtds/cross-domain-policy.dtd\">\n" +
"<cross-domain-policy>\n" +
"<site-control permitted-cross-domain-policies=\"master-only\"/>\n" +
"<allow-http-request-headers-from domain=\"*\" headers=\"*\" secure=\"true\" />\n" +
"<allow-access-from domain=\"*\" to-ports=\"*\" />\n" +
"</cross-domain-policy>\0";
byte[] buffer = encoder.GetBytes(policy);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
Console.WriteLine(policy);
}
else
{
tcpClient.Close();
}
System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead));
}
tcpClient.Close();
}
public static void Main(string[] args)
{
Server blah = new Server();
}
}
}

Resources