From d437b73a8c2dda9884c92d2be44727e66c2289e2 Mon Sep 17 00:00:00 2001 From: "kali kaneko (leap communications)" Date: Fri, 24 Jan 2020 21:19:19 -0600 Subject: refactor into cmd/pkg --- pkg/auth/middleware.go | 12 +++++++ pkg/config/main.go | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ pkg/web/certs.go | 84 +++++++++++++++++++++++++++++++++++++++++++ pkg/web/handlers.go | 19 ++++++++++ 4 files changed, 212 insertions(+) create mode 100644 pkg/auth/middleware.go create mode 100644 pkg/config/main.go create mode 100644 pkg/web/certs.go create mode 100644 pkg/web/handlers.go (limited to 'pkg') diff --git a/pkg/auth/middleware.go b/pkg/auth/middleware.go new file mode 100644 index 0000000..a3a955c --- /dev/null +++ b/pkg/auth/middleware.go @@ -0,0 +1,12 @@ +package auth + +import () + +import ( + "github.com/auth0/go-jwt-middleware" + jwt "github.com/dgrijalva/jwt-go" +) + +func getProtectedHandler() { + jwtMiddleware.Handler(CertHandler) +} diff --git a/pkg/config/main.go b/pkg/config/main.go new file mode 100644 index 0000000..142738d --- /dev/null +++ b/pkg/config/main.go @@ -0,0 +1,97 @@ +package config + +import ( + "flag" + "log" + "os" + "reflect" +) + +const DefaultAuthenticationModule = "anonymous" + +type Opts struct { + Notls bool + CaCrt string + CaKey string + TlsCrt string + TlsKey string + Port string + Auth string +} + +func (o *Opts) fallbackToEnv(field string, envVar string, defaultVal string) { + r := reflect.ValueOf(o) + f := reflect.Indirect(r).FieldByName(field) + + if f.String() == "" { + val, exists := os.LookupEnv(envVar) + if exists && val != "" { + f.SetString(val) + } else { + f.SetString(defaultVal) + } + } +} + +func doCaFilesSanityCheck(caCrt string, caKey string) { + if _, err := os.Stat(caCrt); os.IsNotExist(err) { + log.Fatal("cannot find caCrt file") + } + if _, err := os.Stat(caKey); os.IsNotExist(err) { + log.Fatal("cannot find caKey file") + } +} + +func doTlsFilesSanityCheck(tlsCrt string, tlsKey string) { + if _, err := os.Stat(tlsCrt); os.IsNotExist(err) { + log.Fatal("cannot find tlsCrt file") + } + if _, err := os.Stat(tlsKey); os.IsNotExist(err) { + log.Fatal("cannot find tlsKey file") + } +} + +func InitializeFlags(opts *Opts) { + flag.BoolVar(&opts.Notls, "notls", false, "disable TLS on the service") + flag.StringVar(&opts.CaCrt, "caCrt", "", "path to the CA public key") + flag.StringVar(&opts.CaKey, "caKey", "", "path to the CA private key") + flag.StringVar(&opts.TlsCrt, "tls_crt", "", "path to the cert file for TLS") + flag.StringVar(&opts.TlsKey, "tls_key", "", "path to the key file for TLS") + flag.StringVar(&opts.Port, "port", "", "port where the server will listen (default: 8000)") + flag.StringVar(&opts.Auth, "auth", "", "authentication module (anonymous, sip)") + flag.Parse() + + opts.fallbackToEnv("CaCrt", "VPNWEB_CACRT", "") + opts.fallbackToEnv("CaKey", "VPNWEB_CAKEY", "") + opts.fallbackToEnv("TlsCrt", "VPNWEB_TLSCRT", "") + opts.fallbackToEnv("TlsKey", "VPNWEB_TLSKEY", "") + opts.fallbackToEnv("Port", "VPNWEB_PORT", "8000") + opts.fallbackToEnv("Auth", "VPNWEB_AUTH", DefaultAuthenticationModule) +} + +func CheckConfigurationOptions(opts *Opts) { + if opts.CaCrt == "" { + log.Fatal("missing caCrt parameter") + } + if opts.CaKey == "" { + log.Fatal("missing caKey parameter") + } + + if opts.Notls == false { + if opts.TlsCrt == "" { + log.Fatal("missing tls_crt parameter. maybe use -notls?") + } + if opts.TlsKey == "" { + log.Fatal("missing tls_key parameter. maybe use -notls?") + } + } + + doCaFilesSanityCheck(opts.CaCrt, opts.CaKey) + if opts.Notls == false { + doTlsFilesSanityCheck(opts.TlsCrt, opts.TlsKey) + } + + log.Println("Authentication module:", opts.Auth) + + // TODO -- check authentication module is valud, bail out otherwise +} diff --git a/pkg/web/certs.go b/pkg/web/certs.go new file mode 100644 index 0000000..8c5d423 --- /dev/null +++ b/pkg/web/certs.go @@ -0,0 +1,84 @@ +package web + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "io" + "math/big" + mrand "math/rand" + "time" +) + +const keySize = 2048 +const expiryDays = 28 +const certPrefix = "UNLIMITED" + +var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz") + +func randStringRunes(n int) string { + b := make([]rune, n) + for i := range b { + b[i] = letterRunes[mrand.Intn(len(letterRunes))] + } + return string(b) +} + +type caInfo struct { + cacrt, cakey string +} + +func NewCaInfo(cacrt string, cakey string) caInfo { + return caInfo{cacrt, cakey} +} + +// CertWriter main handler + +func (ci *caInfo) CertWriter(out io.Writer) { + catls, err := tls.LoadX509KeyPair(ci.cacrt, ci.cakey) + + if err != nil { + panic(err) + } + ca, err := x509.ParseCertificate(catls.Certificate[0]) + if err != nil { + panic(err) + } + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + + subjectKeyID := make([]byte, 20) + rand.Read(subjectKeyID) + + _ = randStringRunes(25) + // Prepare certificate + cert := &x509.Certificate{ + SerialNumber: serialNumber, + + Subject: pkix.Name{ + //CommonName: certPrefix + randStringRunes(25), + CommonName: certPrefix, + }, + NotBefore: time.Now().AddDate(0, 0, -7), + NotAfter: time.Now().AddDate(0, 0, expiryDays), + + SubjectKeyId: subjectKeyID, + + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, + KeyUsage: x509.KeyUsageDigitalSignature, + } + priv, _ := rsa.GenerateKey(rand.Reader, keySize) + pub := &priv.PublicKey + + // Sign the certificate + certB, err := x509.CreateCertificate(rand.Reader, cert, ca, pub, catls.PrivateKey) + + // Write the private Key + pem.Encode(out, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}) + + // Write the public key + pem.Encode(out, &pem.Block{Type: "CERTIFICATE", Bytes: certB}) +} diff --git a/pkg/web/handlers.go b/pkg/web/handlers.go new file mode 100644 index 0000000..c4f2e9a --- /dev/null +++ b/pkg/web/handlers.go @@ -0,0 +1,19 @@ +package web + +import ( + "net/http" +) + +type CertHandler struct { + Cainfo caInfo +} + +func (ch *CertHandler) CertResponder(w http.ResponseWriter, r *http.Request) { + ch.Cainfo.CertWriter(w) +} + +func HttpFileHandler(route string, path string) { + http.HandleFunc(route, func(w http.ResponseWriter, r *http.Request) { + http.ServeFile(w, r, path) + }) +} -- cgit v1.2.3