Skip to content

Instantly share code, notes, and snippets.

@erikdubbelboer
Created January 24, 2021 13:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erikdubbelboer/f14b38d258f376dd6d4d47491f32535a to your computer and use it in GitHub Desktop.
Save erikdubbelboer/f14b38d258f376dd6d4d47491f32535a to your computer and use it in GitHub Desktop.
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"io/ioutil"
"math/big"
"net"
"net/http"
"runtime"
"sync/atomic"
"time"
"github.com/valyala/fasthttp"
)
func main() {
caCert, key, err := GenerateCert("localhost")
if err != nil {
panic(err)
}
caCertPool := x509.NewCertPool()
if !caCertPool.AppendCertsFromPEM(caCert) {
panic("not ok")
}
caCertPool.AppendCertsFromPEM(caCert)
cert, err := tls.X509KeyPair(caCert, key)
if err != nil {
panic(err)
}
go server(caCertPool, cert)
time.Sleep(time.Second)
// fasthttpClient(caCertPool, cert)
httpClient(caCertPool, cert)
}
func server(caCertPool *x509.CertPool, cert tls.Certificate) {
// Create the TLS Config with the CA pool and enable Client certificate validation
cfg := &tls.Config{
ClientCAs: caCertPool,
ClientAuth: tls.RequireAndVerifyClientCert,
Certificates: []tls.Certificate{cert},
}
cfg.BuildNameToCertificate()
ln, err := net.Listen("tcp4", "localhost:8443")
if err != nil {
panic(err)
}
lnTls := tls.NewListener(ln, cfg)
server := &fasthttp.Server{
IdleTimeout: 30 * time.Second,
TCPKeepalive: true,
TCPKeepalivePeriod: 30 * time.Second,
MaxConnsPerIP: 200,
Handler: func(ctx *fasthttp.RequestCtx) {
ctx.SetStatusCode(200)
ctx.SetBody([]byte("hello"))
},
}
if err := server.Serve(lnTls); err != nil {
panic(err)
}
}
func fasthttpClient(caCertPool *x509.CertPool, cert tls.Certificate) {
client := &fasthttp.Client{
TLSConfig: &tls.Config{
RootCAs: caCertPool,
Certificates: []tls.Certificate{cert},
ClientSessionCache: tls.NewLRUClientSessionCache(64),
},
}
var requests int64
worker := func() {
for {
req := fasthttp.AcquireRequest()
res := fasthttp.AcquireResponse()
req.SetRequestURI("https://localhost:8443/")
if err := client.Do(req, res); err != nil {
println(err.Error())
}
atomic.AddInt64(&requests, 1)
fasthttp.ReleaseRequest(req)
fasthttp.ReleaseResponse(res)
}
}
for i := 0; i < 4; i++ {
go worker()
}
// Print the request counters every second.
for {
time.Sleep(time.Second)
r := atomic.SwapInt64(&requests, 0)
fmt.Println(r, runtime.NumGoroutine())
}
}
func httpClient(caCertPool *x509.CertPool, cert tls.Certificate) {
client := &http.Client{
Transport: &http.Transport{
TLSHandshakeTimeout: 5 * time.Second,
MaxIdleConns: 2000,
MaxIdleConnsPerHost: 200,
MaxConnsPerHost: 2000,
IdleConnTimeout: 20 * time.Second,
WriteBufferSize: 1024,
ReadBufferSize: 1024,
TLSClientConfig: &tls.Config{
RootCAs: caCertPool,
Certificates: []tls.Certificate{cert},
ClientSessionCache: tls.NewLRUClientSessionCache(64),
},
},
}
var requests int64
worker := func() {
for {
if res, err := client.Get("https://localhost:8443/"); err != nil {
println(err.Error())
} else {
_, err := ioutil.ReadAll(res.Body)
if err != nil {
panic(err)
}
}
atomic.AddInt64(&requests, 1)
}
}
for i := 0; i < 4; i++ {
go worker()
}
// Print the request counters every second.
for {
time.Sleep(time.Second)
r := atomic.SwapInt64(&requests, 0)
fmt.Println(r, runtime.NumGoroutine())
}
}
// GenerateCert generates certificate and private key based on the given host.
func GenerateCert(host string) ([]byte, []byte, error) {
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, nil, err
}
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, nil, err
}
cert := &x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"I have your data"},
},
NotBefore: time.Now(),
NotAfter: time.Now().Add(365 * 24 * time.Hour),
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
SignatureAlgorithm: x509.SHA256WithRSA,
DNSNames: []string{host},
BasicConstraintsValid: true,
IsCA: true,
}
certBytes, err := x509.CreateCertificate(
rand.Reader, cert, cert, &priv.PublicKey, priv,
)
p := pem.EncodeToMemory(
&pem.Block{
Type: "PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(priv),
},
)
b := pem.EncodeToMemory(
&pem.Block{
Type: "CERTIFICATE",
Bytes: certBytes,
},
)
return b, p, err
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment