Add signer backend
This commit adds a simple go backend calling openssl ca to sign CRS coming from the client. The JavaScript code in src/index.html has been extended to send requests to the sign endpoint and display the resulting certificate in a separate div element. A script setup_example_ca.sh and an openssl configuration file ca.cnf has been added to allow quick setup of a simple example CA.main
parent
c751c51713
commit
5c3f0ea942
@ -1,4 +1,6 @@
|
||||
*.pem
|
||||
.*.swp
|
||||
/.idea/
|
||||
/exampleca/
|
||||
/node_modules/
|
||||
/public/
|
||||
|
@ -0,0 +1,31 @@
|
||||
extensions = v3_ext
|
||||
|
||||
[ca]
|
||||
default_ca = EXAMPLECA
|
||||
|
||||
[EXAMPLECA]
|
||||
dir = ./exampleca
|
||||
certs = $dir/certs
|
||||
crl_dir = $dir/crl
|
||||
database = $dir/index.txt
|
||||
new_certs_dir = $dir/newcerts
|
||||
serial = $dir/serial
|
||||
crl = $dir/crl.pem
|
||||
certificate = $dir/ca.crt.pem
|
||||
serial = $dir/serial
|
||||
crl = $dir/crl.pem
|
||||
private_key = $dir/private/ca.key.pem
|
||||
RANDFILE = $dir/private/.rand
|
||||
unique_subject = no
|
||||
email_in_dn = no
|
||||
default_md = sha256
|
||||
|
||||
[policy_match]
|
||||
commonName = supplied
|
||||
|
||||
[client_ext]
|
||||
basicConstraints = critical,CA:false
|
||||
keyUsage = keyEncipherment,digitalSignature,nonRepudiation
|
||||
extendedKeyUsage = clientAuth,emailProtection
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always,issuer:always
|
@ -0,0 +1,3 @@
|
||||
module git.dittberner.info/jan/browser_csr_generation
|
||||
|
||||
go 1.13
|
@ -0,0 +1,112 @@
|
||||
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)
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ ! -d "exampleca" ]; then
|
||||
mkdir -p exampleca/newcerts
|
||||
touch exampleca/index.txt
|
||||
umask 077
|
||||
mkdir exampleca/private
|
||||
openssl req -new -x509 -keyout exampleca/private/ca.key.pem -out exampleca/ca.crt.pem -days 3650 \
|
||||
-subj "/CN=Example CA" -nodes -newkey rsa:3072 -addext "basicConstraints=critical,CA:true,pathlen:0"
|
||||
chmod +r exampleca/ca.crt.pem
|
||||
fi
|
Loading…
Reference in New Issue