commit 15b60eed34028c1bdf7374806a2d4e491debf390 Author: Mirror Date: Sun Oct 16 12:47:15 2022 +0300 Init diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7ee611a --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +ca: + openssl-3.0 req -x509 -new -nodes \ + -newkey rsa:4096 -keyout pki/ca.key \ + -sha256 -days 3650 -out pki/ca.crt \ + -subj "/CN=MTLS TEST Root CA" + cp pki/ca.crt pkg/castore/ca.crt + +server: server-cert + go build mtls/cmd/server + +server-cert: ca + ./cert.sh server + +client: client-cert + go build mtls/cmd/client + +client-cert: ca + ./cert.sh client + + +all: server client + +clean: + rm -r pki/* client server pkg/castore/ca.crt diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..a41b743 --- /dev/null +++ b/Readme.md @@ -0,0 +1,6 @@ +# Golang mutual TLS example with local CA + +## How to run +- run `make all` to build +- run `./server` command +- in separate terminal run `./client` command diff --git a/cert.sh b/cert.sh new file mode 100755 index 0000000..9f4065d --- /dev/null +++ b/cert.sh @@ -0,0 +1,13 @@ +#!/bin/env sh + +openssl-3.0 req -new -nodes \ + -out pki/$1.csr \ + -keyout pki/$1.key \ + -subj "/CN=MTLS TEST $1 certificate" \ + -addext "basicConstraints=CA:FALSE" \ + -addext "keyUsage=digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment" \ + -addext "subjectAltName=DNS.1:$1,DNS.2:localhost" +openssl-3.0 x509 -req -in pki/$1.csr -out pki/$1.crt -copy_extensions copy \ + -days 865 -sha256 \ + -CA pki/ca.crt -CAkey pki/ca.key \ + -CAcreateserial -CAserial pki/ca.srl diff --git a/cmd/client/client.go b/cmd/client/client.go new file mode 100644 index 0000000..35e62fc --- /dev/null +++ b/cmd/client/client.go @@ -0,0 +1,51 @@ +package main + +import ( + "crypto/tls" + "crypto/x509" + "io" + "log" + "mtls/pkg/castore" + "net/http" + "os" +) + +var certPool *x509.CertPool + +const ( + CLIENT_CRT_FILE = "pki/client.crt" + CLIENT_KEY_FILE = "pki/client.key" + SERVER_ADDRESS = "https://localhost:8080/hello" +) + +func main() { + log.Default().SetFlags(log.Lshortfile) + certPool = castore.NewCAstore() + clientKeyPair, err := tls.LoadX509KeyPair(CLIENT_CRT_FILE, CLIENT_KEY_FILE) + if err != nil { + log.Fatal(err) + } + + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: certPool, + Certificates: []tls.Certificate{clientKeyPair}, + }, + }, + } + + resp, err := client.Get(SERVER_ADDRESS) + if err != nil { + log.Fatal(err) + } + + for _, cert := range resp.TLS.PeerCertificates { + log.Printf("Peer certificate CommonName: %s", cert.Subject.CommonName) + } + + _, err = io.Copy(os.Stdout, resp.Body) + if err != nil { + log.Fatal(err) + } +} diff --git a/cmd/server/server.go b/cmd/server/server.go new file mode 100644 index 0000000..39a5e07 --- /dev/null +++ b/cmd/server/server.go @@ -0,0 +1,55 @@ +package main + +import ( + "crypto/tls" + "crypto/x509" + "log" + "mtls/pkg/castore" + "net/http" +) + +var ( + certPool *x509.CertPool +) + +const ( + SERVER_CRT_FILE = "pki/server.crt" + SERVER_KEY_FILE = "pki/server.key" + SERVER_ADDRESS = ":8080" +) + +func main() { + log.Default().SetFlags(log.Lshortfile) + certPool = castore.NewCAstore() + mux := http.NewServeMux() + mux.HandleFunc("/hello", Hello_handler) + + serverKeypair, err := tls.LoadX509KeyPair(SERVER_CRT_FILE, SERVER_KEY_FILE) + if err != nil { + log.Fatal(err) + } + + server := http.Server{ + TLSConfig: &tls.Config{ + MinVersion: tls.VersionTLS13, + RootCAs: certPool, + ClientCAs: certPool, + Certificates: []tls.Certificate{serverKeypair}, + ClientAuth: tls.RequireAndVerifyClientCert, + }, + Addr: SERVER_ADDRESS, + Handler: mux, + } + + err = server.ListenAndServeTLS("", "") + if err != nil { + log.Fatal(err) + } +} + +func Hello_handler(w http.ResponseWriter, r *http.Request) { + for _, cert := range r.TLS.PeerCertificates { + log.Printf("Peer certificate CommonName: %s", cert.Subject.CommonName) + } + w.Write([]byte("Hello world\n")) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d9c3e5e --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module mtls + +go 1.19 diff --git a/pkg/castore/castore.go b/pkg/castore/castore.go new file mode 100644 index 0000000..abc94c8 --- /dev/null +++ b/pkg/castore/castore.go @@ -0,0 +1,20 @@ +package castore + +import ( + "crypto/x509" + _ "embed" + "log" + "os" +) + +//go:embed ca.crt +var CACert []byte + +func NewCAstore() *x509.CertPool { + logger := log.New(os.Stderr, "", log.Lshortfile) + certPool := x509.NewCertPool() + if !certPool.AppendCertsFromPEM(CACert) { + logger.Fatal("Can't append CertPool with embedded CA") + } + return certPool +} diff --git a/pki/.keep b/pki/.keep new file mode 100644 index 0000000..e69de29