diff --git a/checkcrl b/checkcrl index 53b6af2..8cf9c5f 100755 --- a/checkcrl +++ b/checkcrl @@ -2,6 +2,15 @@ set -e +if [ -e data/root-ca.crl ] && [ ! -e /var/www/html/crl/root-ca.crl ]; then + cp -p data/root-ca.crl /var/www/html/crl/root-ca.crl + touch /var/www/html/crl +fi +if [ -e data/root-ca.crl ] && [ data/root-ca.crl -nt /var/www/html/crl/root-ca.crl ]; then + cp -p data/root-ca.crl /var/www/html/crl/root-ca.crl + touch /var/www/html/crl +fi + cd /var/www/html if [ crl/ -nt certs/index.html ]; then echo "Updating certs/index.html with latest CRL info..." diff --git a/commander b/commander index aef9f03..9c92e62 100755 --- a/commander +++ b/commander @@ -239,6 +239,14 @@ case $txt in nohup /labca/install -b $branch &>>$LOGFILE fi ;; +"gen-issuer-crl") + cd /opt/boulder + docker compose exec -i boulder ./bin/boulder crl-updater --config labca/config/crl-updater.json -runOnce -debug-addr :18021 &>>$LOGFILE + /opt/labca/checkcrl &>>$LOGFILE + ;; +"check-crl") + /opt/labca/checkcrl &>>$LOGFILE + ;; *) echo "Unknown command '$txt'. ERROR!" exit 1 diff --git a/gui/apply-boulder b/gui/apply-boulder index d5dc047..6274b44 100755 --- a/gui/apply-boulder +++ b/gui/apply-boulder @@ -183,6 +183,9 @@ rm -f test-root.p8 if [ -e $PKI_INT_CERT_BASE.key ]; then cp -p $PKI_INT_CERT_BASE.key test-ca.key + if [ ! -e $PKI_INT_CERT_BASE.key.der ]; then + openssl pkey -in $PKI_INT_CERT_BASE.key -out $PKI_INT_CERT_BASE.key.der -outform der + fi cp -p $PKI_INT_CERT_BASE.key.der test-ca.key.der cp -p $PKI_INT_CERT_BASE.pem test-ca.pem openssl rsa -in $PKI_INT_CERT_BASE.key -pubout > test-ca.pubkey.pem 2>/dev/null || openssl ec -in $PKI_INT_CERT_BASE.key -pubout > test-ca.pubkey.pem @@ -190,6 +193,9 @@ if [ -e $PKI_INT_CERT_BASE.key ]; then fi if [ -e $PKI_ROOT_CERT_BASE.key ]; then cp -p $PKI_ROOT_CERT_BASE.key test-root.key + if [ ! -e $PKI_ROOT_CERT_BASE.key.der ]; then + openssl pkey -in $PKI_ROOT_CERT_BASE.key -out $PKI_ROOT_CERT_BASE.key.der -outform der + fi cp -p $PKI_ROOT_CERT_BASE.key.der test-root.key.der openssl rsa -in $PKI_ROOT_CERT_BASE.key -pubout > test-root.pubkey.pem 2>/dev/null || openssl ec -in $PKI_ROOT_CERT_BASE.key -pubout > test-root.pubkey.pem openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in test-root.key -out test-root.p8 diff --git a/gui/certificate.go b/gui/certificate.go index 5111244..00ee587 100644 --- a/gui/certificate.go +++ b/gui/certificate.go @@ -664,7 +664,6 @@ func (ci *CertificateInfo) Create(path string, certBase string, wasCSR bool) err keyFileExists = false } if keyFileExists { - // TODO: make option in GUI to trigger crl creation! if _, err := exeCmd("openssl ca -config " + path + "openssl.cnf -gencrl -keyfile " + path + certBase + ".key -cert " + path + certBase + ".pem -out " + path + certBase + ".crl"); err != nil { return reportError(err) } diff --git a/gui/main.go b/gui/main.go index 2e7493f..72b266e 100644 --- a/gui/main.go +++ b/gui/main.go @@ -1039,6 +1039,95 @@ func _checkUpdatesHandler(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(res) } +func generateCRLHandler(w http.ResponseWriter, r *http.Request, isRoot bool) { + res := struct { + Success bool + Errors map[string]string + }{Success: true, Errors: make(map[string]string)} + + if isRoot { + path := "data/" + certBase := "root-ca" + keyFileExists := true + if _, err := os.Stat(path + certBase + ".key"); os.IsNotExist(err) { + keyFileExists = false + } + if keyFileExists { + if _, err := exeCmd("openssl ca -config " + path + "openssl.cnf -gencrl -keyfile " + path + certBase + ".key -cert " + path + certBase + ".pem -out " + path + certBase + ".crl"); err != nil { + res.Success = false + res.Errors["CRL"] = "Could not generate Root CRL - see logs" + } + } else { + if r.Form.Get("rootkey") == "" { + res.Success = false + res.Errors["CRL"] = "NO_ROOT_KEY" + } else { + rootci := &CertificateInfo{ + IsRoot: true, + Key: r.Form.Get("rootkey"), + Passphrase: r.Form.Get("rootpassphrase"), + } + if !rootci.StoreRootKey(path) { + res.Success = false + res.Errors["CRL"] = rootci.Errors["Modal"] + } else { + // Generate CRL now that we have the key + if _, err := exeCmd("openssl ca -config " + path + "openssl.cnf -gencrl -keyfile " + path + certBase + ".key -cert " + path + certBase + ".pem -out " + path + certBase + ".crl"); err != nil { + res.Success = false + res.Errors["CRL"] = "Could not generate Root CRL - see logs" + } + // Remove the Root Key if we want to keep it offline + if viper.GetBool("keep_root_offline") { + if _, err := os.Stat(path + certBase + ".key"); !os.IsNotExist(err) { + fmt.Println("Removing private Root key from the system...") + if _, err := exeCmd("rm " + path + certBase + ".key"); err != nil { + log.Printf("_certCreate: error deleting root key: %v", err) + } + } + if _, err := os.Stat(path + certBase + ".key.der"); !os.IsNotExist(err) { + if _, err := exeCmd("rm " + path + certBase + ".key.der"); err != nil { + log.Printf("_certCreate: error deleting root key (DER format): %v", err) + } + } + } + } + } + } + + _hostCommand(w, r, "check-crl") + + } else { // !isRoot + if !_hostCommand(w, r, "gen-issuer-crl") { + res.Success = false + res.Errors["CRL"] = "Failed to generate CRL - see logs" + } + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(res) +} + +func uploadCRLHandler(w http.ResponseWriter, r *http.Request) { + res := struct { + Success bool + Errors map[string]string + }{Success: true, Errors: make(map[string]string)} + + rootci := &CertificateInfo{ + IsRoot: true, + CRL: r.Form.Get("crl"), + } + if !rootci.StoreCRL("data/") { + res.Success = false + res.Errors["CRL"] = rootci.Errors["Modal"] + } + + _hostCommand(w, r, "check-crl") + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(res) +} + func _managePostDispatch(w http.ResponseWriter, r *http.Request, action string) bool { if action == "backup-restore" || action == "backup-delete" || action == "backup-now" { _backupHandler(w, r) @@ -1080,6 +1169,21 @@ func _managePostDispatch(w http.ResponseWriter, r *http.Request, action string) return true } + if action == "upload-root-crl" { + uploadCRLHandler(w, r) + return true + } + + if action == "gen-root-crl" { + generateCRLHandler(w, r, true) + return true + } + + if action == "gen-issuer-crl" { + generateCRLHandler(w, r, false) + return true + } + return false } @@ -1113,6 +1217,9 @@ func _managePost(w http.ResponseWriter, r *http.Request) { "send-email", "version-check", "version-update", + "upload-root-crl", + "gen-root-crl", + "gen-issuer-crl", } { if a == action { actionKnown = true @@ -1599,7 +1706,8 @@ func _certCreate(w http.ResponseWriter, r *http.Request, certBase string, isRoot if r.Form.Get("revertroot") != "" { // From issuer certificate creation page it is possible to remove the root again and start over - exeCmd("rm data/root-ca.key") // Does not necessarily exist + exeCmd("rm data/root-ca.key") // Does not necessarily exist + exeCmd("rm data/root-ca.key.der") // Does not necessarily exist if _, err := exeCmd("rm data/root-ca.pem"); err != nil { errorHandler(w, r, err, http.StatusInternalServerError) return false @@ -1614,13 +1722,8 @@ func _certCreate(w http.ResponseWriter, r *http.Request, certBase string, isRoot } } else if r.Form.Get("ack-rootkey") == "yes" { // Root Key was shown, do we need to keep it online? - if r.Form.Get("keep-root-online") == "true" { - sess, _ := sessionStore.Get(r, "labca") - sess.Values["root-online"] = true - if err := sess.Save(r, w); err != nil { - log.Printf("cannot save session: %s\n", err) - } - } + viper.Set("keep_root_offline", r.Form.Get("keep-root-online") != "true") + viper.WriteConfig() // Undo what setupHandler did when showing the public key... _, errPem := os.Stat("data/root-ca.pem") @@ -1792,13 +1895,18 @@ func _certCreate(w http.ResponseWriter, r *http.Request, certBase string, isRoot log.Printf("_certCreate: could not calculate IssuerNameID: %v", err) } - if session.Values["root-online"] != true { + if viper.GetBool("keep_root_offline") { if _, err := os.Stat(path + "../root-ca.key"); !os.IsNotExist(err) { fmt.Println("Removing private Root key from the system...") if _, err := exeCmd("rm " + path + "../root-ca.key"); err != nil { log.Printf("_certCreate: error deleting root key: %v", err) } } + if _, err := os.Stat(path + "../root-ca.key.der"); !os.IsNotExist(err) { + if _, err := exeCmd("rm " + path + "../root-ca.key.der"); err != nil { + log.Printf("_certCreate: error deleting root key (DER format): %v", err) + } + } } } diff --git a/gui/templates/views/cert.tmpl b/gui/templates/views/cert.tmpl index 8261595..6ab86c9 100644 --- a/gui/templates/views/cert.tmpl +++ b/gui/templates/views/cert.tmpl @@ -170,7 +170,7 @@ step, we will delete the key from the system.
When we need the key for certain operations in the future, we will ask for it.

- Keep the root key on the LabCA server (UNSAFE)
+ Keep the root key on the LabCA server (INSECURE)
{{ with .CertificateInfo.Errors.Modal }} {{ . }}
{{ end }} @@ -199,7 +199,7 @@ {{ if .GetRootKey }}