add ACME certificate support

This commit is contained in:
Victor Vrantchan
2017-03-16 05:51:42 +00:00
parent 28219fcec2
commit af8e19aeac
3 changed files with 117 additions and 19 deletions

2
.gitignore vendored
View File

@@ -1 +1,3 @@
vendor/
SCEPCACert.pem
mdm.db

View File

@@ -1,5 +1,5 @@
{
"memo": "d051154535b215b85193b9d45b252749d3ee8caa79ccd69e88feedc5490e7416",
"memo": "8ec26b54331ccbcbe914255b2e955a9f4aa1769f53accd011025f5ae2e986e4c",
"projects": [
{
"name": "github.com/RobotsAndPencils/buford",
@@ -7,6 +7,7 @@
"revision": "d6d71aff1447ced56016d09a5d74f4ea488a2d75",
"packages": [
"payload",
"payload/badge",
"push"
]
},
@@ -25,6 +26,7 @@
"packages": [
"endpoint",
"log",
"metrics",
"transport/http"
]
},
@@ -46,8 +48,8 @@
},
{
"name": "github.com/gogo/protobuf",
"version": "v0.3",
"revision": "909568be09de550ed094403c2bf8a261b5bb730a",
"version": "v0.4",
"revision": "100ba4e885062801d56799d78530b73b178a78f3",
"packages": [
"proto"
]
@@ -55,7 +57,7 @@
{
"name": "github.com/golang/protobuf",
"branch": "master",
"revision": "8ee79997227bf9b34611aee7946ae64735e6fd93",
"revision": "c9c7427a2a70d2eb3bafa0ab2dc163e45f143317",
"packages": [
"proto"
]
@@ -79,7 +81,7 @@
{
"name": "github.com/groob/plist",
"branch": "master",
"revision": "a4f34fbabd9152a2140daa4a93606ee2ce868b98",
"revision": "43f06cf03cbc5bd95dd0ba102ac68efab25e1c65",
"packages": [
"."
]
@@ -103,9 +105,12 @@
{
"name": "github.com/micromdm/scep",
"branch": "master",
"revision": "083238ccae1d8bf63e82cf4f6d1c198feeb5294a",
"revision": "1b9e502944245d1d526ad49d39e7d7d3afd5e927",
"packages": [
"depot",
"depot/bolt",
"scep",
"scep/internal/pkcs7",
"server"
]
},
@@ -128,25 +133,31 @@
{
"name": "golang.org/x/crypto",
"branch": "master",
"revision": "854ae91cdcbf914b499b1d7641d07859f3653481",
"revision": "728b753d0135da6801d45a38e6f43ff55779c5c2",
"packages": [
"pkcs12"
"acme",
"acme/autocert",
"pkcs12",
"pkcs12/internal/rc2"
]
},
{
"name": "golang.org/x/net",
"branch": "master",
"revision": "f2499483f923065a842d38eb4c7f1927e6fc6e6d",
"revision": "a6577fac2d73be281a500b310739095313165611",
"packages": [
"context",
"context/ctxhttp",
"http2"
"http2",
"http2/hpack",
"idna",
"lex/httplex"
]
},
{
"name": "golang.org/x/sys",
"branch": "master",
"revision": "d75a52659825e75fff6158388dddc6a5b04f9ba5",
"revision": "99f16d856c9836c42d24e7ab64ea72916925fa97",
"packages": [
"unix"
]

101
main.go
View File

@@ -21,6 +21,7 @@ import (
"syscall"
"time"
"golang.org/x/crypto/acme/autocert"
"golang.org/x/crypto/pkcs12"
"github.com/RobotsAndPencils/buford/push"
@@ -48,10 +49,13 @@ func init() {
func main() {
var (
flServerURL = flag.String("server.url", "", "public HTTPS url of your server")
flAPNSCertPath = flag.String("apns.certificate", "mdm.p12", "path to APNS certificate")
flAPNSKeyPass = flag.String("apns.password", "secret", "password for your APNS cert file.")
flAPNSKeyPath = flag.String("apns.key", "", "path to key file if using .pem push cert")
flServerURL = flag.String("server-url", "", "public HTTPS url of your server")
flAPNSCertPath = flag.String("apns-certificate", "mdm.p12", "path to APNS certificate")
flAPNSKeyPass = flag.String("apns-password", "secret", "password for your APNS cert file.")
flAPNSKeyPath = flag.String("apns-key", "", "path to key file if using .pem push cert")
flTLS = flag.Bool("tls", true, "use https")
flTLSCert = flag.String("tls-cert", "", "path to TLS certificate")
flTLSKey = flag.String("tls-key", "", "path to TLS private key")
)
flag.Parse()
@@ -120,6 +124,21 @@ func main() {
r.Handle("/scep", scepHandler)
r.Handle("/push/{udid}", pushHandlers.PushHandler)
r.Handle("/v1/commands", commandHandlers.NewCommandHandler).Methods("POST")
srv := &http.Server{
Addr: ":https",
Handler: r,
ReadTimeout: 60 * time.Second,
WriteTimeout: 60 * time.Second,
ReadHeaderTimeout: 10 * time.Second,
IdleTimeout: 10 * time.Minute,
MaxHeaderBytes: 1 << 18, // 0.25 MB
TLSConfig: tlsConfig(),
}
srvURL, err := url.Parse(sm.ServerPublicURL)
if err != nil {
stdlog.Fatal(err)
}
errs := make(chan error, 2)
go func() {
@@ -129,15 +148,81 @@ func main() {
}()
go func() {
var httpAddr = "0.0.0.0:8080"
logger := log.NewContext(logger).With("transport", "HTTP")
logger.Log("addr", httpAddr)
errs <- http.ListenAndServe(
httpAddr, r)
if !*flTLS {
var httpAddr = "0.0.0.0:8080"
logger.Log("addr", httpAddr)
errs <- http.ListenAndServe(httpAddr, r)
return
}
tlsFromFile := (*flTLSCert != "" && *flTLSKey != "")
if tlsFromFile {
logger.Log("addr", srv.Addr)
errs <- serveTLS(srv, *flTLSCert, *flTLSKey)
return
} else {
logger.Log("addr", srv.Addr)
errs <- serveACME(srv, srvURL.Hostname())
return
}
}()
mainLogger.Log("terminated", <-errs)
}
func serveTLS(server *http.Server, certPath, keyPath string) error {
redirectTLS()
err := server.ListenAndServeTLS(certPath, keyPath)
return err
}
func serveACME(server *http.Server, domain string) error {
m := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist(domain),
Cache: autocert.DirCache("/var/db/le-certificates"),
}
server.TLSConfig.GetCertificate = m.GetCertificate
redirectTLS()
err := server.ListenAndServeTLS("", "")
return err
}
// redirects port 80 to port 443
func redirectTLS() {
srv := &http.Server{
ReadTimeout: 5 * time.Second,
WriteTimeout: 5 * time.Second,
Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Connection", "close")
url := "https://" + req.Host + req.URL.String()
http.Redirect(w, req, url, http.StatusMovedPermanently)
}),
}
go func() { stdlog.Fatal(srv.ListenAndServe()) }()
}
func tlsConfig() *tls.Config {
cfg := &tls.Config{
PreferServerCipherSuites: true,
CurvePreferences: []tls.CurveID{
tls.CurveP256,
tls.X25519,
},
MinVersion: tls.VersionTLS12,
CipherSuites: []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
},
}
return cfg
}
type config struct {
pubclient *pubsub.Inmem
db *bolt.DB