mirror of
https://github.com/cwinfo/matterbridge.git
synced 2025-07-06 09:34:04 +00:00
Update dependencies (#975)
This commit is contained in:
392
vendor/golang.org/x/crypto/acme/rfc8555.go
generated
vendored
Normal file
392
vendor/golang.org/x/crypto/acme/rfc8555.go
generated
vendored
Normal file
@ -0,0 +1,392 @@
|
||||
// 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 (
|
||||
"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 quivalent to c.Register but for CAs implementing RFC 8555.
|
||||
// It expects c.Discover to have already been called.
|
||||
// TODO: Implement externalAccountBinding.
|
||||
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"`
|
||||
}{
|
||||
Contact: acct.Contact,
|
||||
}
|
||||
if c.dir.Terms != "" {
|
||||
req.TermsAgreed = prompt(c.dir.Terms)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// updateGegRFC 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"
|
||||
}
|
Reference in New Issue
Block a user