From 98d198d4197f35af4a50dafab6ff6766eac06faf Mon Sep 17 00:00:00 2001 From: Gusted Date: Wed, 4 Jan 2023 04:51:27 +0000 Subject: [PATCH] Safely get certificate's leaf (#150) - It's not guaranteed that `tls.X509KeyPair` will set `c.Leaf`. - This patch fixes this by using a wrapper that parses the leaf certificate(in bytes) if `c.Leaf` wasn't set. - Resolves #149 Co-authored-by: Gusted Reviewed-on: https://codeberg.org/Codeberg/pages-server/pulls/150 Reviewed-by: 6543 <6543@obermui.de> Co-authored-by: Gusted Co-committed-by: Gusted --- server/certificates/certificates.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/server/certificates/certificates.go b/server/certificates/certificates.go index 8af4be5..e3cdbfb 100644 --- a/server/certificates/certificates.go +++ b/server/certificates/certificates.go @@ -303,7 +303,11 @@ func obtainCert(acmeClient *lego.Client, domains []string, renew *certificate.Re log.Error().Err(err).Msgf("Couldn't obtain again a certificate or %v", domains) if renew != nil && renew.CertURL != "" { tlsCertificate, err := tls.X509KeyPair(renew.Certificate, renew.PrivateKey) - if err == nil && tlsCertificate.Leaf.NotAfter.After(time.Now()) { + if err != nil { + return mockCert(domains[0], err.Error(), mainDomainSuffix, keyDatabase), err + } + leaf, err := leaf(&tlsCertificate) + if err == nil && leaf.NotAfter.After(time.Now()) { // avoid sending a mock cert instead of a still valid cert, instead abuse CSR field to store time to try again at renew.CSR = []byte(strconv.FormatInt(time.Now().Add(6*time.Hour).Unix(), 10)) if err := keyDatabase.Put(name, renew); err != nil { @@ -529,3 +533,12 @@ func MaintainCertDB(ctx context.Context, interval time.Duration, mainDomainSuffi } } } + +// leaf returns the parsed leaf certificate, either from c.leaf or by parsing +// the corresponding c.Certificate[0]. +func leaf(c *tls.Certificate) (*x509.Certificate, error) { + if c.Leaf != nil { + return c.Leaf, nil + } + return x509.ParseCertificate(c.Certificate[0]) +}