Skip to content

Instantly share code, notes, and snippets.

@svicknesh
Forked from xjdrew/client.go
Created August 13, 2019 00:39
Show Gist options
  • Save svicknesh/653a2b6060e82e1572afa8cd522f579a to your computer and use it in GitHub Desktop.
Save svicknesh/653a2b6060e82e1572afa8cd522f579a to your computer and use it in GitHub Desktop.
golang tls client and server, require and verify certificate in double direction
package main
import (
"crypto/tls"
"crypto/x509"
"flag"
"io"
"io/ioutil"
"log"
"os"
"strings"
"sync"
)
func createClientConfig(ca, crt, key string) (*tls.Config, error) {
caCertPEM, err := ioutil.ReadFile(ca)
if err != nil {
return nil, err
}
roots := x509.NewCertPool()
ok := roots.AppendCertsFromPEM(caCertPEM)
if !ok {
panic("failed to parse root certificate")
}
cert, err := tls.LoadX509KeyPair(crt, key)
if err != nil {
return nil, err
}
return &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: roots,
}, nil
}
func printConnState(conn *tls.Conn) {
log.Print(">>>>>>>>>>>>>>>> State <<<<<<<<<<<<<<<<")
state := conn.ConnectionState()
log.Printf("Version: %x", state.Version)
log.Printf("HandshakeComplete: %t", state.HandshakeComplete)
log.Printf("DidResume: %t", state.DidResume)
log.Printf("CipherSuite: %x", state.CipherSuite)
log.Printf("NegotiatedProtocol: %s", state.NegotiatedProtocol)
log.Printf("NegotiatedProtocolIsMutual: %t", state.NegotiatedProtocolIsMutual)
log.Print("Certificate chain:")
for i, cert := range state.PeerCertificates {
subject := cert.Subject
issuer := cert.Issuer
log.Printf(" %d s:/C=%v/ST=%v/L=%v/O=%v/OU=%v/CN=%s", i, subject.Country, subject.Province, subject.Locality, subject.Organization, subject.OrganizationalUnit, subject.CommonName)
log.Printf(" i:/C=%v/ST=%v/L=%v/O=%v/OU=%v/CN=%s", issuer.Country, issuer.Province, issuer.Locality, issuer.Organization, issuer.OrganizationalUnit, issuer.CommonName)
}
log.Print(">>>>>>>>>>>>>>>> State End <<<<<<<<<<<<<<<<")
}
func main() {
connect := flag.String("connect", "localhost:4433", "who to connect to")
ca := flag.String("ca", "./ca.crt", "root certificate")
crt := flag.String("crt", "./client.crt", "certificate")
key := flag.String("key", "./client.key", "key")
flag.Parse()
addr := *connect
if !strings.Contains(addr, ":") {
addr += ":443"
}
config, err := createClientConfig(*ca, *crt, *key)
if err != nil {
log.Fatal("config failed: %s", err.Error())
}
conn, err := tls.Dial("tcp", addr, config)
if err != nil {
log.Fatalf("failed to connect: %s", err.Error())
}
defer conn.Close()
log.Printf("connect to %s succeed", addr)
printConnState(conn)
var wg sync.WaitGroup
wg.Add(1)
go func() {
io.Copy(conn, os.Stdin)
wg.Done()
}()
wg.Add(1)
go func() {
io.Copy(os.Stdout, conn)
wg.Done()
}()
wg.Wait()
}
# >>>>>>>>>>>>>>>>>> 根证书 <<<<<<<<<<<<<<<<<<<<<<
# 生成根证书私钥: ca.key
openssl genrsa -out ca.key 2048
# 生成自签名根证书: ca.crt
openssl req -new -key ca.key -x509 -days 3650 -out ca.crt -subj /C=CN/ST=GuangDong/O="Localhost Ltd"/CN="Localhost Root"
# >>>>>>>>>>>>>>>>>> 服务器证书 <<<<<<<<<<<<<<<<<<<<<<
# 生成服务器证书私钥: ca.key
openssl genrsa -out server.key 2048
# 生成服务器证书请求: server.csr
openssl req -new -nodes -key server.key -out server.csr -subj /C=CN/ST=GuangDong/L=Guangzhou/O="Localhost Server"/CN=localhost
# 签名服务器证书: server.crt
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
# >>>>>>>>>>>>>>>>>> 客户端证书 <<<<<<<<<<<<<<<<<<<<<<
# 生成客户端证书私钥: ca.key
openssl genrsa -out client.key 2048
# 生成客户端证书请求: client.csr
openssl req -new -nodes -key client.key -out client.csr -subj /C=CN/ST=GuangDong/L=Guangzhou/O="Localhost Client"/CN=localhost
# 签名客户端证书: client.crt
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt
package main
import (
"crypto/tls"
"crypto/x509"
"flag"
"io"
"io/ioutil"
"log"
"net"
)
func createServerConfig(ca, crt, key string) (*tls.Config, error) {
caCertPEM, err := ioutil.ReadFile(ca)
if err != nil {
return nil, err
}
roots := x509.NewCertPool()
ok := roots.AppendCertsFromPEM(caCertPEM)
if !ok {
panic("failed to parse root certificate")
}
cert, err := tls.LoadX509KeyPair(crt, key)
if err != nil {
return nil, err
}
return &tls.Config{
Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: roots,
}, nil
}
func printConnState(conn *tls.Conn) {
log.Print(">>>>>>>>>>>>>>>> State <<<<<<<<<<<<<<<<")
state := conn.ConnectionState()
log.Printf("Version: %x", state.Version)
log.Printf("HandshakeComplete: %t", state.HandshakeComplete)
log.Printf("DidResume: %t", state.DidResume)
log.Printf("CipherSuite: %x", state.CipherSuite)
log.Printf("NegotiatedProtocol: %s", state.NegotiatedProtocol)
log.Printf("NegotiatedProtocolIsMutual: %t", state.NegotiatedProtocolIsMutual)
log.Print("Certificate chain:")
for i, cert := range state.PeerCertificates {
subject := cert.Subject
issuer := cert.Issuer
log.Printf(" %d s:/C=%v/ST=%v/L=%v/O=%v/OU=%v/CN=%s", i, subject.Country, subject.Province, subject.Locality, subject.Organization, subject.OrganizationalUnit, subject.CommonName)
log.Printf(" i:/C=%v/ST=%v/L=%v/O=%v/OU=%v/CN=%s", issuer.Country, issuer.Province, issuer.Locality, issuer.Organization, issuer.OrganizationalUnit, issuer.CommonName)
}
log.Print(">>>>>>>>>>>>>>>> State End <<<<<<<<<<<<<<<<")
}
func main() {
listen := flag.String("listen", "localhost:4433", "which port to listen")
ca := flag.String("ca", "./ca.crt", "root certificate")
crt := flag.String("crt", "./server.crt", "certificate")
key := flag.String("key", "./server.key", "key")
flag.Parse()
config, err := createServerConfig(*ca, *crt, *key)
if err != nil {
log.Fatal("config failed: %s", err.Error())
}
ln, err := tls.Listen("tcp", *listen, config)
if err != nil {
log.Fatal("listen failed: %s", err.Error())
}
log.Printf("listen on %s", *listen)
for {
conn, err := ln.Accept()
if err != nil {
log.Fatal("accept failed: %s", err.Error())
break
}
log.Printf("connection open: %s", conn.RemoteAddr())
printConnState(conn.(*tls.Conn))
go func(c net.Conn) {
wr, _ := io.Copy(c, c)
c.Close()
log.Printf("connection close: %s, written: %d", conn.RemoteAddr(), wr)
}(conn)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment