Initial commit
This commit is contained in:
commit
2fbb3215bd
|
@ -0,0 +1,2 @@
|
|||
certs/
|
||||
*.exe
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
PARTS= root server client
|
||||
KEYS = $(addprefix certs/,$(addsuffix .key,$(PARTS)))
|
||||
CERTS= $(addprefix certs/,$(addsuffix .pem,$(PARTS)))
|
||||
|
||||
all: certs/ $(KEYS) $(CERTS)
|
||||
|
||||
certs/:
|
||||
-mkdir certs
|
||||
|
||||
certs/root.pem certs/root.key &:
|
||||
go run generate.go root certs/root
|
||||
|
||||
certs/server.pem certs/server.key &: certs/root.pem certs/root.key
|
||||
go run generate.go server certs/server certs/root
|
||||
|
||||
certs/client.pem certs/client.key &: certs/root.pem certs/root.key
|
||||
go run generate.go client certs/client certs/root
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"io"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
rawpem, err := os.ReadFile("certs/root.pem")
|
||||
if err != nil {
|
||||
fmt.Println("pem read error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
cert, err := tls.LoadX509KeyPair("certs/client.pem", "certs/client.key")
|
||||
if err != nil {
|
||||
fmt.Println("cert load error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
pool := x509.NewCertPool()
|
||||
if !pool.AppendCertsFromPEM(rawpem) {
|
||||
fmt.Println("add pem not ok")
|
||||
return
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
RootCAs: pool,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := client.Get("https://localhost:8080")
|
||||
if err != nil {
|
||||
fmt.Println("get error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
raw, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
fmt.Println("readall error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(">", string(raw))
|
||||
}
|
|
@ -0,0 +1,355 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"time"
|
||||
"os"
|
||||
"math/big"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/alexflint/go-arg"
|
||||
)
|
||||
|
||||
func run(args *Arguments) error {
|
||||
switch args.Type {
|
||||
case "root":
|
||||
return selfSign(args.Name)
|
||||
case "server":
|
||||
if args.Signing == "" {
|
||||
return fmt.Errorf("Signing key required")
|
||||
}
|
||||
return serverCert(args.Name, args.Signing)
|
||||
case "client":
|
||||
if args.Signing == "" {
|
||||
return fmt.Errorf("Signing key required")
|
||||
}
|
||||
return clientCert(args.Name, args.Signing)
|
||||
|
||||
case "verify":
|
||||
//if args.Signing == "" {
|
||||
// return fmt.Errorf("root cert required")
|
||||
//}
|
||||
return verify(args.Name, args.Signing)
|
||||
}
|
||||
|
||||
return fmt.Errorf("unknown type: %s", args.Type)
|
||||
}
|
||||
|
||||
func verify(target, root string) error {
|
||||
rawcert, err := os.ReadFile(target+".pem")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(rawcert)
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("cert pubkey type: %T\n", cert.PublicKey)
|
||||
switch k := cert.PublicKey.(type) {
|
||||
case *rsa.PublicKey:
|
||||
size := k.N.BitLen();
|
||||
pub := cert.PublicKey.(*rsa.PublicKey)
|
||||
fmt.Printf("pubkey size: %d (%d)\n", pub.Size(), size)
|
||||
default:
|
||||
}
|
||||
|
||||
pool := x509.NewCertPool()
|
||||
//rawroot, err := os.ReadFile(root+".pem")
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
|
||||
//block, _ := pem.Decode(rawroot)
|
||||
//rootcert, err := x509.ParseCertificate(block.Bytes)
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
if root != "" {
|
||||
fmt.Println("loading "+root+".pem")
|
||||
rootRaw, err := os.ReadFile(root+".pem")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !pool.AppendCertsFromPEM(rootRaw) {
|
||||
return fmt.Errorf("add pem not ok")
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("primary: %d (%08b)\n", cert.KeyUsage, cert.KeyUsage)
|
||||
for _, usage := range cert.ExtKeyUsage {
|
||||
fmt.Printf("> %d (%08b)\n", usage, usage)
|
||||
}
|
||||
|
||||
chains, err := cert.Verify(x509.VerifyOptions{
|
||||
Roots: pool,
|
||||
KeyUsages: []x509.ExtKeyUsage{
|
||||
x509.ExtKeyUsageClientAuth,
|
||||
},
|
||||
})
|
||||
fmt.Println("len(chains):", len(chains))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("verify OK")
|
||||
return nil
|
||||
}
|
||||
|
||||
func selfSign(name string) error {
|
||||
notBefore := time.Now()
|
||||
notAfter := notBefore.Add(90*24*time.Hour)
|
||||
|
||||
/*
|
||||
Root Cert
|
||||
*/
|
||||
rootkey, err := rsa.GenerateKey(rand.Reader, 4096)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.WriteFile(name+".key", pem.EncodeToMemory(&pem.Block{Type:"RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(rootkey)}), 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rootTemplate := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{"Zorchenhimer LLC"},
|
||||
CommonName: "Root CA",
|
||||
},
|
||||
NotBefore: notBefore,
|
||||
NotAfter: notAfter,
|
||||
KeyUsage: x509.KeyUsageCertSign,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
}
|
||||
|
||||
rootcert, err := x509.CreateCertificate(rand.Reader, rootTemplate, rootTemplate, &rootkey.PublicKey, rootkey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.WriteFile(name+".pem", pem.EncodeToMemory(
|
||||
&pem.Block{
|
||||
Type:"CERTIFICATE",
|
||||
Bytes: rootcert,
|
||||
}), 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadRoot(name string) (*x509.Certificate, *pem.Block, *rsa.PrivateKey, error) {
|
||||
rawroot, err := os.ReadFile(name+".pem")
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
rootpem, _ := pem.Decode(rawroot)
|
||||
rootcert, err := x509.ParseCertificate(rootpem.Bytes)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
rawkey, err := os.ReadFile(name+".key")
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(rawkey)
|
||||
rootkey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
return rootcert, rootpem, rootkey, nil
|
||||
}
|
||||
|
||||
func serverCert(name, rootname string) error {
|
||||
rootcert, _, rootkey, err := loadRoot(rootname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notBefore := time.Now()
|
||||
notAfter := notBefore.Add(90*24*time.Hour)
|
||||
|
||||
/*
|
||||
Server Cert
|
||||
*/
|
||||
|
||||
serverkey, err := rsa.GenerateKey(rand.Reader, 4096)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.WriteFile(name+".key",
|
||||
pem.EncodeToMemory(&pem.Block{
|
||||
Type:"RSA PRIVATE KEY",
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(serverkey),
|
||||
}), 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serverTemplate := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(2),
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{"Zorchenhimer LLC"},
|
||||
CommonName: "Server Cert",
|
||||
},
|
||||
NotBefore: notBefore,
|
||||
NotAfter: notAfter,
|
||||
KeyUsage: x509.KeyUsageDigitalSignature |
|
||||
x509.KeyUsageKeyEncipherment,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{
|
||||
x509.ExtKeyUsageServerAuth,
|
||||
x509.ExtKeyUsageClientAuth,
|
||||
},
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: false,
|
||||
|
||||
DNSNames: []string{
|
||||
"localhost",
|
||||
"ryuko.local",
|
||||
},
|
||||
IPAddresses: []net.IP{
|
||||
net.ParseIP("127.0.0.1"),
|
||||
net.ParseIP("192.168.1.10"),
|
||||
},
|
||||
}
|
||||
|
||||
servercert, err := x509.CreateCertificate(
|
||||
rand.Reader, serverTemplate, rootcert, &serverkey.PublicKey, rootkey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.WriteFile(name+".pem",
|
||||
pem.EncodeToMemory(&pem.Block{Type:"CERTIFICATE", Bytes: servercert}), 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func clientCert(name, root string) error {
|
||||
rootcert, rootblock, rootkey, err := loadRoot(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notBefore := time.Now()
|
||||
notAfter := notBefore.Add(90*24*time.Hour)
|
||||
|
||||
/*
|
||||
Client Cert
|
||||
*/
|
||||
|
||||
clientkey, err := rsa.GenerateKey(rand.Reader, 4096)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.WriteFile(name+".key", pem.EncodeToMemory(
|
||||
&pem.Block{
|
||||
Type:"RSA PRIVATE KEY",
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(clientkey),
|
||||
}), 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientTemplate := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(3),
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{"Zorchenhimer LLC"},
|
||||
CommonName: "Client Cert",
|
||||
},
|
||||
NotBefore: notBefore,
|
||||
NotAfter: notAfter,
|
||||
//KeyUsage: x509.KeyUsageDigitalSignature |
|
||||
// x509.KeyUsageDataEncipherment |
|
||||
// x509.KeyUsageKeyEncipherment |
|
||||
// x509.KeyUsageContentCommitment |
|
||||
// x509.KeyUsageKeyAgreement,
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment |
|
||||
x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{
|
||||
//x509.ExtKeyUsageAny,
|
||||
x509.ExtKeyUsageClientAuth,
|
||||
},
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: false,
|
||||
IPAddresses: []net.IP{
|
||||
net.ParseIP("127.0.0.1"),
|
||||
},
|
||||
}
|
||||
|
||||
clientcert, err := x509.CreateCertificate(
|
||||
rand.Reader, clientTemplate, rootcert, &clientkey.PublicKey, rootkey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file, err := os.Create(name+".pem")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
err = pem.Encode(file, &pem.Block{
|
||||
Type:"CERTIFICATE",
|
||||
Bytes: clientcert,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//err = pem.Encode(file, &pem.Block{
|
||||
// Type: "PUBLIC KEY",
|
||||
// Bytes: clientkey.Pubkey
|
||||
//})
|
||||
|
||||
err = pem.Encode(file, rootblock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//err = os.WriteFile(name+".pem",
|
||||
// pem.EncodeToMemory(&pem.Block{Type:"CERTIFICATE", Bytes: clientcert}), 0700)
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Arguments struct {
|
||||
Type string `arg:"positional,required"`
|
||||
Name string `arg:"positional,required"`
|
||||
Signing string `arg:"positional"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
args := &Arguments{}
|
||||
arg.MustParse(args)
|
||||
|
||||
err := run(args)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
mux := &http.ServeMux{}
|
||||
mux.HandleFunc("/", handle_default)
|
||||
|
||||
serverCert, err := tls.LoadX509KeyPair("certs/server.pem", "certs/server.key")
|
||||
if err != nil {
|
||||
fmt.Println("cert load error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
rootRaw, err := os.ReadFile("certs/root.pem")
|
||||
if err != nil {
|
||||
fmt.Println("root cert read error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
pool := x509.NewCertPool()
|
||||
if !pool.AppendCertsFromPEM(rootRaw) {
|
||||
fmt.Println("add pem not ok")
|
||||
return
|
||||
}
|
||||
|
||||
sv := &http.Server{
|
||||
Addr: ":8080",
|
||||
Handler: mux,
|
||||
TLSConfig: &tls.Config{
|
||||
MinVersion: tls.VersionTLS13,
|
||||
PreferServerCipherSuites: true,
|
||||
Certificates: []tls.Certificate{serverCert},
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
//ClientAuth: tls.RequireAnyClientCert,
|
||||
ClientCAs: pool,
|
||||
},
|
||||
}
|
||||
|
||||
//sv.ListenAndServeTLS("certs/server.crt", "certs/server.key")
|
||||
fmt.Println("starting...")
|
||||
err = sv.ListenAndServeTLS("", "")
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
func handle_default(w http.ResponseWriter, req *http.Request) {
|
||||
fmt.Fprintln(w, "hello.")
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"encoding/pem"
|
||||
"crypto/x509"
|
||||
|
||||
"github.com/alexflint/go-arg"
|
||||
)
|
||||
|
||||
func run(args *Arguments) error {
|
||||
raw, err := os.ReadFile(args.Input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
block, rest := pem.Decode(raw)
|
||||
fmt.Println(block.Type)
|
||||
fmt.Println("len(rest):", len(rest))
|
||||
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(cert)
|
||||
return nil
|
||||
}
|
||||
|
||||
type Arguments struct {
|
||||
Input string `arg:"positional,required"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
args := &Arguments{}
|
||||
arg.MustParse(args)
|
||||
|
||||
err := run(args)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue