* validateCertificates(): change input parameters; added short description

This commit is contained in:
Simon Zolin 2019-02-27 14:11:41 +03:00
parent d218e047a3
commit 766fbab071
3 changed files with 25 additions and 26 deletions

4
app.go
View file

@ -178,13 +178,13 @@ func run(args options) {
} }
address := net.JoinHostPort(config.BindHost, strconv.Itoa(config.TLS.PortHTTPS)) address := net.JoinHostPort(config.BindHost, strconv.Itoa(config.TLS.PortHTTPS))
// validate current TLS config and update warnings (it could have been loaded from file) // 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 { if !data.usable {
log.Fatal(data.WarningValidation) log.Fatal(data.WarningValidation)
os.Exit(1) os.Exit(1)
} }
config.Lock() config.Lock()
config.TLS = data // update warnings config.TLS.tlsConfigStatus = data // update warnings
config.Unlock() config.Unlock()
// prepare certs for HTTPS server // prepare certs for HTTPS server

View file

@ -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) marshalTLS(w, data)
} }
@ -1051,7 +1051,7 @@ func handleTLSConfigure(w http.ResponseWriter, r *http.Request) {
} }
restartHTTPS := false restartHTTPS := false
data = validateCertificates(data) data.tlsConfigStatus = validateCertificates(data.CertificateChain, data.PrivateKey, data.ServerName)
if !reflect.DeepEqual(config.TLS.tlsConfigSettings, data.tlsConfigSettings) { if !reflect.DeepEqual(config.TLS.tlsConfigSettings, data.tlsConfigSettings) {
log.Printf("tls config settings have changed, will restart HTTPS server") log.Printf("tls config settings have changed, will restart HTTPS server")
restartHTTPS = true 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 var err error
var data tlsConfigStatus
// clear out status for certificates
data.tlsConfigStatus = tlsConfigStatus{}
// check only public certificate separately from the key // check only public certificate separately from the key
if data.CertificateChain != "" { if CertificateChain != "" {
log.Tracef("got certificate: %s", data.CertificateChain) log.Tracef("got certificate: %s", CertificateChain)
// now do a more extended validation // now do a more extended validation
var certs []*pem.Block // PEM-encoded certificates var certs []*pem.Block // PEM-encoded certificates
var skippedBytes []string // skipped bytes var skippedBytes []string // skipped bytes
pemblock := []byte(data.CertificateChain) pemblock := []byte(CertificateChain)
for { for {
var decoded *pem.Block var decoded *pem.Block
decoded, pemblock = pem.Decode(pemblock) decoded, pemblock = pem.Decode(pemblock)
@ -1127,7 +1130,7 @@ func validateCertificates(data tlsConfig) tlsConfig {
// spew.Dump(parsedCerts) // spew.Dump(parsedCerts)
opts := x509.VerifyOptions{ opts := x509.VerifyOptions{
DNSName: data.ServerName, DNSName: ServerName,
} }
log.Printf("number of certs - %d", len(parsedCerts)) 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) // validate private key (right now the only validation possible is just parsing it)
if data.PrivateKey != "" { if PrivateKey != "" {
// now do a more extended validation // now do a more extended validation
var key *pem.Block // PEM-encoded certificates var key *pem.Block // PEM-encoded certificates
var skippedBytes []string // skipped bytes var skippedBytes []string // skipped bytes
// go through all pem blocks, but take first valid pem block and drop the rest // go through all pem blocks, but take first valid pem block and drop the rest
pemblock := []byte(data.PrivateKey) pemblock := []byte(PrivateKey)
for { for {
var decoded *pem.Block var decoded *pem.Block
decoded, pemblock = pem.Decode(pemblock) decoded, pemblock = pem.Decode(pemblock)
@ -1202,8 +1205,8 @@ func validateCertificates(data tlsConfig) tlsConfig {
} }
// if both are set, validate both in unison // if both are set, validate both in unison
if data.PrivateKey != "" && data.CertificateChain != "" { if PrivateKey != "" && CertificateChain != "" {
_, err = tls.X509KeyPair([]byte(data.CertificateChain), []byte(data.PrivateKey)) _, err = tls.X509KeyPair([]byte(CertificateChain), []byte(PrivateKey))
if err != nil { if err != nil {
data.WarningValidation = fmt.Sprintf("Invalid certificate or key: %s", err) data.WarningValidation = fmt.Sprintf("Invalid certificate or key: %s", err)
return data return data

View file

@ -10,12 +10,10 @@ import (
. Bad private key . Bad private key
. Valid certificate & private key */ . Valid certificate & private key */
func TestValidateCertificates(t *testing.T) { func TestValidateCertificates(t *testing.T) {
var data tlsConfig var data tlsConfigStatus
// bad cert // bad cert
data.CertificateChain = "bad cert" data = validateCertificates("bad cert", "", "")
data.PrivateKey = ""
data = validateCertificates(data)
if !(data.WarningValidation != "" && if !(data.WarningValidation != "" &&
!data.ValidCert && !data.ValidCert &&
!data.ValidChain) { !data.ValidChain) {
@ -23,16 +21,14 @@ func TestValidateCertificates(t *testing.T) {
} }
// bad priv key // bad priv key
data.CertificateChain = "" data = validateCertificates("", "bad priv key", "")
data.PrivateKey = "bad priv key"
data = validateCertificates(data)
if !(data.WarningValidation != "" && if !(data.WarningValidation != "" &&
!data.ValidKey) { !data.ValidKey) {
t.Fatalf("bad priv key: validateCertificates(): %v", data) t.Fatalf("bad priv key: validateCertificates(): %v", data)
} }
// valid cert & priv key // valid cert & priv key
data.CertificateChain = `-----BEGIN CERTIFICATE----- CertificateChain := `-----BEGIN CERTIFICATE-----
MIICKzCCAZSgAwIBAgIJAMT9kPVJdM7LMA0GCSqGSIb3DQEBCwUAMC0xFDASBgNV MIICKzCCAZSgAwIBAgIJAMT9kPVJdM7LMA0GCSqGSIb3DQEBCwUAMC0xFDASBgNV
BAoMC0FkR3VhcmQgTHRkMRUwEwYDVQQDDAxBZEd1YXJkIEhvbWUwHhcNMTkwMjI3 BAoMC0FkR3VhcmQgTHRkMRUwEwYDVQQDDAxBZEd1YXJkIEhvbWUwHhcNMTkwMjI3
MDkyNDIzWhcNNDYwNzE0MDkyNDIzWjAtMRQwEgYDVQQKDAtBZEd1YXJkIEx0ZDEV MDkyNDIzWhcNNDYwNzE0MDkyNDIzWjAtMRQwEgYDVQQKDAtBZEd1YXJkIEx0ZDEV
@ -46,7 +42,7 @@ LwlXfbakf7qkVTlCNXgoY7RaJ8rJdPgOZPoCTVToEhT6u/cb1c2qp8QB0dNExDna
b0Z+dnODTZqQOJo6z/wIXlcUrnR4cQVvytXt8lFn+26l6Y6EMI26twC/xWr+1swq b0Z+dnODTZqQOJo6z/wIXlcUrnR4cQVvytXt8lFn+26l6Y6EMI26twC/xWr+1swq
Muj4FeWHVDerquH4yMr1jsYLD3ci+kc5sbIX6TfVxQ== Muj4FeWHVDerquH4yMr1jsYLD3ci+kc5sbIX6TfVxQ==
-----END CERTIFICATE-----` -----END CERTIFICATE-----`
data.PrivateKey = `-----BEGIN PRIVATE KEY----- PrivateKey := `-----BEGIN PRIVATE KEY-----
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALC/BSc8mI68tw5p MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALC/BSc8mI68tw5p
aYa7pjrySwWvXeetcFywOWHGVfLw9qiFWLdfESa3Y6tWMpZAXD9t1Xh9n211YUBV aYa7pjrySwWvXeetcFywOWHGVfLw9qiFWLdfESa3Y6tWMpZAXD9t1Xh9n211YUBV
FGSB4ZshnM/tgEPU6t787lJD4NsIIRp++MkJxdAitN4oUTqL0bdpIwezQ/CrYuBX FGSB4ZshnM/tgEPU6t787lJD4NsIIRp++MkJxdAitN4oUTqL0bdpIwezQ/CrYuBX
@ -62,7 +58,7 @@ O5EX70gpeGQMPDK0QSWpaazg956njJSDbNCFM4BccrdQbJu1cW4qOsfBAkAMgZuG
O88slmgTRHX4JGFmy3rrLiHNI2BbJSuJ++Yllz8beVzh6NfvuY+HKRCmPqoBPATU O88slmgTRHX4JGFmy3rrLiHNI2BbJSuJ++Yllz8beVzh6NfvuY+HKRCmPqoBPATU
kXS9jgARhhiWXJrk kXS9jgARhhiWXJrk
-----END PRIVATE KEY-----` -----END PRIVATE KEY-----`
data = validateCertificates(data) data = validateCertificates(CertificateChain, PrivateKey, "")
notBefore, _ := time.Parse(time.RFC3339, "2019-02-27T09:24:23Z") notBefore, _ := time.Parse(time.RFC3339, "2019-02-27T09:24:23Z")
notAfter, _ := time.Parse(time.RFC3339, "2046-07-14T09:24:23Z") notAfter, _ := time.Parse(time.RFC3339, "2046-07-14T09:24:23Z")
if !(data.WarningValidation != "" /* self signed */ && if !(data.WarningValidation != "" /* self signed */ &&