commit 29860982d8ceb91da5d20563979e6b363eca526b
Author: Brian C. Lane <bcl@brianlane.com>
Date: Sat, 29 Feb 2020 08:39:24 -0800
Initial commit - working dir-server with TLS support
Diffstat:
A | main.go | | | 155 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 155 insertions(+), 0 deletions(-)
diff --git a/main.go b/main.go
@@ -0,0 +1,155 @@
+/*dir-server - simple http or https server for current directory
+
+ Copyright (C) 2019-2020 Brian C. Lane <bcl@brianlane.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+package main
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "flag"
+ "fmt"
+ "log"
+ "math/big"
+ "net/http"
+ "os"
+ "time"
+)
+
+type cmdlineArgs struct {
+ ListenIP string
+ ListenPort int
+ TLS bool
+ Cert string
+ Key string
+}
+
+var cfg = cmdlineArgs{
+ ListenIP: "0.0.0.0",
+ ListenPort: 8000,
+ TLS: false,
+ Cert: "/var/tmp/cert.pem",
+ Key: "/var/tmp/key.pem",
+}
+
+func init() {
+ flag.StringVar(&cfg.ListenIP, "ip", cfg.ListenIP, "IP Address to Listen to (0.0.0.0)")
+ flag.IntVar(&cfg.ListenPort, "port", cfg.ListenPort, "Port to listen to (8000)")
+ flag.BoolVar(&cfg.TLS, "tls", cfg.TLS, "Use https instead of http")
+ flag.StringVar(&cfg.Cert, "cert", cfg.Cert, "Path to temporary cert.pem")
+ flag.StringVar(&cfg.Key, "key", cfg.Key, "Path to temporary key.pem")
+
+ flag.Parse()
+}
+
+func publicKey(priv interface{}) interface{} {
+ switch k := priv.(type) {
+ case *ecdsa.PrivateKey:
+ return &k.PublicKey
+ default:
+ return nil
+ }
+}
+
+// This generates a self-signed cert good for 6 hours using ecdsa P256 curve
+func makeSelfSigned(cert, key string) {
+ hostname, err := os.Hostname()
+ if err != nil {
+ log.Fatalf("Error getting hostname: %s", err)
+ }
+
+ // these are temporary certs, only valid for 6 hours
+ notBefore := time.Now()
+ notAfter := notBefore.Add(6 * time.Hour)
+
+ var priv interface{}
+ priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ log.Fatalf("Failed to generate private key: %s", err)
+ }
+ serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+ if err != nil {
+ log.Fatalf("Failed to generate serial number: %s", err)
+ }
+ serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+
+ template := x509.Certificate{
+ SerialNumber: serialNumber,
+ Subject: pkix.Name{
+ Organization: []string{"Random Bits UNL"},
+ },
+ NotBefore: notBefore,
+ NotAfter: notAfter,
+ KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+ BasicConstraintsValid: true,
+ DNSNames: []string{hostname},
+ }
+ derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
+ if err != nil {
+ log.Fatalf("Failed to create certificate: %s", err)
+ }
+
+ certOut, err := os.Create(cert)
+ if err != nil {
+ log.Fatalf("Failed to open %s for writing: %s", cert, err)
+ }
+ if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
+ log.Fatalf("Failed to write data to cert.pem: %s", err)
+ }
+ if err := certOut.Close(); err != nil {
+ log.Fatalf("Error closing %s: %s", cert, err)
+ }
+ log.Printf("wrote %s\n", cert)
+
+ keyOut, err := os.OpenFile(key, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
+ if err != nil {
+ log.Fatalf("Failed to open %s for writing: %s", key, err)
+ }
+ privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
+ if err != nil {
+ log.Fatalf("Unable to marshal private key: %v", err)
+ }
+ if err := pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil {
+ log.Fatalf("Failed to write data to %s: %s", key, err)
+ }
+ if err := keyOut.Close(); err != nil {
+ log.Fatalf("Error closing %s: %s", key, err)
+ }
+ log.Printf("wrote %s\n", key)
+}
+
+func main() {
+ http.Handle("/", http.FileServer(http.Dir("./")))
+ listen := fmt.Sprintf("%s:%d", cfg.ListenIP, cfg.ListenPort)
+
+ if !cfg.TLS {
+ if err := http.ListenAndServe(listen, nil); err != nil {
+ panic(err)
+ }
+ } else {
+ makeSelfSigned(cfg.Cert, cfg.Key)
+ if err := http.ListenAndServeTLS(listen, cfg.Cert, cfg.Key, nil); err != nil {
+ panic(err)
+ }
+
+ }
+}