Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upgrade a connection to TLS in Go

Tags:

ssl

go

I have an open TCP connection and read from it with a for loop like so

for {
  // tx.Text is of type textproto.Conn
  // the underlying connection is stored in tx.Conn
  l, err := tx.Text.Reader.ReadLine()

  // do stuff with the text line ...
}

Now I want to upgrade the connection to TLS like this (TlsConf contains a certificate loaded with tls.LoadX509KeyPair)

tx.Conn = tls.Server(tx.Conn, tx.Server.Conf.TlsConf)
tx.Text = textproto.NewConn(tx.Conn)

When I do this I get a segmentation fault on the client when the server attempts a handshake. I'm implementing a SMTP server and am testing it with swaks using the -tls flag. The terminal output of swaks is the following

-> STARTTLS
<-  220 Start TLS
Segmentation fault: 11

Since swaks is a tested tool, and worked with the nodeJS SMTP implementation I had before, I don't suspect the error is on the client side.

What did I do wrong or what is missing?

PS: When a TLS connection is started from an existing insecure connection, what does exactly happen? Does the client establish a new connection on a different port or is the connection reused?

like image 808
Era Avatar asked Oct 28 '12 16:10

Era


1 Answers

Here's how to upgrade a net.conn to tls.con:

1) Somewhere in your code, you have these variables defined

var TLSconfig *tls.Config
...
// conn is a normal connection of type net.Conn
conn, err := listener.Accept()
...

2) Initialize TLSConfig somewhere above, do something like this

cert, err := tls.LoadX509KeyPair("/path/to/cert", "/path/to/key")
if err != nil {
    // ...
}
TLSconfig = &tls.Config{
Certificates: []tls.Certificate{cert}, 
ClientAuth: tls.VerifyClientCertIfGiven, 
ServerName: "example.com"}

3) At this point you are reading/writing to a standard connection.

When the client issues STARTTLS command, do this in your server:

// Init a new TLS connection. I need a *tls.Conn type 
// so that I can do the Handshake()
var tlsConn *tls.Conn
tlsConn = tls.Server(client.socket, TLSconfig)
// run a handshake
tlsConn.Handshake()
// 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
conn = net.Conn(tlsConn)

Next, you may probably update your buffers with the new connection, etc.

Test your server like this:

openssl s_client -starttls smtp -crlf -connect  example.com:25

This allows you to interact with the server through the tls connection and you can issue some commands, etc.

More about conversions in Go

I guess conversions are another reason for what makes Go so powerful!

http://golang.org/ref/spec#Conversions

http://golang.org/doc/effective_go.html#conversions

like image 172
Allen Hamilton Avatar answered Oct 15 '22 08:10

Allen Hamilton