I use the built-in standard SSL socket client library (net + crypto/tls) like this:
conn, err := net.Dial("tcp", "exploit.im:5222")
//...
config := tls.Config{InsecureSkipVerify: true}
tls_conn := tls.Client(conn, &config)
fmt.Println(tls_conn.Handshake())
And am getting the message:
conn, err := net.Dial("tcp", "exploit.im:5222")
I managed to find out it is somehow related to the default maximum packet size (16384 + 2048 set in common.go:31). Is there any standard work around (without patching this value & rebuilding the lib)?
You get this kind of messages if you try to do a SSL handshake with a peer which does not reply with SSL. In this case it is probably some XMPP server and with XMPP you first have some clear text handshake before you start with SSL. Trying to start directly with SSL will result in interpreting the servers clear text response as an SSL frame which can result in strange error messages like this.
Related
I changed BIO to a non-blocking mode with
BIO_set_nbio(m_bio, 1)
for BIO_do_connect to not hang (and using BIO_should_retry and select to retry to reconnect). It solved my problem with connection to the wrong listener now fails immediately instead of timing out in 2 hours.
But now I have a new problem - SSL_get_verify_result always returns X509_V_OK. Doesn't matter if it is expired cert or just not the same as server cert - validation always succeeds.
What I don't understand is how and why non-blocking mode changes validation for a cert. I confirmed that without switching to a non-blocking mode validation fails for if the client cert not the same.
I tried to set client cert with both SSL_CTX_load_verify_locations and SSL_CTX_use_certificate_file and it doesn't seem to matter.
As Patrick pointed out the issue I had was due to SSL context in non-blocking mode didn't have server cert so verification immediately after establishing a connection always succeeded. To fix the issue I added cert validation (if it is the same I expect to see) after first read-write data exchange.
SSL_CTX_new(SSLv23_client_method());
SSL_CTX_load_verify_locations(ctx, certFilePath, NULL);
BIO_new_ssl_connect(ctx);
BIO_get_ssl(bio, &ssl);
BIO_set_conn_hostname(bio, hostname);
BIO_set_nbio(bio, 1);
auto err = BIO_do_connect(bio);
// check err and BIO_should_retry to retry as needed
// Problem I had was here - the call always returns X509_V_OK
// in non-blocking mode regardless of what cert I use on
// my (client) side.
// In IO blocking mode (without BIO_set_nbio call above) validation
// fails as expected for mismatching certs.
SSL_get_verify_result(ssl);
// Exchange some data with server with
// BIO_read/BIO_write
// And now we have server cert in ctx
auto clientCert = SSL_get_certificate(ssl);
auto serverCert = SSL_get_peer_certificate(ssl);
auto certsAreTheSame = X509_cmp(clientCert, serverCert) == 0;
I got this error:
SSL: hello: ssl_handshake.erl:171:Fatal error: internal error - server_has_no_suitable_certificates
when supplying a der-decocded certificate for the callback function in the {sni_fun, CallbackFun} option. The CallbackFun returns [{cacerts, [Cert]}], where Cert is der-encoded. So things comply with Erlang ssl module's documentation.
I tried look into the otp source code. It seems that whatever the callback returns is ignored, thus causing this function clause to be evaluated:
certificate_chain(undefined, _, _) ->
{error, no_cert};
which leads to that error! But I could be wrong as I kind of lost in browsing the code base...
If it helps, I use a self-signed CA to sign CSRs that are generated as a SNI is found during a TLS handshake (via sni_fun option).
please advise! thanks a lot!
Update:
I tried Erlang OTP 20.3 release and get another error:
TLS server: In state hello at tls_connection.erl:739 generated SERVER ALERT: Fatal - Handshake Failure - malformed_handshake_data
Looking at OTP source code, it is result of an exception from this block:
try
Version = ssl_handshake:select_version(tls_record, ClientVersion, Versions),
case ssl_cipher:is_fallback(CipherSuites) of
true ->
Highest = tls_record:highest_protocol_version(Versions),
case tls_record:is_higher(Highest, Version) of
true ->
?ALERT_REC(?FATAL, ?INAPPROPRIATE_FALLBACK);
false ->
handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
end;
false ->
handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
end
catch
_:_ ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, malformed_handshake_data)
end.
I am sure the cert is fine, I could view it as well as convert it between DER/PEM formats with openssl with no error. Is there a way to reveal what kind of exception it is in this case?
I solved the problem: the sni_fun must return the list of
[{cert, DerdecodedCert}, {keyfile, PathToTheCsrKeyFile}]
I was returning only
[{cert, DerdecodedCert}]
(which was so instructed by Erlang ssl doc)
Hope this helps anyone who bumps into similar problem as I did!
I'm using Go to perform HTTPS requests with a custom root CA. The root CA is the only certificate I have on my side.
My code looks like this:
// performRequest sets up the HTTPS Client we'll use for communication and handle the actual requesting to the external
// end point. It is used by the auth and collect adapters who set their response data up first.
func performRequest(rawData []byte, soapHeader string) (*http.Response, error) {
conf := config.GetConfig()
// Set up the certificate handler and the HTTP client.
certPool := x509.NewCertPool()
certPool.AppendCertsFromPEM(certificate)
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: certPool,
InsecureSkipVerify: false,
},
},
}
req, err := http.NewRequest(http.MethodPost, baseURL, bytes.NewBuffer(rawData))
if err != nil {
return nil, err
}
// Sets the SOAPAction and Content-Type headers to the request.
req.Header.Set("SOAPAction", soapHeader)
req.Header.Set("Content-Type", "text/xml; charset=UTF-8")
// Send request as our custom client, return response
return client.Do(req)
}
The error I get back is this:
2017/12/09 21:06:13 Post https://secure.site: x509: certificate is not valid for any names, but wanted to match secure.site
I've been unable to find out exactly what the cause is of this. When checking the SANs of the CA cert, I don't have secure.site in there (no names at all, as the error states), but I can't see how I've done this wrong.
What should I do to troubleshoot this?
You need to do two things:
add the CA certificate on the server side as well, the CA needs to be known by all parties.
generate and use a server certificate (with the hostname in the certificate) on the server. The server cert needs to be signed by the CA.
You can find an example of this at here (first google example)
Edit: to clarify, the error is due to the fact that you are trying to connect securely to a remote host. By default, the go client will look for a valid certificate returned by the server.
Valid means (among other things):
it is signed by a known CA
it contains the ip/dns of the server (the one you passed to http.NewRequest) in the CommonName or Subject Alternative Name: DNS/IP fields.
final edit:
The server certificate contained the correct Common Name set to the server hostname, but it also contained a Subject Alternative Name set to an email address.
As mentioned in https://groups.google.com/a/chromium.org/forum/#!topic/security-dev/IGT2fLJrAeo, Go now ignores the Common Name if is a SAN is found.
I am writing a TCP text protocol for a project that I am working on. One of the commands in the protocol is STARTTLS which should upgrade the connection to TLS and continue on. My code to upgrade the connection is similar to the answer in this question. The problem I am having is when I am upgrading the TLS connection, the tlsConn.Handshake will hang and never let go. There are some code samples below. Any help is greatly appreciated.
After the STARTTLS command is received...
// Init a new TLS connection. I need a *tls.Conn type
// so that I can do the Handshake()
s.Logf("++> Upgrading connection to TLS")
tlsConn := tls.Server(s.Conn, s.Server.TLSConfig)
s.Logf("++> Attempting TLS Handshake")
tlsConn.Handshake()
s.Logf("++> TLS Handshake Successful")
// Here is the trick. Since I do not need to access
// any of the TLS functions anymore,
// I can convert tlsConn back in to a net.Conn type
s.Conn = net.Conn(tlsConn)
s.Logf("++> Updating read/write buffers")
s.reader = textproto.NewReader(bufio.NewReader(s.Conn))
s.writer = textproto.NewWriter(bufio.NewWriter(s.Conn))
s.Printf("100 SUCCESS")
The client is currently upgrading the connection right after it sends the STARTTLS command like this...
c.conn = tls.Client(c.conn, clientTLSConfig)
The server *tls.Config looks like this...
// Load the key and certificate - paths are provided in flags.
cert, err := tls.LoadX509KeyPair(flagTLSCert, flagTLSKey)
if err != nil {
log.Fatal(err)
}
// Create the TLS config
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
ClientAuth: tls.VerifyClientCertIfGiven,
ServerName: fqdn(),
}
The client *tls.Config looks like this...
clientTLSConfig := &tls.Config{
InsecureSkipVerify: true,
}
Do you call c.conn.Handshake() or do something else to initiate the TLS handshake on the client side?
If the client does not initiate the handshake by sending TLS Client Hello, the server will sit forever waiting for it.
This is my best guess as you did not provide much of the client side code. Also checking with tcpdump would help to narrow the problem down (to server or client side).
Need your help with this
package main
import (
"log"
"net/http"
)
func main() {
client := &http.Client{}
_, err := client.Get("https://www.marathonbet.com/en/")
if err != nil {
log.Fatalf("%s\n", err)
}
}
This always return:Get https://www.marathonbet.com/en/: net/http: TLS handshake timeout exit status 1
I`m try:
it
and use this lib
and do it
But nothing works for me..
So, please help me.
Update:
In Python 2.7 with requests this works:
s = Session()
r = s.get('https://www.marathonbet.com/en/, verify=False)
But i need do it with go(
UPD:
Fixed: Just replase https://www.marathonbet.com/en/ to https://87.117.250.213/en/ and adding skip verify.
thx all for help.
Here's a more detailed explanation of what's happening. When you call a domain, your HTTP client calls a DNS server. The DNS server responds with the IP of the target server. At this point everything's OK.
If it's an HTTPS connection, then it starts the TLS handshake. Here's how it works.
And this the point where you experienced the issue. The request was sent but the server didn't answer correctly (or at all). It may be caused by many factors like the server:
isn't accessible
needs more time to respond
can be hidden behind some firewall/proxy that refuses the connection
block all requests from your IP/location
etc
By providing the skip verify option and providing the explicit IP address, you skips everything I described above. It means:
if the server's IP changes your code will stop working
if someone perform a man-in-the-middle attach you won't find out about it.
It's hard to find out what's the root cause without a more deep investigation. If you want to find out what's happening, use the httptrace as #Flowchartsman suggested