i tried it some ours now but i could not get it to work. I want to push some notifications from a Qt Application. Tried to get it to work on macOS Sierra with Qt 5.8 installation and on Pi3 also with Qt 5.8.
I created my push certificate with "fastlane pem" and i tested it with "Pusher" and it works correct. But i cannot get it to work in Qt....
At first is the code i use to initialize and connect the QSslSocket:
QSslSocket * ssl = new QSslSocket;
connect(ssl, &QSslSocket::encrypted, this, &IOSPusher::encrypted );
connect(ssl, static_cast<void(QSslSocket::*)(const QList<QSslError> &)>(&QSslSocket::sslErrors),this,&IOSPusher::sslErrors);
connect(ssl, static_cast<void(QSslSocket::*)(QAbstractSocket::SocketError)>(&QSslSocket::error),this, &IOSPusher::error );
connect(ssl,&QSslSocket::stateChanged,this,&IOSPusher::stateChanged );
Loading the certificate
QString path = QStandardPaths::writableLocation(certificateLocation) + "/apns.pem";
const auto certs = QSslCertificate::fromPath(path);
if(certs.count() > 0){
qDebug() << "IOSPusher: Certificate loaded successfully";
}else{
qDebug() << "Could not load certificate : " + path;
}
QSslConfiguration config = QSslConfiguration::defaultConfiguration();
config.setCaCertificates(certs);
ssl->setSslConfiguration(config);
ssl->connectToHostEncrypted( gateway.sandbox.push.apple.com,2195 );
And thats the output i get:
IOSPusher: Certificate loaded successfully
IOSPusher::stateChanged QAbstractSocket::HostLookupState
IOSPusher::stateChanged QAbstractSocket::ConnectingState
IOSPusher::stateChanged QAbstractSocket::ConnectedState
IOSPusher::error QAbstractSocket::SocketError(13)
IOSPusher::stateChanged QAbstractSocket::ClosingState
IOSPusher::stateChanged QAbstractSocket::UnconnectedState
So according to the Qt documentation the error:
QAbstractSocket::SocketError(13)
means the following:
SslHandshakeFailedError
And
> the SSL/TLS handshake failed and the encrypted channel could not be established. The sslErrors() signal should have been emitted.
But the sslErrors()
signal will not be emitted in my case....
The SSL/TLS handshake failed, so the connection was closed (only used in QSslSocket)
Any ideas or samples how i can establish a encrypted connection to apple?
Thanks in advance!
Okay like so often when i try to get help from anyone i got it now :D
The solution which worked for me now is:
Create the *.pem
cert with fastlane pem
with a password (maybe it works without password too but that was the last i tried now and....never change a running system haha)
fastlane pem --development -p <private_key_password> -a <your_app_identifier>
Then to connect with the QSslSocket do the following... as before in my question...
QSslSocket * ssl = new QSslSocket;
QString path = QStandardPaths::writableLocation(certificateLocation) + "/apns.pem";
connect(ssl, &QSslSocket::encrypted, this, &IOSPusher::encrypted );
connect(ssl, static_cast<void(QSslSocket::*)(const QList<QSslError> &)>(&QSslSocket::sslErrors),this,&IOSPusher::sslErrors);
connect(ssl, static_cast<void(QSslSocket::*)(QAbstractSocket::SocketError)>(&QSslSocket::error),this, &IOSPusher::error );
connect(ssl,&QSslSocket::stateChanged,this,&IOSPusher::stateChanged );
QSslCertificate cert;
const auto certs = QSslCertificate::fromPath(path);
if(certs.count() > 0){
cert = certs.at(0);
qDebug() << "IOSPusher: Certificate loaded successfully";
}else{
qDebug() << "Could not load certificate : " + path;
return false;
}
Now here comes the magic what it did for me
Use the private_key (.pkey) file which will also be created with fastlane pem
//Use the path to the .pkey file from fastlane
QFile keyfile(path + "/apns.pkey");
keyfile.open(QFile::ReadOnly);
//Create the QSslKey as private key
QSslKey privateKey(&keyfile,QSsl::Rsa,QSsl::Pem,QSsl::PrivateKey,QByteArray("<private_key_password_from_fastlane>"));
//Close the file
keyfile.close();
And add the private key and the certificate to the ssl config
QSslConfiguration config = QSslConfiguration::defaultConfiguration();
config.setLocalCertificate(cert);
config.setPrivateKey(privateKey);
as you can see here this time i not use the config.setCaCertificates
method but instead the config.setLocalCertificate
method. That was a mistake on my side...
At least add the config to the ssl socket and FIRE!
ssl->setSslConfiguration(config);
ssl->connectToHostEncrypted( "gateway.sandbox.push.apple.com",2195 );
Thats all
Now the encrypted()
signal gets emitted! Yeah..