107 lines
2.9 KiB
Go
107 lines
2.9 KiB
Go
package acme
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/x509"
|
|
"encoding/base64"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"net/http"
|
|
)
|
|
|
|
func (c Client) decodeCertificateChain(body []byte, resp *http.Response, account Account) ([]*x509.Certificate, error) {
|
|
var certs []*x509.Certificate
|
|
for {
|
|
var p *pem.Block
|
|
p, body = pem.Decode(body)
|
|
if p == nil {
|
|
break
|
|
}
|
|
cert, err := x509.ParseCertificate(p.Bytes)
|
|
if err != nil {
|
|
return certs, fmt.Errorf("acme: error parsing certificate: %v", err)
|
|
}
|
|
certs = append(certs, cert)
|
|
}
|
|
|
|
up := fetchLink(resp, "up")
|
|
if up != "" {
|
|
upCerts, err := c.FetchCertificates(account, up)
|
|
if err != nil {
|
|
return certs, fmt.Errorf("acme: error fetching up cert: %v", err)
|
|
}
|
|
if len(upCerts) != 0 {
|
|
certs = append(certs, upCerts...)
|
|
}
|
|
}
|
|
|
|
return certs, nil
|
|
}
|
|
|
|
// FetchCertificates downloads a certificate chain from a url given in an order certificate.
|
|
func (c Client) FetchCertificates(account Account, certificateURL string) ([]*x509.Certificate, error) {
|
|
resp, body, err := c.postRaw(0, certificateURL, account.URL, account.PrivateKey, "", []int{http.StatusOK})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return c.decodeCertificateChain(body, resp, account)
|
|
}
|
|
|
|
// FetchAllCertificates downloads a certificate chain from a url given in an order certificate, as well as any alternate certificates if provided.
|
|
// Returns a mapping of certificate urls to the certificate chain.
|
|
func (c Client) FetchAllCertificates(account Account, certificateURL string) (map[string][]*x509.Certificate, error) {
|
|
resp, body, err := c.postRaw(0, certificateURL, account.URL, account.PrivateKey, "", []int{http.StatusOK})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
certChain, err := c.decodeCertificateChain(body, resp, account)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
certs := map[string][]*x509.Certificate{
|
|
certificateURL: certChain,
|
|
}
|
|
|
|
alternates := fetchLinks(resp, "alternate")
|
|
|
|
for _, altURL := range alternates {
|
|
altResp, altBody, err := c.postRaw(0, altURL, account.URL, account.PrivateKey, "", []int{http.StatusOK})
|
|
if err != nil {
|
|
return certs, fmt.Errorf("acme: error fetching alt cert chain at %q - %v", altURL, err)
|
|
}
|
|
altCertChain, err := c.decodeCertificateChain(altBody, altResp, account)
|
|
if err != nil {
|
|
return certs, fmt.Errorf("acme: error decoding alt cert chain at %q - %v", altURL, err)
|
|
}
|
|
certs[altURL] = altCertChain
|
|
}
|
|
|
|
return certs, nil
|
|
|
|
}
|
|
|
|
// RevokeCertificate revokes a given certificate given the certificate key or account key, and a reason.
|
|
func (c Client) RevokeCertificate(account Account, cert *x509.Certificate, key crypto.Signer, reason int) error {
|
|
revokeReq := struct {
|
|
Certificate string `json:"certificate"`
|
|
Reason int `json:"reason"`
|
|
}{
|
|
Certificate: base64.RawURLEncoding.EncodeToString(cert.Raw),
|
|
Reason: reason,
|
|
}
|
|
|
|
kid := ""
|
|
if key == account.PrivateKey {
|
|
kid = account.URL
|
|
}
|
|
|
|
if _, err := c.post(c.dir.RevokeCert, kid, key, revokeReq, nil, http.StatusOK); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|