Monthly Archives: October 2010

How to dial remote SSL/TLS services in Go

Go has wonderful support for server side TLS, but the client side takes a little bit of massaging to generate a correct Config struct. Check out this thread from Hans Stimer for more details on handling TLS on the server side.

package main

import (
	"crypto/tls"
	"io/ioutil"
	"net"
	"os"
	"time"
)

func loadRootCA(file string) (*tls.CASet, os.Error) {
	pemBytes, err := ioutil.ReadFile(file)
	if err != nil {
		return nil, err
	}

	caset := tls.NewCASet()
	if caset.SetFromPEM(pemBytes) {
		return caset, nil
	}
	return nil, os.NewError("Unable to decode root CA set")
}

func newClientConfig(rootCAPath string) (*tls.Config, os.Error) {
	rootca, err := loadRootCA(rootCAPath)
	if err != nil {
		return nil, err
	}

	urandom, err := os.Open("/dev/urandom", os.O_RDONLY, 0)
	if err != nil {
		return nil, err
	}

	return &tls.Config{
		Rand:    urandom,
		Time:    time.Seconds,
		RootCAs: rootca,
	}, nil
}

func dialTLS(raddr *net.TCPAddr) (c *tls.Conn, err os.Error) {
	config, err := newClientConfig("ca-certificates.crt")
	if err != nil {
		return nil, err
	}

	conn, err := net.DialTCP("tcp", nil, raddr)
	if err != nil {
		return nil, err
	}

	c = tls.Client(conn, config)
	err = c.Handshake()
	if err == nil {
		return c, nil
	}
	c.Close()
	return nil, err
}