File: certificate.go

package info (click to toggle)
golang-github-eggsampler-acme 3.6.1-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 312 kB
  • sloc: makefile: 47
file content (106 lines) | stat: -rw-r--r-- 3,010 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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
}