gSOAP SSL - converting existing code to ssl - c++

The earlier Version of this question got no Response, so I'm updating the entire Thing:
I have a test gSOAP Client and server on my machine. The client does an MTOM upload of various files to the server.
When attempting to convert the code to ssl I get the following error:
The server reports:
"SSL_ERROR_SSL
error:1408A0C1:SSL routines:ssl3_get_client_hello:no shared cipher"
The client reports:
An SSL error occured
SOAP 1.2 fault SOAP-ENV:Receiver [no subcode]
"SSL_ERROR_SSL
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure"
Detail: SSL_connect error in tcp_connect()
it runs without the "SSL" option. Can someone advise me as to what I'm doing wrong?
Applicable client code -
if(fSSL)
soap_ssl_init();
. . .
soap_init1(&my_soap, SOAP_ENC_MTOM); /* Enable MTOM */
. . .
if(fSSL)
{
if (soap_ssl_client_context(&my_soap,
SOAP_SSL_NO_AUTHENTICATION + SOAP_TLSv1_2,
NULL, // client keyfile
NULL, // passphrase for keyfile
NULL, // certified authority certificate
NULL, // directory for trusted certificates
NULL))// random data for seed
{
soap_print_fault(&my_soap, stderr);
...
}
}
...
long gsoap_status = soap_call___ns1__upload(&my_soap, endpoint.c_str(), NULL, &upload_parms, &upload_response);
Applicable server code -
if(fSSL)
soap_ssl_init();
. . .
soap_init1(&my_soap, SOAP_ENC_MTOM); /* Enable MTOM */
. . .
if(fSSL)
{
if (soap_ssl_server_context(&my_soap,
SOAP_SSL_NO_AUTHENTICATION + SOAP_TLSv1_2, // per EMAIL - option 1
NULL, // Keyfile - required for authentication
NULL, // passphrase
NULL, // password to read Keyfile
NULL, // optional cacert file
NULL, // DH Filename or DH key len bits
NULL, // Randfile
NULL)) // optional server identification (enable SSL session cache)
{
soap_print_fault(&my_soap, stderr);
exit(0);
}
}
. . .
my_soap.connect_timeout = 20;
my_soap.send_timeout = 60;
my_soap.recv_timeout = 60;
if(!soap_valid_socket(soap_bind(&my_soap, NULL, port, 100)))
{
soap_print_fault(&my_soap, stderr);
exit(1);
}
fprintf(stderr, "Bind to port %d successful\n", port);
// server loop starts
for (;;)
printf("server loop sta\n");
int t_socket = soap_accept(&my_soap);
struct soap* t_soap = 0;
t_soap = soap_copy(&my_soap);
if(fSSL)
{
if(soap_ssl_accept(&my_soap)) <------ FAILS HERE
{
printf("NOT Accepting (ssl) socket=%d connection from IP: %d.%d.%d.%d ...", t_socket,
(int)my_soap.ip>>24&0xFF,
(int)my_soap.ip>>16&0xFF,
(int)my_soap.ip>>8&0xFF,
(int)my_soap.ip&0xFF);
soap_print_fault(&my_soap, stderr);
soap_destroy(&my_soap);
soap_end(&my_soap);
continue;
}
}
. . .
if(soap_serve(&my_soap))
...
Server Console output:
Bind to port 8080 successful
server loop sta
NOT Accepting (ssl) socket=364 connection from IP: 127.0.0.1 ...Error 30 fault is internal [no subcode]
"SSL_ERROR_SSL
error:1408A0C1:SSL routines:ssl3_get_client_hello:no shared cipher"
Detail: SSL_accept() failed in soap_ssl_accept()

I'm working on this now. I think the errors that you are seeing are because most/all distributions of openSSL do not support anonymous authentication any longer due to man in the middle attacks. A self-signed certificate on the server-side may be the only way to make these examples work.

Related

Golang Paho MQTT over Websocket

Hey I was trying to connect to AWS IoT Core via Golang Paho MQTT client. I tried the normal MQTT connection which was working without problems. Next I wanted to try the connection via MQTT over Websocket but could not find anything relating that in the Paho.Mqtt docs. How do I make the Websocket connection? I could post my code from my normal MQTT connection if necessary.
Edit, here is my code:
package main
import (
"crypto/tls"
"fmt"
"time"
MQTT "github.com/eclipse/paho.mqtt.golang"
)
type Message struct {
message string
}
/*var f MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
fmt.Printf("TOPIC: %s\n", msg.Topic())
fmt.Printf("MSG: %s\n", msg.Payload())
}*/
func main() {
cer, err := tls.LoadX509KeyPair("cd5a04e9fd9a094326c9ee0cdc1e1f7b2e3510a9e106968683d333a2a4344ca7-certificate.pem.crt",
"./cd5a04e9fd9a094326c9ee0cdc1e1f7b2e3510a9e106968683d333a2a4344ca7-private.pem.key")
check(err)
cid := "ClientID"
// AutoReconnect option is true by default
// CleanSession option is true by default
// KeepAlive option is 30 seconds by default
connOpts := MQTT.NewClientOptions() // This line is different, we use the constructor function instead of creating the instance ourselves.
connOpts.SetClientID(cid)
connOpts.SetMaxReconnectInterval(1 * time.Second)
connOpts.SetTLSConfig(&tls.Config{Certificates: []tls.Certificate{cer}})
host := "a2to6mbspmaw82-ats.iot.eu-west-1.amazonaws.com"
port := 443
brokerURL := fmt.Sprintf("wss://%s:%d", host, port)
connOpts.AddBroker(brokerURL)
mqttClient := MQTT.NewClient(connOpts)
if token := mqttClient.Connect(); token.Wait() && token.Error() != nil {
panic(token.Error())
}
var message = "message from lap"
for message != "bye" {
token := mqttClient.Publish("some_topic", 0, false, message)
token.Wait()
message = "bye"
}
}
func check(err error) {
if err != nil {
panic(err)
}
}
From the Eclipse Paho GoLang page
The type of connection required is specified by the scheme of the
connection URL set in the ClientOptions struct, for example:
tcp://mqtt.eclipseprojects.io:1883 - connect to mqtt.eclipseprojects.io on port 1883 using plain TCP
ws://mqtt.eclipseprojects.io:1883 - connect to mqtt.eclipseprojects.io on port 1883 using WebSockets
tls://mqtt.eclipseprojects.io:8883 - connect to mqtt.eclipseprojects.io on port 8883 using TLS (ssl:// and tcps:// are
synonyms for tls://)
The second entry in the list suggests you just pas in the URL with the right schema ( ws:// or probably wss://)

Client authentication (certificat + private key) using WinHttp

I'm trying to communicate in https with a server using the Win32 API.
Here is a very minimalist code :
HINTERNET ses = WinHttpOpen(L"test",WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,WINHTTP_NO_PROXY_NAME,WINHTTP_NO_PROXY_BYPASS,0 ) ;
HINTERNET con = WinHttpConnect(ses,L"stackoverflow.com",INTERNET_DEFAULT_HTTPS_PORT,0 ) ;
HINTERNET req = WinHttpOpenRequest(con,L"GET",NULL,NULL,WINHTTP_NO_REFERER,WINHTTP_DEFAULT_ACCEPT_TYPES,WINHTTP_FLAG_SECURE ) ;
WinHttpSendRequest( req,WINHTTP_NO_ADDITIONAL_HEADERS,0,WINHTTP_NO_REQUEST_DATA,0,0,0 ) ;
WinHttpReceiveResponse( req,NULL ) ;
char buffer [10000] ;
unsigned long size ;
WinHttpReadData( req,reinterpret_cast<void*>( buffer ),sizeof( buffer )-1,&size ) ;
buffer[size] = 0 ;
cout << buffer << endl ;
As long as I communicate with a "classic" https server like stackoverflow.com everything goes well.
The problem is when I try to communicate with a server that requests an authentication of the client.
I have 3 .pem files : a certificate and a private key for my client, and a root certificate that authenticates my client certificate (i.e. a certificate chain of length 2).
For information, I can connect my server using this cULR command line :
curl https://my.server --cert Client_cert.pem --key Client_key.pem --cacert Root_cert.pem
So I kown it's possible!
Reading the win32 API documentation, I figured out that the key is to call
WinHttpSetOption but it's not clear between the options WINHTTP_OPTION_CLIENT_CERT_CONTEXT and WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST...
And I did not find out how to pass my data (cert+key files).
Any wise advice ?
Thanks in advance !

Secured SSL connection Error: unknown protocol | bad hostname lookup

Iam downloading RSS feed file (eg. https://tools.ietf.org/dailydose/dailydose_atom.xml) from server via HTTP.
First, i have to connect to the remote server via OpenSSL, as described here.
Unsecured version works just fine and i can connect and receive HTTP answer with feeds:
bio = BIO_new_connect("www.tools.ietf.org:80");
if(bio == NULL)
{
/* Handle the failure */
}
if(BIO_do_connect(bio) <= 0)
{
/* Handle failed connection */
}
Secured version:
BIO * m_bio;
SSL_CTX * m_ctx;
SSL * m_ssl;
SSL_library_init();
m_ctx = SSL_CTX_new(SSLv23_client_method());
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
SSL_CTX_set_default_verify_paths(m_ctx);
m_bio = BIO_new_ssl_connect(m_ctx);
BIO_get_ssl(m_bio, &m_ssl);
SSL_set_mode(m_ssl, SSL_MODE_AUTO_RETRY);
BIO_set_conn_hostname(m_bio, "www.tools.ietf.org:80");
if (BIO_do_connect(m_bio) <= 0)
{
printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));
throw std::runtime_error("FEEDREADER: Connection failed.");
}
if(SSL_get_verify_result(m_ssl) != X509_V_OK)
{
throw std::runtime_error("FEEDREADER: Verification failed.");
}
Where do_connect fails with following error:
Error: unknown protocol
when i replace www.tools.ietf.org with http(s)://www.tools.ietf.org
another error appears:
Error: bad hostname lookup
But hostname & dns works well for unsecured version, so may somebody help me with this one ?
80 is the default HTTP port. 443 is the default HTTPS port.
bio = BIO_new_connect("www.tools.ietf.org:443");
BIO_set_conn_hostname(m_bio, "www.tools.ietf.org:443");

Using CURLOPT_CONNECT_TO with an IPv6 address

I am attempting to use curl's CURLOPT_CONNECT_TO option to connect to a specific address (rather than the result of the DNS lookup of the host part of the url):
CURL * r_curl = NULL;
struct curl_slist * r_connect = NULL;
char connectStr[128];
if (af == AF_INET) {
sprintf(connectStr, "::%s:", ipAddrString);
} else if (af == AF_INET6) {
/* in [] per https://curl.haxx.se/libcurl/c/CURLOPT_CONNECT_TO.html */
sprintf(connectStr, "::[%s]:", ipAddrString);
}
fprintf(stderr, "DEBUG: connect '%s', url %s\n", connectStr, url);
r_curl = curl_easy_init();
...
r_connect = curl_slist_append(r_connect, connectStr);
curl_easy_setopt(r_curl, CURLOPT_CONNECT_TO, r_connect);
curl_easy_setopt(r_curl, CURLOPT_URL, url);
curl_easy_perform(r_curl);
When af is AF_INET and ipAddrSring is an IPv4 address this works perfectly. When af is AF_INET6 and ipAddrSring is an IPv6 address, curl looks like it is trying to do a DNS host lookup on the IPv6 address:
DEBUG: connect '::129.186.23.166:', url http://www.iastate.edu/
* Connecting to hostname: 129.186.23.166
* Trying 129.186.23.166...
* TCP_NODELAY set
* Connected to 129.186.23.166 (129.186.23.166) port 80 (#0)
vs
DEBUG: connect '::[2610:130:101:104::2]:', url http://www.iastate.edu/
* Connecting to hostname: 2610:130:101:104::2
* Could not resolve host: 2610:130:101:104::2
What I am doing wrong here?
(Curl is version 7.56.1)
There was a bug in libcurl (before 7.58.0) which made it take IPv6 addresses and attempt to use them for CURLOPT_CONNECT_TO, even if it was built without support for IPv6!
This was addressed in curl 7.58.0 and from then on it makes libcurl return an error if this is attempted!
Answer: Curl Library was built w/o IPv6 support.
I'm thinking that maybe that should result in a more meaningful error message.

InternetConnect fails to connect to FTP server via ftp proxy

I am trying to connect to FTP server using WinGate FTP Proxy. The InternetOpen() executes successfully returning appropriate handle in all cases.
In case Proxy Authentication is OFF, InternetConnect() returns proper handle and I can proceed with further ftp operations but in case Proxy Authentication is ON, InternetConnect() returns NULL.
On MSDN they have mentioned for proxies use InternetSetOption() with INTERNET_OPTION_PROXY_USERNAME and INTERNET_OPTION_PROXY_PASSWORD flags to set proxy username and password on handle returned by InternetConnect, but it's returning NULL and on printing GetLastError(), I get the following message:
InternetConnect failed: 12014
220 WinGate Engine FTP Gateway ready
331 send password
530 Auth Failed
if ((hHandle=InternetOpen("Upload", INTERNET_OPEN_TYPE_PROXY, "ftp=ftp://<servername>:<port>", NULL, 0)) == NULL)
{
printf("InternetOpen failed: %d", GetLastError());
printInternetErrorMsg(function);
return false;
}
char buffer[1024];
string proxy_username,proxy_password;
// get ftp proxy username and password
// ..
if ((m_itConnect=InternetConnect(hHandle, ftpserver, INTERNET_DEFAULT_FTP_PORT, ftpusrname, ftppasswd, INTERNET_SERVICE_FTP, NULL, NULL)) == NULL){
printf("InternetConnect failed: %d", GetLastError());
printInternetErrorMsg(function);
//Internet Connect Fails with following error when Proxy Authentication is ON
//InternetConnect failed: 12014
//220 WinGate Engine FTP Gateway ready
//331 send password
//530 Auth Failed
return false;
}
strcpy(buffer,proxy_username.c_str());
if ( !InternetSetOption (m_itConnect, INTERNET_OPTION_PROXY_USERNAME, (LPVOID) buffer, lstrlen (buffer) ))
{
printf("Unable to set proxy authetication settings (username). Error returned: %d", GetLastError() );
return false;
}
strcpy(buffer, proxy_password.c_str());
if ( !InternetSetOption (m_itConnect, INTERNET_OPTION_PROXY_PASSWORD, (LPVOID) buffer, lstrlen (buffer) ))
{
printf("Unable to set proxy authetication settings (password). Error returned: %d", GetLastError() );
return false;
}
}
printf("InternetConnect successful ...");
return true;
Any help is appreciated.
Thanks in Advance.
the problem is you are connecting to an FTP proxy, rather than an HTTP proxy. So you're getting an FTP welcome string back.
When working through a proxy using WinInet, FTP is done over HTTP. The client makes an HTTP request to the HTTP proxy for an FTP URL. the HTTP proxy acts as an FTP client to the FTP server, and translates the response back to HTTP for the client. Strange but true.
So you need to change the proxy port to be the HTTP proxy in WinGate.