diff --git a/app.go b/app.go index 0b55b6fa..07c67916 100644 --- a/app.go +++ b/app.go @@ -178,13 +178,13 @@ func run(args options) { } address := net.JoinHostPort(config.BindHost, strconv.Itoa(config.TLS.PortHTTPS)) // validate current TLS config and update warnings (it could have been loaded from file) - data := validateCertificates(config.TLS) + data := validateCertificates(config.TLS.CertificateChain, config.TLS.PrivateKey, config.TLS.ServerName) if !data.usable { log.Fatal(data.WarningValidation) os.Exit(1) } config.Lock() - config.TLS = data // update warnings + config.TLS.tlsConfigStatus = data // update warnings config.Unlock() // prepare certs for HTTPS server diff --git a/control.go b/control.go index fd1759e3..f6b4bab1 100644 --- a/control.go +++ b/control.go @@ -1025,7 +1025,7 @@ func handleTLSValidate(w http.ResponseWriter, r *http.Request) { } } - data = validateCertificates(data) + data.tlsConfigStatus = validateCertificates(data.CertificateChain, data.PrivateKey, data.ServerName) marshalTLS(w, data) } @@ -1051,7 +1051,7 @@ func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { } restartHTTPS := false - data = validateCertificates(data) + data.tlsConfigStatus = validateCertificates(data.CertificateChain, data.PrivateKey, data.ServerName) if !reflect.DeepEqual(config.TLS.tlsConfigSettings, data.tlsConfigSettings) { log.Printf("tls config settings have changed, will restart HTTPS server") restartHTTPS = true @@ -1078,21 +1078,24 @@ func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { } } -func validateCertificates(data tlsConfig) tlsConfig { +/* Process certificate data and its private key. +CertificateChain, PrivateKey parameters are optional. +On error, return partially set object + with 'WarningValidation' field containing error description. +*/ +func validateCertificates(CertificateChain, PrivateKey, ServerName string) tlsConfigStatus { var err error - - // clear out status for certificates - data.tlsConfigStatus = tlsConfigStatus{} + var data tlsConfigStatus // check only public certificate separately from the key - if data.CertificateChain != "" { - log.Tracef("got certificate: %s", data.CertificateChain) + if CertificateChain != "" { + log.Tracef("got certificate: %s", CertificateChain) // now do a more extended validation var certs []*pem.Block // PEM-encoded certificates var skippedBytes []string // skipped bytes - pemblock := []byte(data.CertificateChain) + pemblock := []byte(CertificateChain) for { var decoded *pem.Block decoded, pemblock = pem.Decode(pemblock) @@ -1127,7 +1130,7 @@ func validateCertificates(data tlsConfig) tlsConfig { // spew.Dump(parsedCerts) opts := x509.VerifyOptions{ - DNSName: data.ServerName, + DNSName: ServerName, } log.Printf("number of certs - %d", len(parsedCerts)) @@ -1164,13 +1167,13 @@ func validateCertificates(data tlsConfig) tlsConfig { } // validate private key (right now the only validation possible is just parsing it) - if data.PrivateKey != "" { + if PrivateKey != "" { // now do a more extended validation var key *pem.Block // PEM-encoded certificates var skippedBytes []string // skipped bytes // go through all pem blocks, but take first valid pem block and drop the rest - pemblock := []byte(data.PrivateKey) + pemblock := []byte(PrivateKey) for { var decoded *pem.Block decoded, pemblock = pem.Decode(pemblock) @@ -1202,8 +1205,8 @@ func validateCertificates(data tlsConfig) tlsConfig { } // if both are set, validate both in unison - if data.PrivateKey != "" && data.CertificateChain != "" { - _, err = tls.X509KeyPair([]byte(data.CertificateChain), []byte(data.PrivateKey)) + if PrivateKey != "" && CertificateChain != "" { + _, err = tls.X509KeyPair([]byte(CertificateChain), []byte(PrivateKey)) if err != nil { data.WarningValidation = fmt.Sprintf("Invalid certificate or key: %s", err) return data diff --git a/control_test.go b/control_test.go index 725457b9..c5df3b45 100644 --- a/control_test.go +++ b/control_test.go @@ -10,12 +10,10 @@ import ( . Bad private key . Valid certificate & private key */ func TestValidateCertificates(t *testing.T) { - var data tlsConfig + var data tlsConfigStatus // bad cert - data.CertificateChain = "bad cert" - data.PrivateKey = "" - data = validateCertificates(data) + data = validateCertificates("bad cert", "", "") if !(data.WarningValidation != "" && !data.ValidCert && !data.ValidChain) { @@ -23,16 +21,14 @@ func TestValidateCertificates(t *testing.T) { } // bad priv key - data.CertificateChain = "" - data.PrivateKey = "bad priv key" - data = validateCertificates(data) + data = validateCertificates("", "bad priv key", "") if !(data.WarningValidation != "" && !data.ValidKey) { t.Fatalf("bad priv key: validateCertificates(): %v", data) } // valid cert & priv key - data.CertificateChain = `-----BEGIN CERTIFICATE----- + CertificateChain := `-----BEGIN CERTIFICATE----- MIICKzCCAZSgAwIBAgIJAMT9kPVJdM7LMA0GCSqGSIb3DQEBCwUAMC0xFDASBgNV BAoMC0FkR3VhcmQgTHRkMRUwEwYDVQQDDAxBZEd1YXJkIEhvbWUwHhcNMTkwMjI3 MDkyNDIzWhcNNDYwNzE0MDkyNDIzWjAtMRQwEgYDVQQKDAtBZEd1YXJkIEx0ZDEV @@ -46,7 +42,7 @@ LwlXfbakf7qkVTlCNXgoY7RaJ8rJdPgOZPoCTVToEhT6u/cb1c2qp8QB0dNExDna b0Z+dnODTZqQOJo6z/wIXlcUrnR4cQVvytXt8lFn+26l6Y6EMI26twC/xWr+1swq Muj4FeWHVDerquH4yMr1jsYLD3ci+kc5sbIX6TfVxQ== -----END CERTIFICATE-----` - data.PrivateKey = `-----BEGIN PRIVATE KEY----- + PrivateKey := `-----BEGIN PRIVATE KEY----- MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALC/BSc8mI68tw5p aYa7pjrySwWvXeetcFywOWHGVfLw9qiFWLdfESa3Y6tWMpZAXD9t1Xh9n211YUBV FGSB4ZshnM/tgEPU6t787lJD4NsIIRp++MkJxdAitN4oUTqL0bdpIwezQ/CrYuBX @@ -62,7 +58,7 @@ O5EX70gpeGQMPDK0QSWpaazg956njJSDbNCFM4BccrdQbJu1cW4qOsfBAkAMgZuG O88slmgTRHX4JGFmy3rrLiHNI2BbJSuJ++Yllz8beVzh6NfvuY+HKRCmPqoBPATU kXS9jgARhhiWXJrk -----END PRIVATE KEY-----` - data = validateCertificates(data) + data = validateCertificates(CertificateChain, PrivateKey, "") notBefore, _ := time.Parse(time.RFC3339, "2019-02-27T09:24:23Z") notAfter, _ := time.Parse(time.RFC3339, "2046-07-14T09:24:23Z") if !(data.WarningValidation != "" /* self signed */ &&