paulgorman.org/technical

A Simple Go (golang) TLS Client and Server

(April 2017)

If our server has a cert already, use it. Otherwise, for testing, generate a private key and public cert:

$ openssl genpkey -algorithm RSA -out ~/tmp/test.key -pkeyopt rsa_keygen_bits:4096
$ openssl req -new -x509 -sha256 -key ~/tmp/test.key -out ~/tmp/test.crt -days 3650

A very simple HTTPS server:

package main

import (
	"net/http"
	"log"
)

func TestServer(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte("Serving TLS!\n"))
}

func main() {
	http.HandleFunc("/", TestServer)
	err := http.ListenAndServeTLS(":4430", "/home/paulgorman/tmp/test.crt", "/home/paulgorman/tmp/test.key", nil)
	if err != nil {
		log.Fatal(err)
	}
}

A server:

package main

import (
	"io"
	"log"
	"crypto/tls"
	"net"
	"bufio"
)

func main() {
	cer, err := tls.LoadX509KeyPair("/home/paulgorman/tmp/test.crt", "/home/paulgorman/tmp/test.key")
	if err != nil {
		log.Fatal(err)
	}
	config := &tls.Config{Certificates: []tls.Certificate{cer}}
	ln, err := tls.Listen("tcp", ":4430", config)
	if err != nil {
		log.Fatal(err)
	}
	defer ln.Close()
	for {
		conn, err := ln.Accept()
		if err != nil {
			log.Fatal(err)
		}
		go handleConnection(conn)
	}
}

func handleConnection(conn net.Conn) {
	defer conn.Close()
	r := bufio.NewReader(conn)
	for {
		msg, err := r.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
			log.Println(err)
			return
		}
		println(msg)
		n, err := conn.Write([]byte("pong\n"))
		if err != nil {
			log.Println(n, err)
			return
		}
	}
}

The client:

package main

import (
	"log"
	"crypto/tls"
)

func main() {
	log.SetFlags(log.Lshortfile)
	conf := &tls.Config{
		InsecureSkipVerify: true,
	}
	conn, err := tls.Dial("tcp", "127.0.0.1:4430", conf)
	if err != nil {
		log.Println(err)
		return
	}
	defer conn.Close()
	n, err := conn.Write([]byte("ping\n"))
	if err != nil {
		log.Println(n, err)
		return
	}
	buf := make([]byte, 100)
	n, err = conn.Read(buf)
	if err != nil {
		log.Println(n, err)
		return
	}
	println(string(buf[:n]))
}

References