diff --git a/cmd/acme/cert.go b/cmd/acme/cert.go index d1643d9..e6c19b9 100644 --- a/cmd/acme/cert.go +++ b/cmd/acme/cert.go @@ -93,6 +93,18 @@ func runCert(args []string) { fatalf("no key found for %s", uc.URI) } + // read crt if existent + certPath := sameDir(certKeypath, cn+".crt") + certCrt, err := readCrt(certPath) + if err == nil { + // do not re-issue certificate if it's not about to expire in less than three weeks + expiresIn := certCrt.NotAfter.Sub(time.Now()) + if expiresIn > 24*7*3*time.Hour { + errorf("cert is still valid for more than a three weeks, not renewing") + exit() + } + } + // read or generate new cert key certKey, err := anyKey(certKeypath, true) if err != nil { @@ -135,10 +147,9 @@ func runCert(args []string) { logf("cert url: %s", curl) var pemcert []byte for _, b := range cert { - b = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: b}) + b = pem.EncodeToMemory(&pem.Block{Type: x509PublicKey, Bytes: b}) pemcert = append(pemcert, b...) } - certPath := sameDir(certKeypath, cn+".crt") if err := ioutil.WriteFile(certPath, pemcert, 0644); err != nil { fatalf("write cert: %v", err) } diff --git a/cmd/acme/config.go b/cmd/acme/config.go index c1e4179..1e668ef 100644 --- a/cmd/acme/config.go +++ b/cmd/acme/config.go @@ -39,6 +39,7 @@ const ( rsaPrivateKey = "RSA PRIVATE KEY" ecPrivateKey = "EC PRIVATE KEY" + x509PublicKey = "CERTIFICATE" ) // configDir is acme configuration dir. @@ -122,6 +123,21 @@ func readKey(path string) (crypto.Signer, error) { } } +func readCrt(path string) (*x509.Certificate, error) { + b, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + d, _ := pem.Decode(b) + if d == nil { + return nil, fmt.Errorf("no block found in %q", path) + } + if d.Type != x509PublicKey { + return nil, fmt.Errorf("%q is unsupported", d.Type) + } + return x509.ParseCertificate(d.Bytes) +} + // writeKey writes k to the specified path in PEM format. // If file does not exists, it will be created with 0600 mod. func writeKey(path string, k *ecdsa.PrivateKey) error {