-
-
Save losintikfos/a8d89d0878e1670ed5058c7fdb7b670c to your computer and use it in GitHub Desktop.
golang tls client and server, require and verify certificate in double direction
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# >>>>>>>>>>>>>>>>>> Root certificate <<<<<<<<<<<<<<<<<<<<<< | |
# Generate root certificate private key: ca.key | |
openssl genrsa -out ca.key 2048 | |
# Generate a self-signed root certificate: 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" | |
# >>>>>>>>>>>>>>>>>> Server certificate <<<<<<<<<<<<<<<<<<<<<< | |
# Generate server certificate private key: ca.key | |
openssl genrsa -out server.key 2048 | |
# Generate server certificate request: server.csr | |
openssl req -new -nodes -key server.key -out server.csr -subj /C=CN/ST=GuangDong/L=Guangzhou/O="Localhost Server"/CN=localhost | |
# Signing server certificate: server.crt | |
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt | |
# >>>>>>>>>>>>>>>>>> Client certificate <<<<<<<<<<<<<<<<<<<<<< | |
# Generate client certificate private key: ca.key | |
openssl genrsa -out client.key 2048 | |
# Generate a client certificate request: client.csr | |
openssl req -new -nodes -key client.key -out client.csr -subj /C=CN/ST=GuangDong/L=Guangzhou/O="Localhost Client"/CN=localhost | |
# Signing client certificate: client.crt | |
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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