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