summaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/crypto/acme/rfc8555.go
diff options
context:
space:
mode:
authortechknowlogick <techknowlogick@gitea.io>2021-01-24 18:37:35 -0500
committerGitHub <noreply@github.com>2021-01-25 01:37:35 +0200
commitd2ea21d0d8103986b2ce53c17b7b99b1ce6828b0 (patch)
tree802ea1a787b1f6ef08b18524d3818115a750f0eb /vendor/golang.org/x/crypto/acme/rfc8555.go
parentbc05ddc0ebd6fdc826ef2beec99304bac60ddd8a (diff)
downloadgitea-d2ea21d0d8103986b2ce53c17b7b99b1ce6828b0.tar.gz
gitea-d2ea21d0d8103986b2ce53c17b7b99b1ce6828b0.zip
Use caddy's certmagic library for extensible/robust ACME handling (#14177)
* use certmagic for more extensible/robust ACME cert handling * accept TOS based on config option Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: Lauris BH <lauris@nix.lv>
Diffstat (limited to 'vendor/golang.org/x/crypto/acme/rfc8555.go')
-rw-r--r--vendor/golang.org/x/crypto/acme/rfc8555.go415
1 files changed, 0 insertions, 415 deletions
diff --git a/vendor/golang.org/x/crypto/acme/rfc8555.go b/vendor/golang.org/x/crypto/acme/rfc8555.go
deleted file mode 100644
index ceb239d72a..0000000000
--- a/vendor/golang.org/x/crypto/acme/rfc8555.go
+++ /dev/null
@@ -1,415 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package acme
-
-import (
- "bytes"
- "context"
- "crypto"
- "encoding/base64"
- "encoding/json"
- "encoding/pem"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "time"
-)
-
-// DeactivateReg permanently disables an existing account associated with c.Key.
-// A deactivated account can no longer request certificate issuance or access
-// resources related to the account, such as orders or authorizations.
-//
-// It only works with CAs implementing RFC 8555.
-func (c *Client) DeactivateReg(ctx context.Context) error {
- url := string(c.accountKID(ctx))
- if url == "" {
- return ErrNoAccount
- }
- req := json.RawMessage(`{"status": "deactivated"}`)
- res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
- if err != nil {
- return err
- }
- res.Body.Close()
- return nil
-}
-
-// registerRFC is equivalent to c.Register but for CAs implementing RFC 8555.
-// It expects c.Discover to have already been called.
-func (c *Client) registerRFC(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) {
- c.cacheMu.Lock() // guard c.kid access
- defer c.cacheMu.Unlock()
-
- req := struct {
- TermsAgreed bool `json:"termsOfServiceAgreed,omitempty"`
- Contact []string `json:"contact,omitempty"`
- ExternalAccountBinding *jsonWebSignature `json:"externalAccountBinding,omitempty"`
- }{
- Contact: acct.Contact,
- }
- if c.dir.Terms != "" {
- req.TermsAgreed = prompt(c.dir.Terms)
- }
-
- // set 'externalAccountBinding' field if requested
- if acct.ExternalAccountBinding != nil {
- eabJWS, err := c.encodeExternalAccountBinding(acct.ExternalAccountBinding)
- if err != nil {
- return nil, fmt.Errorf("acme: failed to encode external account binding: %v", err)
- }
- req.ExternalAccountBinding = eabJWS
- }
-
- res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus(
- http.StatusOK, // account with this key already registered
- http.StatusCreated, // new account created
- ))
- if err != nil {
- return nil, err
- }
-
- defer res.Body.Close()
- a, err := responseAccount(res)
- if err != nil {
- return nil, err
- }
- // Cache Account URL even if we return an error to the caller.
- // It is by all means a valid and usable "kid" value for future requests.
- c.kid = keyID(a.URI)
- if res.StatusCode == http.StatusOK {
- return nil, ErrAccountAlreadyExists
- }
- return a, nil
-}
-
-// encodeExternalAccountBinding will encode an external account binding stanza
-// as described in https://tools.ietf.org/html/rfc8555#section-7.3.4.
-func (c *Client) encodeExternalAccountBinding(eab *ExternalAccountBinding) (*jsonWebSignature, error) {
- jwk, err := jwkEncode(c.Key.Public())
- if err != nil {
- return nil, err
- }
- var rProtected bytes.Buffer
- fmt.Fprintf(&rProtected, `{"alg":%q,"kid":%q,"url":%q}`, eab.Algorithm, eab.KID, c.dir.RegURL)
- return jwsWithMAC(eab.Key, eab.Algorithm, rProtected.Bytes(), []byte(jwk))
-}
-
-// updateRegRFC is equivalent to c.UpdateReg but for CAs implementing RFC 8555.
-// It expects c.Discover to have already been called.
-func (c *Client) updateRegRFC(ctx context.Context, a *Account) (*Account, error) {
- url := string(c.accountKID(ctx))
- if url == "" {
- return nil, ErrNoAccount
- }
- req := struct {
- Contact []string `json:"contact,omitempty"`
- }{
- Contact: a.Contact,
- }
- res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
- if err != nil {
- return nil, err
- }
- defer res.Body.Close()
- return responseAccount(res)
-}
-
-// getGegRFC is equivalent to c.GetReg but for CAs implementing RFC 8555.
-// It expects c.Discover to have already been called.
-func (c *Client) getRegRFC(ctx context.Context) (*Account, error) {
- req := json.RawMessage(`{"onlyReturnExisting": true}`)
- res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus(http.StatusOK))
- if e, ok := err.(*Error); ok && e.ProblemType == "urn:ietf:params:acme:error:accountDoesNotExist" {
- return nil, ErrNoAccount
- }
- if err != nil {
- return nil, err
- }
-
- defer res.Body.Close()
- return responseAccount(res)
-}
-
-func responseAccount(res *http.Response) (*Account, error) {
- var v struct {
- Status string
- Contact []string
- Orders string
- }
- if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
- return nil, fmt.Errorf("acme: invalid account response: %v", err)
- }
- return &Account{
- URI: res.Header.Get("Location"),
- Status: v.Status,
- Contact: v.Contact,
- OrdersURL: v.Orders,
- }, nil
-}
-
-// AuthorizeOrder initiates the order-based application for certificate issuance,
-// as opposed to pre-authorization in Authorize.
-// It is only supported by CAs implementing RFC 8555.
-//
-// The caller then needs to fetch each authorization with GetAuthorization,
-// identify those with StatusPending status and fulfill a challenge using Accept.
-// Once all authorizations are satisfied, the caller will typically want to poll
-// order status using WaitOrder until it's in StatusReady state.
-// To finalize the order and obtain a certificate, the caller submits a CSR with CreateOrderCert.
-func (c *Client) AuthorizeOrder(ctx context.Context, id []AuthzID, opt ...OrderOption) (*Order, error) {
- dir, err := c.Discover(ctx)
- if err != nil {
- return nil, err
- }
-
- req := struct {
- Identifiers []wireAuthzID `json:"identifiers"`
- NotBefore string `json:"notBefore,omitempty"`
- NotAfter string `json:"notAfter,omitempty"`
- }{}
- for _, v := range id {
- req.Identifiers = append(req.Identifiers, wireAuthzID{
- Type: v.Type,
- Value: v.Value,
- })
- }
- for _, o := range opt {
- switch o := o.(type) {
- case orderNotBeforeOpt:
- req.NotBefore = time.Time(o).Format(time.RFC3339)
- case orderNotAfterOpt:
- req.NotAfter = time.Time(o).Format(time.RFC3339)
- default:
- // Package's fault if we let this happen.
- panic(fmt.Sprintf("unsupported order option type %T", o))
- }
- }
-
- res, err := c.post(ctx, nil, dir.OrderURL, req, wantStatus(http.StatusCreated))
- if err != nil {
- return nil, err
- }
- defer res.Body.Close()
- return responseOrder(res)
-}
-
-// GetOrder retrives an order identified by the given URL.
-// For orders created with AuthorizeOrder, the url value is Order.URI.
-//
-// If a caller needs to poll an order until its status is final,
-// see the WaitOrder method.
-func (c *Client) GetOrder(ctx context.Context, url string) (*Order, error) {
- if _, err := c.Discover(ctx); err != nil {
- return nil, err
- }
-
- res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
- if err != nil {
- return nil, err
- }
- defer res.Body.Close()
- return responseOrder(res)
-}
-
-// WaitOrder polls an order from the given URL until it is in one of the final states,
-// StatusReady, StatusValid or StatusInvalid, the CA responded with a non-retryable error
-// or the context is done.
-//
-// It returns a non-nil Order only if its Status is StatusReady or StatusValid.
-// In all other cases WaitOrder returns an error.
-// If the Status is StatusInvalid, the returned error is of type *OrderError.
-func (c *Client) WaitOrder(ctx context.Context, url string) (*Order, error) {
- if _, err := c.Discover(ctx); err != nil {
- return nil, err
- }
- for {
- res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
- if err != nil {
- return nil, err
- }
- o, err := responseOrder(res)
- res.Body.Close()
- switch {
- case err != nil:
- // Skip and retry.
- case o.Status == StatusInvalid:
- return nil, &OrderError{OrderURL: o.URI, Status: o.Status}
- case o.Status == StatusReady || o.Status == StatusValid:
- return o, nil
- }
-
- d := retryAfter(res.Header.Get("Retry-After"))
- if d == 0 {
- // Default retry-after.
- // Same reasoning as in WaitAuthorization.
- d = time.Second
- }
- t := time.NewTimer(d)
- select {
- case <-ctx.Done():
- t.Stop()
- return nil, ctx.Err()
- case <-t.C:
- // Retry.
- }
- }
-}
-
-func responseOrder(res *http.Response) (*Order, error) {
- var v struct {
- Status string
- Expires time.Time
- Identifiers []wireAuthzID
- NotBefore time.Time
- NotAfter time.Time
- Error *wireError
- Authorizations []string
- Finalize string
- Certificate string
- }
- if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
- return nil, fmt.Errorf("acme: error reading order: %v", err)
- }
- o := &Order{
- URI: res.Header.Get("Location"),
- Status: v.Status,
- Expires: v.Expires,
- NotBefore: v.NotBefore,
- NotAfter: v.NotAfter,
- AuthzURLs: v.Authorizations,
- FinalizeURL: v.Finalize,
- CertURL: v.Certificate,
- }
- for _, id := range v.Identifiers {
- o.Identifiers = append(o.Identifiers, AuthzID{Type: id.Type, Value: id.Value})
- }
- if v.Error != nil {
- o.Error = v.Error.error(nil /* headers */)
- }
- return o, nil
-}
-
-// CreateOrderCert submits the CSR (Certificate Signing Request) to a CA at the specified URL.
-// The URL is the FinalizeURL field of an Order created with AuthorizeOrder.
-//
-// If the bundle argument is true, the returned value also contain the CA (issuer)
-// certificate chain. Otherwise, only a leaf certificate is returned.
-// The returned URL can be used to re-fetch the certificate using FetchCert.
-//
-// This method is only supported by CAs implementing RFC 8555. See CreateCert for pre-RFC CAs.
-//
-// CreateOrderCert returns an error if the CA's response is unreasonably large.
-// Callers are encouraged to parse the returned value to ensure the certificate is valid and has the expected features.
-func (c *Client) CreateOrderCert(ctx context.Context, url string, csr []byte, bundle bool) (der [][]byte, certURL string, err error) {
- if _, err := c.Discover(ctx); err != nil { // required by c.accountKID
- return nil, "", err
- }
-
- // RFC describes this as "finalize order" request.
- req := struct {
- CSR string `json:"csr"`
- }{
- CSR: base64.RawURLEncoding.EncodeToString(csr),
- }
- res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
- if err != nil {
- return nil, "", err
- }
- defer res.Body.Close()
- o, err := responseOrder(res)
- if err != nil {
- return nil, "", err
- }
-
- // Wait for CA to issue the cert if they haven't.
- if o.Status != StatusValid {
- o, err = c.WaitOrder(ctx, o.URI)
- }
- if err != nil {
- return nil, "", err
- }
- // The only acceptable status post finalize and WaitOrder is "valid".
- if o.Status != StatusValid {
- return nil, "", &OrderError{OrderURL: o.URI, Status: o.Status}
- }
- crt, err := c.fetchCertRFC(ctx, o.CertURL, bundle)
- return crt, o.CertURL, err
-}
-
-// fetchCertRFC downloads issued certificate from the given URL.
-// It expects the CA to respond with PEM-encoded certificate chain.
-//
-// The URL argument is the CertURL field of Order.
-func (c *Client) fetchCertRFC(ctx context.Context, url string, bundle bool) ([][]byte, error) {
- res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
- if err != nil {
- return nil, err
- }
- defer res.Body.Close()
-
- // Get all the bytes up to a sane maximum.
- // Account very roughly for base64 overhead.
- const max = maxCertChainSize + maxCertChainSize/33
- b, err := ioutil.ReadAll(io.LimitReader(res.Body, max+1))
- if err != nil {
- return nil, fmt.Errorf("acme: fetch cert response stream: %v", err)
- }
- if len(b) > max {
- return nil, errors.New("acme: certificate chain is too big")
- }
-
- // Decode PEM chain.
- var chain [][]byte
- for {
- var p *pem.Block
- p, b = pem.Decode(b)
- if p == nil {
- break
- }
- if p.Type != "CERTIFICATE" {
- return nil, fmt.Errorf("acme: invalid PEM cert type %q", p.Type)
- }
-
- chain = append(chain, p.Bytes)
- if !bundle {
- return chain, nil
- }
- if len(chain) > maxChainLen {
- return nil, errors.New("acme: certificate chain is too long")
- }
- }
- if len(chain) == 0 {
- return nil, errors.New("acme: certificate chain is empty")
- }
- return chain, nil
-}
-
-// sends a cert revocation request in either JWK form when key is non-nil or KID form otherwise.
-func (c *Client) revokeCertRFC(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error {
- req := &struct {
- Cert string `json:"certificate"`
- Reason int `json:"reason"`
- }{
- Cert: base64.RawURLEncoding.EncodeToString(cert),
- Reason: int(reason),
- }
- res, err := c.post(ctx, key, c.dir.RevokeURL, req, wantStatus(http.StatusOK))
- if err != nil {
- if isAlreadyRevoked(err) {
- // Assume it is not an error to revoke an already revoked cert.
- return nil
- }
- return err
- }
- defer res.Body.Close()
- return nil
-}
-
-func isAlreadyRevoked(err error) bool {
- e, ok := err.(*Error)
- return ok && e.ProblemType == "urn:ietf:params:acme:error:alreadyRevoked"
-}