go-acme / lego

Let's Encrypt/ACME client and library written in Go
https://go-acme.github.io/lego/
MIT License
8.05k stars 1.02k forks source link

fix: avoid Int63n panic in ShouldRenewAt() #2246

Closed robstradling closed 3 months ago

robstradling commented 3 months ago

https://www.ietf.org/archive/id/draft-ietf-acme-ari-04.html#section-4.2 says:

If the client receives no response or a malformed response (e.g. an end timestamp which is equal to or precedes the start timestamp), it SHOULD make its own determination of when to renew the certificate, and MAY retry the renewalInfo request with appropriate exponential backoff behavior.

Currently when lego encounters an ARI renewal window that specifies "an end timestamp which is equal to or precedes the start timestamp", the following panic occurs:

panic: invalid argument to Int63n

goroutine 1 [running]:
math/rand.(*Rand).Int63n(0x0?, 0x0?)
        math/rand/rand.go:122 +0xcb
math/rand.Int63n(0x0)
        math/rand/rand.go:443 +0x25
github.com/go-acme/lego/v4/certificate.(*RenewalInfoResponse).ShouldRenewAt(0xc001608c80, {0x7d8a241, 0xede57ede7, 0x0}, 0x0)
        github.com/go-acme/lego/v4/certificate/renewal.go:45 +0x1fb
github.com/go-acme/lego/v4/cmd.getARIRenewalTime(0xc001159dc0, 0x3618d8d?, {0xc000e8ac30, 0xa}, 0xc0012a7060?)
        github.com/go-acme/lego/v4/cmd/cmd_renew.go:326 +0x3b4
github.com/go-acme/lego/v4/cmd.renewForDomains(0xc001159dc0, 0xc0012a60e0, 0xc0012b6720, 0x1, 0xc00133f928)
        github.com/go-acme/lego/v4/cmd/cmd_renew.go:145 +0x212
github.com/go-acme/lego/v4/cmd.renew(0xc001159dc0)
        github.com/go-acme/lego/v4/cmd/cmd_renew.go:126 +0x245
github.com/urfave/cli/v2.(*Command).Run(0xc001156dc0, 0xc001159dc0, {0xc0013579a0, 0x2, 0x2})
        github.com/urfave/cli/v2@v2.27.2/command.go:276 +0x97d
github.com/urfave/cli/v2.(*Command).Run(0xc001157340, 0xc001159200, {0xc0001ae000, 0x12, 0x12})
        github.com/urfave/cli/v2@v2.27.2/command.go:269 +0xbb7
github.com/urfave/cli/v2.(*App).RunContext(0xc00017ac00, {0x3a6dd30, 0x5f1d680}, {0xc0001ae000, 0x12, 0x12})
        github.com/urfave/cli/v2@v2.27.2/app.go:333 +0x58b
github.com/urfave/cli/v2.(*App).Run(...)
        github.com/urfave/cli/v2@v2.27.2/app.go:307
main.main()
        github.com/go-acme/lego/v4/cmd/lego/main.go:42 +0x1c7

https://pkg.go.dev/math/rand#Rand.Int63n documents this behaviour: "It panics if n <= 0".

This PR avoids panicking when the renewal window is "malformed", and instead makes "its own determination" that the start timestamp is "when to renew the certificate".