Remove ObtainCertificates and rename ObtainSANCertificate to ObtainCertificate.

Also removes revokation abilities from RenewCertificate.

Makes the API more orthogonal. These things are not provided by the
ACME protocol, but were convenience helpers.
This commit is contained in:
Tommie Gannert 2015-12-05 22:07:12 +00:00
parent 71624f607a
commit e32b9abfb2
2 changed files with 11 additions and 95 deletions

View file

@ -176,56 +176,12 @@ func (c *Client) AgreeToTOS() error {
return err return err
} }
// ObtainCertificates tries to obtain certificates from the CA server // ObtainCertificate tries to obtain a single certificate using all domains passed into it.
// using the challenges it has configured. The returned certificates are
// PEM encoded byte slices.
// If bundle is true, the []byte contains both the issuer certificate and
// your issued certificate as a bundle.
func (c *Client) ObtainCertificates(domains []string, bundle bool) ([]CertificateResource, map[string]error) {
if bundle {
logf("[INFO] acme: Obtaining bundled certificates for %v", strings.Join(domains, ", "))
} else {
logf("[INFO] acme: Obtaining certificates for %v", strings.Join(domains, ", "))
}
challenges, failures := c.getChallenges(domains)
if len(challenges) == 0 {
return nil, failures
}
err := c.solveChallenges(challenges)
for k, v := range err {
failures[k] = v
}
if len(failures) == len(domains) {
return nil, failures
}
// remove failed challenges from slice
var succeededChallenges []authorizationResource
for _, chln := range challenges {
if failures[chln.Domain] == nil {
succeededChallenges = append(succeededChallenges, chln)
}
}
logf("[INFO] acme: Validations succeeded; requesting certificates")
certs, err := c.requestCertificates(succeededChallenges, bundle)
for k, v := range err {
failures[k] = v
}
return certs, failures
}
// ObtainSANCertificate tries to obtain a single certificate using all domains passed into it.
// The first domain in domains is used for the CommonName field of the certificate, all other // The first domain in domains is used for the CommonName field of the certificate, all other
// domains are added using the Subject Alternate Names extension. // domains are added using the Subject Alternate Names extension.
// If bundle is true, the []byte contains both the issuer certificate and // If bundle is true, the []byte contains both the issuer certificate and
// your issued certificate as a bundle. // your issued certificate as a bundle.
func (c *Client) ObtainSANCertificate(domains []string, bundle bool) (CertificateResource, map[string]error) { func (c *Client) ObtainCertificate(domains []string, bundle bool) (CertificateResource, map[string]error) {
if bundle { if bundle {
logf("[INFO] acme: Obtaining bundled SAN certificate for %v", strings.Join(domains, ", ")) logf("[INFO] acme: Obtaining bundled SAN certificate for %v", strings.Join(domains, ", "))
} else { } else {
@ -281,7 +237,7 @@ func (c *Client) RevokeCertificate(certificate []byte) error {
// this function will start a new-cert flow where a new certificate gets generated. // this function will start a new-cert flow where a new certificate gets generated.
// If bundle is true, the []byte contains both the issuer certificate and // If bundle is true, the []byte contains both the issuer certificate and
// your issued certificate as a bundle. // your issued certificate as a bundle.
func (c *Client) RenewCertificate(cert CertificateResource, revokeOld bool, bundle bool) (CertificateResource, error) { func (c *Client) RenewCertificate(cert CertificateResource, bundle bool) (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. The input may be a bundle or a single certificate. // cert later on in the renewal process. The input may be a bundle or a single certificate.
certificates, err := parsePEMBundle(cert.Certificate) certificates, err := parsePEMBundle(cert.Certificate)
@ -319,9 +275,6 @@ func (c *Client) RenewCertificate(cert CertificateResource, revokeOld bool, bund
// 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) {
logf("[INFO] acme: [%s] Server responded with renewed certificate", cert.Domain) logf("[INFO] acme: [%s] Server responded with renewed certificate", cert.Domain)
if revokeOld {
c.RevokeCertificate(cert.Certificate)
}
issuedCert := pemEncode(derCertificateBytes(serverCertBytes)) issuedCert := pemEncode(derCertificateBytes(serverCertBytes))
// If bundle is true, we want to return a certificate bundle. // If bundle is true, we want to return a certificate bundle.
// To do this, we need the issuer certificate. // To do this, we need the issuer certificate.
@ -345,16 +298,8 @@ func (c *Client) RenewCertificate(cert CertificateResource, revokeOld bool, bund
return cert, nil return cert, nil
} }
newCerts, failures := c.ObtainCertificates([]string{cert.Domain}, bundle) newCert, failures := c.ObtainCertificate([]string{cert.Domain}, bundle)
if len(failures) > 0 { return newCert, failures[cert.Domain]
return CertificateResource{}, failures[cert.Domain]
}
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.
@ -449,39 +394,6 @@ func (c *Client) getChallenges(domains []string) ([]authorizationResource, map[s
return challenges, failures return challenges, failures
} }
// requestCertificates iterates all granted authorizations, creates RSA private keys and CSRs.
// It then uses these to request a certificate from the CA and returns the list of successfully
// granted certificates.
func (c *Client) requestCertificates(challenges []authorizationResource, bundle bool) ([]CertificateResource, map[string]error) {
resc, errc := make(chan CertificateResource), make(chan domainError)
for _, authz := range challenges {
go func(authz authorizationResource, resc chan CertificateResource, errc chan domainError) {
certRes, err := c.requestCertificate([]authorizationResource{authz}, bundle)
if err != nil {
errc <- domainError{Domain: authz.Domain, Error: err}
} else {
resc <- certRes
}
}(authz, resc, errc)
}
var certs []CertificateResource
failures := make(map[string]error)
for i := 0; i < len(challenges); i++ {
select {
case res := <-resc:
certs = append(certs, res)
case err := <-errc:
failures[err.Domain] = err.Error
}
}
close(resc)
close(errc)
return certs, failures
}
func (c *Client) requestCertificate(authz []authorizationResource, bundle bool) (CertificateResource, error) { func (c *Client) requestCertificate(authz []authorizationResource, bundle bool) (CertificateResource, error) {
if len(authz) == 0 { if len(authz) == 0 {
return CertificateResource{}, errors.New("Passed no authorizations to requestCertificate!") return CertificateResource{}, errors.New("Passed no authorizations to requestCertificate!")

View file

@ -125,7 +125,7 @@ func run(c *cli.Context) {
logger().Fatal("Please specify --domains") logger().Fatal("Please specify --domains")
} }
cert, failures := client.ObtainSANCertificate(c.GlobalStringSlice("domains"), true) cert, failures := client.ObtainCertificate(c.GlobalStringSlice("domains"), true)
if len(failures) > 0 { if len(failures) > 0 {
for k, v := range failures { for k, v := range failures {
logger().Printf("[%s] Could not obtain certificates\n\t%v", k, v) logger().Printf("[%s] Could not obtain certificates\n\t%v", k, v)
@ -203,12 +203,16 @@ func renew(c *cli.Context) {
certRes.PrivateKey = keyBytes certRes.PrivateKey = keyBytes
certRes.Certificate = certBytes certRes.Certificate = certBytes
newCert, err := client.RenewCertificate(certRes, true, true) newCert, err := client.RenewCertificate(certRes, true)
if err != nil { if err != nil {
logger().Printf("%v", err) logger().Printf("%v", err)
return return
} }
if err := client.RevokeCertificate(certBytes); err != nil {
logger().Printf("%v (ignored)", err)
}
saveCertRes(newCert, conf) saveCertRes(newCert, conf)
} }
} }