diff --git a/acme/client.go b/acme/client.go index 9f837af3..e758d24f 100644 --- a/acme/client.go +++ b/acme/client.go @@ -49,12 +49,11 @@ type validateFunc func(j *jws, domain, uri string, chlng challenge) error // Client is the user-friendy way to ACME type Client struct { - directory directory - user User - jws *jws - keyType KeyType - issuerCert []byte - solvers map[Challenge]solver + directory directory + user User + jws *jws + keyType KeyType + solvers map[Challenge]solver } // NewClient creates a new ACME client on behalf of the user. The client will depend on @@ -634,24 +633,26 @@ func (c *Client) requestCertificateForCsr(authz []authorizationResource, bundle cerRes.AccountRef = c.user.GetRegistration().URI issuedCert := pemEncode(derCertificateBytes(cert)) - // If bundle is true, we want to return a certificate bundle. - // To do this, we need the issuer certificate. - if bundle { - // The issuer certificate link is always supplied via an "up" link - // in the response headers of a new certificate. - links := parseLinks(resp.Header["Link"]) - issuerCert, err := c.getIssuerCertificate(links["up"]) - if err != nil { - // If we fail to acquire the issuer cert, return the issued certificate - do not fail. - logf("[WARNING][%s] acme: Could not bundle issuer certificate: %v", commonName.Domain, err) - } else { - // Success - append the issuer cert to the issued cert. - issuerCert = pemEncode(derCertificateBytes(issuerCert)) + + // The issuer certificate link is always supplied via an "up" link + // in the response headers of a new certificate. + links := parseLinks(resp.Header["Link"]) + issuerCert, err := c.getIssuerCertificate(links["up"]) + if err != nil { + // If we fail to acquire the issuer cert, return the issued certificate - do not fail. + logf("[WARNING][%s] acme: Could not bundle issuer certificate: %v", commonName.Domain, err) + } else { + issuerCert = pemEncode(derCertificateBytes(issuerCert)) + + // If bundle is true, we want to return a certificate bundle. + // To do this, we append the issuer cert to the issued cert. + if bundle { issuedCert = append(issuedCert, issuerCert...) } } cerRes.Certificate = issuedCert + cerRes.IssuerCertificate = issuerCert logf("[INFO][%s] Server responded with a certificate.", commonName.Domain) return cerRes, nil } @@ -679,14 +680,9 @@ func (c *Client) requestCertificateForCsr(authz []authorizationResource, bundle } } -// getIssuerCertificate requests the issuer certificate and caches it for -// subsequent requests. +// getIssuerCertificate requests the issuer certificate func (c *Client) getIssuerCertificate(url string) ([]byte, error) { logf("[INFO] acme: Requesting issuer cert from %s", url) - if c.issuerCert != nil { - return c.issuerCert, nil - } - resp, err := httpGet(url) if err != nil { return nil, err @@ -703,7 +699,6 @@ func (c *Client) getIssuerCertificate(url string) ([]byte, error) { return nil, err } - c.issuerCert = issuerBytes return issuerBytes, err } diff --git a/acme/messages.go b/acme/messages.go index 0f6514c3..36db3b21 100644 --- a/acme/messages.go +++ b/acme/messages.go @@ -94,16 +94,17 @@ type revokeCertMessage struct { } // CertificateResource represents a CA issued certificate. -// PrivateKey and Certificate are both already PEM encoded -// and can be directly written to disk. Certificate may -// be a certificate bundle, depending on the options supplied -// to create it. +// PrivateKey, Certificate and IssuerCertificate are all +// already PEM encoded and can be directly written to disk. +// Certificate may be a certificate bundle, depending on the +// options supplied to create it. type CertificateResource struct { - Domain string `json:"domain"` - CertURL string `json:"certUrl"` - CertStableURL string `json:"certStableUrl"` - AccountRef string `json:"accountRef,omitempty"` - PrivateKey []byte `json:"-"` - Certificate []byte `json:"-"` - CSR []byte `json:"-"` + Domain string `json:"domain"` + CertURL string `json:"certUrl"` + CertStableURL string `json:"certStableUrl"` + AccountRef string `json:"accountRef,omitempty"` + PrivateKey []byte `json:"-"` + Certificate []byte `json:"-"` + IssuerCertificate []byte `json:"-"` + CSR []byte `json:"-"` } diff --git a/cli_handlers.go b/cli_handlers.go index 858d7100..dad19a14 100644 --- a/cli_handlers.go +++ b/cli_handlers.go @@ -136,12 +136,20 @@ func saveCertRes(certRes acme.CertificateResource, conf *Configuration) { privOut := path.Join(conf.CertPath(), certRes.Domain+".key") pemOut := path.Join(conf.CertPath(), certRes.Domain+".pem") metaOut := path.Join(conf.CertPath(), certRes.Domain+".json") + issuerOut := path.Join(conf.CertPath(), certRes.Domain+".issuer.crt") err := ioutil.WriteFile(certOut, certRes.Certificate, 0600) if err != nil { logger().Fatalf("Unable to save Certificate for domain %s\n\t%s", certRes.Domain, err.Error()) } + if certRes.IssuerCertificate != nil { + err = ioutil.WriteFile(issuerOut, certRes.IssuerCertificate, 0600) + if err != nil { + logger().Fatalf("Unable to save IssuerCertificate for domain %s\n\t%s", certRes.Domain, err.Error()) + } + } + if certRes.PrivateKey != nil { // if we were given a CSR, we don't know the private key err = ioutil.WriteFile(privOut, certRes.PrivateKey, 0600)