Created
January 24, 2021 13:34
-
-
Save erikdubbelboer/f14b38d258f376dd6d4d47491f32535a to your computer and use it in GitHub Desktop.
This file contains hidden or 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/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