Skip to content

Commit

Permalink
home: imp cyclo
Browse files Browse the repository at this point in the history
  • Loading branch information
EugeneOne1 committed Oct 31, 2022
1 parent 86c47b6 commit 9d4ecd9
Showing 1 changed file with 47 additions and 38 deletions.
85 changes: 47 additions & 38 deletions internal/home/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -488,10 +488,33 @@ func validatePorts(
return nil
}

// validateCertChain validates the certificate chain. It returns the first
// certificate within the chain. ok is true if the main certificate is valid.
// main is guaranteed to be non-nil when ok is true.
func validateCertChain(chain []byte, srvName string) (main *x509.Certificate, ok bool, err error) {
// validateCertChain verifies certs using the first as the main one and others
// as intermediate. srvName stands for the expected DNS name.
func validateCertChain(certs []*x509.Certificate, srvName string) (err error) {
main, others := certs[0], certs[1:]

pool := x509.NewCertPool()
for _, cert := range others {
log.Info("tls: got an intermediate cert")
pool.AddCert(cert)
}

opts := x509.VerifyOptions{
DNSName: srvName,
Roots: Context.tlsRoots,
Intermediates: pool,
}
_, err = main.Verify(opts)
if err != nil {
return fmt.Errorf("certificate does not verify: %w", err)
}

return nil
}

// parseCertChain parses the certificate chain from raw data, and returns it.
// If ok is true, the returned error, if any, is not critical.
func parseCertChain(chain []byte) (parsedCerts []*x509.Certificate, ok bool, err error) {
log.Debug("tls: got certificate chain: %d bytes", len(chain))

var certs []*pem.Block
Expand All @@ -503,32 +526,18 @@ func validateCertChain(chain []byte, srvName string) (main *x509.Certificate, ok
decoded, pemblock = pem.Decode(pemblock)
}

parsedCerts, err := parsePEMCerts(certs)
parsedCerts, err = parsePEMCerts(certs)
if err != nil {
return nil, false, err
}

log.Info("tls: number of certs: %d", len(parsedCerts))

var others []*x509.Certificate
main, others = parsedCerts[0], parsedCerts[1:]

pool := x509.NewCertPool()
for _, cert := range others {
log.Info("tls: got an intermediate cert")
pool.AddCert(cert)
if mainCert := parsedCerts[0]; len(mainCert.IPAddresses) == 0 {
err = errors.Error(`certificate has no IP addresses` +
`, this may cause issues with DNS-over-TLS clients`)
}

opts := x509.VerifyOptions{
DNSName: srvName,
Roots: Context.tlsRoots,
Intermediates: pool,
}
_, err = main.Verify(opts)
err = errors.Annotate(err, "certificate does not verify: %w")

// Let self-signed certs through and don't return this error.
return main, true, err
return parsedCerts, true, err
}

// parsePEMCerts parses multiple PEM-encoded certificates.
Expand Down Expand Up @@ -586,9 +595,9 @@ func validatePKey(pkey []byte) (keyType string, err error) {
return keyType, nil
}

// validateCertificates processes certificate data and its private key. All
// parameters are optional. status must not be nil. The returned error is also
// set in status.WarningValidation.
// validateCertificates processes certificate data and its private key. status
// must not be nil, since it's used to accumulate the validation results. Other
// parameters are optional.
func validateCertificates(
status *tlsConfigStatus,
certChain []byte,
Expand All @@ -597,26 +606,26 @@ func validateCertificates(
) (err error) {
// Check only the public certificate separately from the key.
if len(certChain) > 0 {
var mainCert *x509.Certificate
mainCert, status.ValidCert, err = validateCertChain(certChain, serverName)
if err != nil {
if !status.ValidCert {
// Don't wrap the error, since it's informative enough as is.
return err
}
} else {
status.ValidChain = true
var certs []*x509.Certificate
certs, status.ValidCert, err = parseCertChain(certChain)
if !status.ValidCert {
// Don't wrap the error, since it's informative enough as is.
return err
}

mainCert := certs[0]
status.Subject = mainCert.Subject.String()
status.Issuer = mainCert.Issuer.String()
status.NotAfter = mainCert.NotAfter
status.NotBefore = mainCert.NotBefore
status.DNSNames = mainCert.DNSNames

if err == nil && len(mainCert.IPAddresses) == 0 {
err = errors.Error(`certificate has no IP addresses` +
`, this may cause issues with DNS-over-TLS clients`)
if chainErr := validateCertChain(certs, serverName); chainErr != nil {
// Let self-signed certs through and don't return this error to set
// its message into the status.WarningValidation afterwards.
err = chainErr
} else {
status.ValidChain = true
}
}

Expand Down

0 comments on commit 9d4ecd9

Please sign in to comment.