package main import ( "crypto" "crypto/rand" "crypto/rsa" "crypto/tls" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "fmt" "io" "math/big" "os" "time" ) func main() { fmt.Println(run()) } type fakeSigner struct { crypto.Signer } func (s *fakeSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) { k := s.Public().(*rsa.PublicKey).Size() return make([]byte, k), nil } func generateBigRSA(size int) *rsa.PrivateKey { b := make([]byte, size) b[0] = 0xf3 return &rsa.PrivateKey{PublicKey: rsa.PublicKey{ N: big.NewInt(0).SetBytes(b), E: 0b100001, }} } func run() error { certPEM, err := os.ReadFile("./ca.pem") if err != nil { return err } pCert, _ := pem.Decode(certPEM) cert, err := x509.ParseCertificate(pCert.Bytes) if err != nil { return err } pool := x509.NewCertPool() pool.AddCert(cert) if os.Args[1] == "client" { c, err := tls.Dial("tcp", "localhost:8888", &tls.Config{RootCAs: pool}) if err != nil { return err } defer c.Close() err = c.Handshake() if err != nil { return err } return nil } else if os.Args[1] == "client-auth" { rsa := generateBigRSA(1024 * 63) clientCertRaw, err := makeCert("./ca.pem", "./ca-key.pem", pkix.Name{CommonName: "localhost"}, []string{"localhost"}, rsa.Public()) if err != nil { return err } var clientCert = tls.Certificate{ Certificate: [][]byte{clientCertRaw}, PrivateKey: &fakeSigner{rsa}, } c, err := tls.Dial("tcp", "localhost:8889", &tls.Config{RootCAs: pool, Certificates: []tls.Certificate{clientCert}}) if err != nil { return err } defer c.Close() err = c.Handshake() if err != nil { return err } c.Read(make([]byte, 1)) return nil } else { go func() { rsa, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { panic(err) } c, err := makeCert("./ca.pem", "./ca-key.pem", pkix.Name{CommonName: "localhost"}, []string{"localhost"}, rsa.Public()) if err != nil { panic(err) } var cert = tls.Certificate{ Certificate: [][]byte{c}, PrivateKey: rsa, } l, err := tls.Listen("tcp", "localhost:8889", &tls.Config{ClientCAs: pool, Certificates: []tls.Certificate{cert}, ClientAuth: tls.RequireAndVerifyClientCert}) if err != nil { panic(err) } for { con, err := l.Accept() if err != nil { fmt.Println(err) continue } go func() { err = con.(*tls.Conn).Handshake() con.Write(make([]byte, 1)) fmt.Println(err) con.Close() }() } }() rsa := generateBigRSA(1024 * 63) c, err := makeCert("./ca.pem", "./ca-key.pem", pkix.Name{CommonName: "localhost"}, []string{"localhost"}, rsa.Public()) if err != nil { return err } var cert = tls.Certificate{ Certificate: [][]byte{c}, PrivateKey: &fakeSigner{rsa}, } l, err := tls.Listen("tcp", "localhost:8888", &tls.Config{Certificates: []tls.Certificate{cert}}) if err != nil { return err } for { con, err := l.Accept() if err != nil { fmt.Println(err) continue } go func() { err = con.(*tls.Conn).Handshake() con.Write(make([]byte, 1)) fmt.Println(err) con.Close() }() } } } func makeCert(caCertPath, caKeyPath string, subject pkix.Name, dnsNames []string, public any) ([]byte, error) { intCertPEM, err := os.ReadFile(caCertPath) if err != nil { return nil, err } intKeyPem, err := os.ReadFile(caKeyPath) if err != nil { return nil, err } pIntCert, _ := pem.Decode(intCertPEM) pIntKey, _ := pem.Decode(intKeyPem) key, err := x509.ParsePKCS8PrivateKey(pIntKey.Bytes) if err != nil { return nil, err } cert, err := x509.ParseCertificate(pIntCert.Bytes) if err != nil { return nil, err } buf := make([]byte, 16) buf2 := make([]byte, 16) rand.Read(buf) rand.Read(buf2) newCert, err := x509.CreateCertificate(rand.Reader, &x509.Certificate{ SubjectKeyId: buf, AuthorityKeyId: cert.SubjectKeyId, SerialNumber: big.NewInt(0).SetBytes(buf2), Subject: subject, DNSNames: dnsNames, BasicConstraintsValid: true, IsCA: false, NotBefore: time.Now().Add(-time.Hour), NotAfter: time.Now().Add(time.Hour * 24 * 365 * 50), }, cert, public, key) if err != nil { return nil, err } return newCert, nil }