Sunday, April 3, 2016

Generate the private key and certificate

Generate the private key and certificate

Run gen.go:

# go run gen.go

package main

import (
 "crypto/x509"
 "crypto/x509/pkix"
 "crypto/rsa"
 "crypto/rand"
 "math/big"
 "io/ioutil"
 "log"
 "time"
)

func main() {
 ca := &x509.Certificate{
  SerialNumber: big.NewInt(1653),
  Subject: pkix.Name{
   Country: []string{"China"},
   Organization: []string{"Yjwt"},
   OrganizationalUnit: []string{"YjwtU"},
  },
  NotBefore: time.Now(),
  NotAfter: time.Now().AddDate(10,0,0),
  SubjectKeyId: []byte{1,2,3,4,5},
  BasicConstraintsValid: true,
  IsCA: true,
  ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
  KeyUsage: x509.KeyUsageDigitalSignature|x509.KeyUsageCertSign,
 }

 priv, _ := rsa.GenerateKey(rand.Reader, 1024)
 pub := &priv.PublicKey
 ca_b, err := x509.CreateCertificate(rand.Reader, ca, ca, pub, priv)
 if err != nil {
  log.Println("create ca failed", err)
  return
 }
 ca_f := "ca.pem"
 log.Println("write to", ca_f)
 ioutil.WriteFile(ca_f, ca_b, 0777)

 priv_f := "ca.key"
 priv_b := x509.MarshalPKCS1PrivateKey(priv)
 log.Println("write to", priv_f)
 ioutil.WriteFile(priv_f, priv_b, 0777)

 cert2 := &x509.Certificate{
  SerialNumber: big.NewInt(1658),
  Subject: pkix.Name{
   Country: []string{"China"},
   Organization: []string{"Fuck"},
   OrganizationalUnit: []string{"FuckU"},
  },
  NotBefore: time.Now(),
  NotAfter: time.Now().AddDate(10,0,0),
  SubjectKeyId: []byte{1,2,3,4,6},
  ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
  KeyUsage: x509.KeyUsageDigitalSignature|x509.KeyUsageCertSign,
 }
 priv2, _ := rsa.GenerateKey(rand.Reader, 1024)
 pub2 := &priv2.PublicKey
 cert2_b, err2 := x509.CreateCertificate(rand.Reader, cert2, ca, pub2, priv)
 if err2 != nil {
  log.Println("create cert2 failed", err2)
  return
 }

 cert2_f := "cert2.pem"
 log.Println("write to", cert2_f)
 ioutil.WriteFile(cert2_f, cert2_b, 0777)

 priv2_f := "cert2.key"
 priv2_b := x509.MarshalPKCS1PrivateKey(priv2)
 log.Println("write to", priv2_f)
 ioutil.WriteFile(priv2_f, priv2_b, 0777)

 ca_c, _ := x509.ParseCertificate(ca_b)
 cert2_c, _ := x509.ParseCertificate(cert2_b)

 err3 := cert2_c.CheckSignatureFrom(ca_c)
 log.Println("check signature", err3 == nil)
}

server.go:

package main

import (
 "crypto/rand"
 "crypto/tls"
 "log"
 "net"
 "crypto/x509"
 "io/ioutil"
)

func main() {

 ca_b, _ := ioutil.ReadFile("ca.pem")
 ca, _ := x509.ParseCertificate(ca_b)
 priv_b, _ := ioutil.ReadFile("ca.key")
 priv, _ := x509.ParsePKCS1PrivateKey(priv_b)

 pool := x509.NewCertPool()
 pool.AddCert(ca)

 cert := tls.Certificate{
  Certificate: [][]byte{ ca_b },
  PrivateKey: priv,
 }

 config := tls.Config{
  ClientAuth: tls.RequireAndVerifyClientCert,
  Certificates: []tls.Certificate{cert},
  ClientCAs: pool,
 }
 config.Rand = rand.Reader
 service := "0.0.0.0:443"
 listener, err := tls.Listen("tcp", service, &config)
 if err != nil {
  log.Fatalf("server: listen: %s", err)
 }
 log.Print("server: listening")

 for {
  conn, err := listener.Accept()
  if err != nil {
   log.Printf("server: accept: %s", err)
   break
  }
  defer conn.Close()
  log.Printf("server: accepted from %s", conn.RemoteAddr())
  go handleClient(conn)
 }
}

func handleClient(conn net.Conn) {
 defer conn.Close()
 buf := make([]byte, 512)
 for {
  log.Print("server: conn: waiting")
  n, err := conn.Read(buf)
  if err != nil {
   if err != nil {
    log.Printf("server: conn: read: %s", err)
   }
   break
  }

  tlscon, ok := conn.(*tls.Conn)
  if ok {
   state := tlscon.ConnectionState()
   sub := state.PeerCertificates[0].Subject
   log.Println(sub)
  }

  log.Printf("server: conn: echo %q\n", string(buf[:n]))
  n, err = conn.Write(buf[:n])

  n, err = conn.Write(buf[:n])
  log.Printf("server: conn: wrote %d bytes", n)

  if err != nil {
   log.Printf("server: write: %s", err)
   break
  }
 }
 log.Println("server: conn: closed")
}

client.go:

package main

import (
 "crypto/tls"
 "crypto/x509"
 "fmt"
 "io"
 "io/ioutil"
 "log"
)

func main() {
 cert2_b, _ := ioutil.ReadFile("cert2.pem")
 priv2_b, _ := ioutil.ReadFile("cert2.key")
 priv2, _ := x509.ParsePKCS1PrivateKey(priv2_b)

 cert := tls.Certificate{
  Certificate: [][]byte{ cert2_b },
  PrivateKey: priv2,
 }

 config := tls.Config{Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true}
 conn, err := tls.Dial("tcp", "127.0.0.1:443", &config)
 if err != nil {
  log.Fatalf("client: dial: %s", err)
 }
 defer conn.Close()
 log.Println("client: connected to: ", conn.RemoteAddr())

 state := conn.ConnectionState()
 for _, v := range state.PeerCertificates {
  fmt.Println(x509.MarshalPKIXPublicKey(v.PublicKey))
  fmt.Println(v.Subject)
 }
 log.Println("client: handshake: ", state.HandshakeComplete)
 log.Println("client: mutual: ", state.NegotiatedProtocolIsMutual)

 message := "Hello\n"
 n, err := io.WriteString(conn, message)
 if err != nil {
  log.Fatalf("client: write: %s", err)
 }
 log.Printf("client: wrote %q (%d bytes)", message, n)

 reply := make([]byte, 256)
 n, err = conn.Read(reply)
 log.Printf("client: read %q (%d bytes)", string(reply[:n]), n)
 log.Print("client: exiting")
}

Reference:

https://github.com/nareix/tls-example/blob/master/gen.go

No comments: