community-website/main.go

113 lines
2.7 KiB
Go
Raw Normal View History

package main
import (
"bytes"
"crypto/tls"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os/exec"
"time"
)
type signCertificate struct{}
type requestData struct {
Csr string `json:"csr"`
CommonName string `json:"commonName"`
}
type responseData struct {
Certificate string `json:"certificate"`
}
func (h *signCertificate) sign(csrPem string, commonName string) (certPem string, err error) {
log.Printf("received CSR for %s:\n\n%s", commonName, csrPem)
subjectDN := fmt.Sprintf("/CN=%s", commonName)
err = ioutil.WriteFile("in.pem", []byte(csrPem), 0644)
if err != nil {
log.Print(err)
return
}
opensslCommand := exec.Command(
"openssl", "ca", "-config", "ca.cnf", "-days", "365",
"-policy", "policy_match", "-extensions", "client_ext",
"-batch", "-subj", subjectDN, "-utf8", "-rand_serial", "-in", "in.pem")
var out, cmdErr bytes.Buffer
opensslCommand.Stdout = &out
opensslCommand.Stderr = &cmdErr
err = opensslCommand.Run()
if err != nil {
log.Print(err)
log.Print(cmdErr.String())
return
}
certPem = out.String()
return
}
func (h *signCertificate) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Only POST requests support", http.StatusMethodNotAllowed)
return
}
if r.Header.Get("content-type") != "application/json" {
http.Error(w, "Only JSON content is accepted", http.StatusNotAcceptable)
return
}
var err error
var requestBody requestData
var certificate string
if err = json.NewDecoder(r.Body).Decode(&requestBody); err != nil {
log.Print(err)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
certificate, err = h.sign(requestBody.Csr, requestBody.CommonName)
if err != nil {
http.Error(w, "Could not sign certificate", http.StatusInternalServerError)
return
}
var jsonBytes []byte
if jsonBytes, err = json.Marshal(&responseData{Certificate: certificate}); err != nil {
log.Print(err)
}
if _, err = w.Write(jsonBytes); err != nil {
log.Print(err)
}
}
func main() {
tlsConfig := &tls.Config{
CipherSuites: []uint16{
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
},
NextProtos: []string{"h2"},
PreferServerCipherSuites: true,
MinVersion: tls.VersionTLS12,
}
mux := http.NewServeMux()
mux.Handle("/", http.FileServer(http.Dir("public")))
mux.Handle("/sign/", &signCertificate{})
server := http.Server{
Addr: ":8000",
Handler: mux,
TLSConfig: tlsConfig,
ReadTimeout: 20 * time.Second,
ReadHeaderTimeout: 5 * time.Second,
WriteTimeout: 30 * time.Second,
IdleTimeout: 30 * time.Second,
}
err := server.ListenAndServeTLS("server.crt.pem", "server.key.pem")
if err != nil {
log.Fatal(err)
}
}