Skip to content

Instantly share code, notes, and snippets.

@spikebike
Created March 29, 2012 01:13
Show Gist options
  • Select an option

  • Save spikebike/2232102 to your computer and use it in GitHub Desktop.

Select an option

Save spikebike/2232102 to your computer and use it in GitHub Desktop.
TLS server and client
package main
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io"
"log"
)
func main() {
cert, err := tls.LoadX509KeyPair("certs/client.pem", "certs/client.key")
if err != nil {
log.Fatalf("server: loadkeys: %s", err)
}
config := tls.Config{Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true}
conn, err := tls.Dial("tcp", "127.0.0.1:8000", &config)
if err != nil {
log.Fatalf("client: dial: %s", err)
}
defer conn.Close()
log.Println("client: connected to: ", conn.RemoteAddr())
state := conn.ConnectionState()
for _, v := range state.PeerCertificates {
fmt.Println(x509.MarshalPKIXPublicKey(v.PublicKey))
fmt.Println(v.Subject)
}
log.Println("client: handshake: ", state.HandshakeComplete)
log.Println("client: mutual: ", state.NegotiatedProtocolIsMutual)
message := "Hello\n"
n, err := io.WriteString(conn, message)
if err != nil {
log.Fatalf("client: write: %s", err)
}
log.Printf("client: wrote %q (%d bytes)", message, n)
reply := make([]byte, 256)
n, err = conn.Read(reply)
log.Printf("client: read %q (%d bytes)", string(reply[:n]), n)
log.Print("client: exiting")
}
#!/bin/bash
# call this script with an email address (valid or not).
# like:
# ./makecert.sh joe@random.com
mkdir certs
rm certs/*
echo "make server cert"
openssl req -new -nodes -x509 -out certs/server.pem -keyout certs/server.key -days 3650 -subj "/C=DE/ST=NRW/L=Earth/O=Random Company/OU=IT/CN=www.random.com/emailAddress=$1"
echo "make client cert"
openssl req -new -nodes -x509 -out certs/client.pem -keyout certs/client.key -days 3650 -subj "/C=DE/ST=NRW/L=Earth/O=Random Company/OU=IT/CN=www.random.com/emailAddress=$1"
package main
import (
"crypto/rand"
"crypto/tls"
"log"
"net"
"crypto/x509"
)
func main() {
cert, err := tls.LoadX509KeyPair("certs/server.pem", "certs/server.key")
if err != nil {
log.Fatalf("server: loadkeys: %s", err)
}
config := tls.Config{Certificates: []tls.Certificate{cert}}
config.Rand = rand.Reader
service := "0.0.0.0:8000"
listener, err := tls.Listen("tcp", service, &config)
if err != nil {
log.Fatalf("server: listen: %s", err)
}
log.Print("server: listening")
for {
conn, err := listener.Accept()
if err != nil {
log.Printf("server: accept: %s", err)
break
}
defer conn.Close()
log.Printf("server: accepted from %s", conn.RemoteAddr())
tlscon, ok := conn.(*tls.Conn)
if ok {
log.Print("ok=true")
state := tlscon.ConnectionState()
for _, v := range state.PeerCertificates {
log.Print(x509.MarshalPKIXPublicKey(v.PublicKey))
}
}
go handleClient(conn)
}
}
func handleClient(conn net.Conn) {
defer conn.Close()
buf := make([]byte, 512)
for {
log.Print("server: conn: waiting")
n, err := conn.Read(buf)
if err != nil {
if err != nil {
log.Printf("server: conn: read: %s", err)
}
break
}
log.Printf("server: conn: echo %q\n", string(buf[:n]))
n, err = conn.Write(buf[:n])
n, err = conn.Write(buf[:n])
log.Printf("server: conn: wrote %d bytes", n)
if err != nil {
log.Printf("server: write: %s", err)
break
}
}
log.Println("server: conn: closed")
}
@btfak

btfak commented Nov 17, 2013

Copy link
Copy Markdown

good job!

@jeffkit

jeffkit commented Dec 25, 2013

Copy link
Copy Markdown

great! thank you!

@jvkumar

jvkumar commented Feb 4, 2014

Copy link
Copy Markdown

Thanks for the post. Can you help me to find solution of my TLS config question at http://stackoverflow.com/questions/21562269/golang-how-to-specify-certificate-in-tls-config-for-http-client

@rem7

rem7 commented Mar 27, 2014

Copy link
Copy Markdown

thanks!

@gosharplite

Copy link
Copy Markdown

You might want to remove line 30 in server.go, it will cause memory leak.

@xtremebeing

Copy link
Copy Markdown

I'm using go version go1.5.1 linux/amd64 , the conversion on line 32 of server.go works but tlscon is always empty. Any ideas why?

@itczl22

itczl22 commented Dec 25, 2016

Copy link
Copy Markdown

thanks!

@quiznilo1

Copy link
Copy Markdown

What's with line 57 and 59 in the server code?

@mh-cbon

mh-cbon commented May 3, 2018

Copy link
Copy Markdown

You might want to remove line 30 in server.go, it will cause memory leak.

to add on this, the defer will not terminate because it is within a for loop. Indeed it is preferable to either undefer the statement, or wrap the for body loop within a func(){}() call.

What's with line 57 and 59 in the server code?

looks likes it is duplicated.

@mimoo

mimoo commented Sep 5, 2018

Copy link
Copy Markdown

you do not want to have the defer in the loop

@mkrawczuk

Copy link
Copy Markdown

In server.go, conn.Close() is called twice - in main() (line 30), and in handleClient() (line 45).

@reinkrul

reinkrul commented May 1, 2020

Copy link
Copy Markdown

I think the purpose of this snippet is also to have the server require and verify the client's certificate, which must be configured in the server's TLS config:

ClientAuth: tls.RequireAndVerifyClientCert

@FavorWen

Copy link
Copy Markdown

Thank you, it's really help!

@oermoshkin

oermoshkin commented Nov 6, 2021

Copy link
Copy Markdown

I'm using go version go1.5.1 linux/amd64 , the conversion on line 32 of server.go works but tlscon is always empty. Any ideas why?

In server.go file after the line: log.Print("ok=true"), insert

err = tlscon.Handshake()
if err != nil {
  log.Fatalf("Handshake error: %s", err)
}

@nishanths

nishanths commented Nov 27, 2022

Copy link
Copy Markdown

server.go:17: config.Rand = rand.Reader is not necessary from go1.19 or later at least (and likely not necessary in earlier go versions either). Note that the documentation for tls.Config.Rand says:

If Rand is nil, TLS uses the cryptographic random reader in package crypto/rand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment