Make cert revocation on renewal optional. Also change signature of renew.

This commit is contained in:
xenolf 2015-10-19 03:18:06 +02:00
parent 006242198b
commit e74d5d4586
2 changed files with 23 additions and 12 deletions

View file

@ -168,7 +168,12 @@ func (c *Client) ObtainCertificates(domains []string) ([]CertificateResource, er
// RevokeCertificate takes a PEM encoded certificate and tries to revoke it at the CA. // RevokeCertificate takes a PEM encoded certificate and tries to revoke it at the CA.
func (c *Client) RevokeCertificate(certificate []byte) error { func (c *Client) RevokeCertificate(certificate []byte) error {
encodedCert := base64.URLEncoding.EncodeToString(certificate) certBlock, err := pemDecode(certificate)
if err != nil {
return err
}
encodedCert := base64.URLEncoding.EncodeToString(certBlock.Bytes)
jsonBytes, err := json.Marshal(revokeCertMessage{Resource: "revoke-cert", Certificate: encodedCert}) jsonBytes, err := json.Marshal(revokeCertMessage{Resource: "revoke-cert", Certificate: encodedCert})
if err != nil { if err != nil {
@ -192,14 +197,13 @@ func (c *Client) RevokeCertificate(certificate []byte) error {
// If the renewal process succeeds, the new certificate will replace the old one in the CertResource. // If the renewal process succeeds, the new certificate will replace the old one in the CertResource.
// Please be aware that this function will return a new certificate in ANY case that is not an error. // Please be aware that this function will return a new certificate in ANY case that is not an error.
// If the server does not provide us with a new cert on a GET request to the CertURL // If the server does not provide us with a new cert on a GET request to the CertURL
// this function will start a new-cert flow where the old (provided) cert will get REVOKED // this function will start a new-cert flow where a new certificate gets generated.
// and a new certificate gets generated. func (c *Client) RenewCertificate(cert CertificateResource, revokeOld bool) (CertificateResource, error) {
func (c *Client) RenewCertificate(cert *CertificateResource) (*CertificateResource, error) {
// Input certificate is PEM encoded. Decode it here as we may need the decoded // Input certificate is PEM encoded. Decode it here as we may need the decoded
// cert later on in the renewal process. // cert later on in the renewal process.
x509Cert, err := pemDecodeTox509(cert.Certificate) x509Cert, err := pemDecodeTox509(cert.Certificate)
if err != nil { if err != nil {
return nil, err return CertificateResource{}, err
} }
// This is just meant to be informal for the user. // This is just meant to be informal for the user.
@ -211,28 +215,35 @@ func (c *Client) RenewCertificate(cert *CertificateResource) (*CertificateResour
resp, err := http.Get(cert.CertURL) resp, err := http.Get(cert.CertURL)
serverCertBytes, err := ioutil.ReadAll(resp.Body) serverCertBytes, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return CertificateResource{}, err
} }
serverCert, err := x509.ParseCertificate(serverCertBytes) serverCert, err := x509.ParseCertificate(serverCertBytes)
if err != nil { if err != nil {
return nil, err return CertificateResource{}, err
} }
// If the server responds with a different certificate we are effectively renewed. // If the server responds with a different certificate we are effectively renewed.
// TODO: Further test if we can actually use the new certificate (Our private key works) // TODO: Further test if we can actually use the new certificate (Our private key works)
if !x509Cert.Equal(serverCert) { if !x509Cert.Equal(serverCert) {
logger().Printf("[%s] The server responded with a renewed certificate.", cert.Domain) logger().Printf("[%s] The server responded with a renewed certificate.", cert.Domain)
if revokeOld {
c.RevokeCertificate(cert.Certificate)
}
cert.Certificate = pemEncode(derCertificateBytes(serverCertBytes)) cert.Certificate = pemEncode(derCertificateBytes(serverCertBytes))
return cert, nil return cert, nil
} }
newCerts, err := c.ObtainCertificates([]string{cert.Domain}) newCerts, err := c.ObtainCertificates([]string{cert.Domain})
if err != nil { if err != nil {
return nil, err return CertificateResource{}, err
} }
return &newCerts[0], nil if revokeOld {
c.RevokeCertificate(cert.Certificate)
}
return newCerts[0], nil
} }
// Looks through the challenge combinations to find a solvable match. // Looks through the challenge combinations to find a solvable match.

View file

@ -35,7 +35,7 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
return conf, acc, acme.NewClient(c.GlobalString("server"), acc, conf.RsaBits(), conf.OptPort(), c.GlobalBool("devMode")) return conf, acc, acme.NewClient(c.GlobalString("server"), acc, conf.RsaBits(), conf.OptPort(), c.GlobalBool("devMode"))
} }
func saveCertRes(certRes *acme.CertificateResource, conf *Configuration) { func saveCertRes(certRes acme.CertificateResource, conf *Configuration) {
// We store the certificate, private key and metadata in different files // We store the certificate, private key and metadata in different files
// as web servers would not be able to work with a combined file. // as web servers would not be able to work with a combined file.
certOut := path.Join(conf.CertPath(), certRes.Domain+".crt") certOut := path.Join(conf.CertPath(), certRes.Domain+".crt")
@ -131,7 +131,7 @@ func run(c *cli.Context) {
} }
for _, certRes := range certs { for _, certRes := range certs {
saveCertRes(&certRes, conf) saveCertRes(certRes, conf)
} }
} }
@ -198,7 +198,7 @@ func renew(c *cli.Context) {
certRes.PrivateKey = keyBytes certRes.PrivateKey = keyBytes
certRes.Certificate = certBytes certRes.Certificate = certBytes
newCert, err := client.RenewCertificate(&certRes) newCert, err := client.RenewCertificate(certRes, true)
if err != nil { if err != nil {
logger().Printf("%v", err) logger().Printf("%v", err)
return return