210 lines
6.0 KiB
Go
210 lines
6.0 KiB
Go
package acme
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
)
|
|
|
|
// ACME server response statuses used to describe Authorization and Challenge states.
|
|
const (
|
|
StatusUnknown = "unknown"
|
|
StatusPending = "pending"
|
|
StatusProcessing = "processing"
|
|
StatusValid = "valid"
|
|
StatusInvalid = "invalid"
|
|
StatusRevoked = "revoked"
|
|
)
|
|
|
|
// CRLReasonCode identifies the reason for a certificate revocation.
|
|
type CRLReasonCode int
|
|
|
|
// CRL reason codes as defined in RFC 5280.
|
|
const (
|
|
CRLReasonUnspecified CRLReasonCode = 0
|
|
CRLReasonKeyCompromise CRLReasonCode = 1
|
|
CRLReasonCACompromise CRLReasonCode = 2
|
|
CRLReasonAffiliationChanged CRLReasonCode = 3
|
|
CRLReasonSuperseded CRLReasonCode = 4
|
|
CRLReasonCessationOfOperation CRLReasonCode = 5
|
|
CRLReasonCertificateHold CRLReasonCode = 6
|
|
CRLReasonRemoveFromCRL CRLReasonCode = 8
|
|
CRLReasonPrivilegeWithdrawn CRLReasonCode = 9
|
|
CRLReasonAACompromise CRLReasonCode = 10
|
|
)
|
|
|
|
var (
|
|
// ErrAuthorizationFailed indicates that an authorization for an identifier
|
|
// did not succeed.
|
|
ErrAuthorizationFailed = errors.New("acme: identifier authorization failed")
|
|
|
|
// ErrUnsupportedKey is returned when an unsupported key type is encountered.
|
|
ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported")
|
|
)
|
|
|
|
// Error is an ACME error, defined in Problem Details for HTTP APIs doc
|
|
// http://tools.ietf.org/html/draft-ietf-appsawg-http-problem.
|
|
type Error struct {
|
|
// StatusCode is The HTTP status code generated by the origin server.
|
|
StatusCode int
|
|
// ProblemType is a URI reference that identifies the problem type,
|
|
// typically in a "urn:acme:error:xxx" form.
|
|
ProblemType string
|
|
// Detail is a human-readable explanation specific to this occurrence of the problem.
|
|
Detail string
|
|
// Header is the original server error response headers.
|
|
Header http.Header
|
|
}
|
|
|
|
func (e *Error) Error() string {
|
|
return fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail)
|
|
}
|
|
|
|
// Account is a user account. It is associated with a private key.
|
|
type Account struct {
|
|
// URI is the account unique ID, which is also a URL used to retrieve
|
|
// account data from the CA.
|
|
URI string
|
|
|
|
// Contact is a slice of contact info used during registration.
|
|
Contact []string
|
|
|
|
// The terms user has agreed to.
|
|
// A value not matching CurrentTerms indicates that the user hasn't agreed
|
|
// to the actual Terms of Service of the CA.
|
|
AgreedTerms string
|
|
|
|
// Actual terms of a CA.
|
|
CurrentTerms string
|
|
|
|
// Authz is the authorization URL used to initiate a new authz flow.
|
|
Authz string
|
|
|
|
// Authorizations is a URI from which a list of authorizations
|
|
// granted to this account can be fetched via a GET request.
|
|
Authorizations string
|
|
|
|
// Certificates is a URI from which a list of certificates
|
|
// issued for this account can be fetched via a GET request.
|
|
Certificates string
|
|
}
|
|
|
|
// Directory is ACME server discovery data.
|
|
type Directory struct {
|
|
// RegURL is an account endpoint URL, allowing for creating new
|
|
// and modifying existing accounts.
|
|
RegURL string
|
|
|
|
// AuthzURL is used to initiate Identifier Authorization flow.
|
|
AuthzURL string
|
|
|
|
// CertURL is a new certificate issuance endpoint URL.
|
|
CertURL string
|
|
|
|
// RevokeURL is used to initiate a certificate revocation flow.
|
|
RevokeURL string
|
|
|
|
// Term is a URI identifying the current terms of service.
|
|
Terms string
|
|
|
|
// Website is an HTTP or HTTPS URL locating a website
|
|
// providing more information about the ACME server.
|
|
Website string
|
|
|
|
// CAA consists of lowercase hostname elements, which the ACME server
|
|
// recognises as referring to itself for the purposes of CAA record validation
|
|
// as defined in RFC6844.
|
|
CAA []string
|
|
}
|
|
|
|
// Challenge encodes a returned CA challenge.
|
|
type Challenge struct {
|
|
// Type is the challenge type, e.g. "http-01", "tls-sni-02", "dns-01".
|
|
Type string
|
|
|
|
// URI is where a challenge response can be posted to.
|
|
URI string
|
|
|
|
// Token is a random value that uniquely identifies the challenge.
|
|
Token string
|
|
|
|
// Status identifies the status of this challenge.
|
|
Status string
|
|
}
|
|
|
|
// Authorization encodes an authorization response.
|
|
type Authorization struct {
|
|
// URI uniquely identifies a authorization.
|
|
URI string
|
|
|
|
// Status identifies the status of an authorization.
|
|
Status string
|
|
|
|
// Identifier is what the account is authorized to represent.
|
|
Identifier AuthzID
|
|
|
|
// Challenges that the client needs to fulfill in order to prove possession
|
|
// of the identifier (for pending authorizations).
|
|
// For final authorizations, the challenges that were used.
|
|
Challenges []*Challenge
|
|
|
|
// A collection of sets of challenges, each of which would be sufficient
|
|
// to prove possession of the identifier.
|
|
// Clients must complete a set of challenges that covers at least one set.
|
|
// Challenges are identified by their indices in the challenges array.
|
|
// If this field is empty, the client needs to complete all challenges.
|
|
Combinations [][]int
|
|
}
|
|
|
|
// AuthzID is an identifier that an account is authorized to represent.
|
|
type AuthzID struct {
|
|
Type string // The type of identifier, e.g. "dns".
|
|
Value string // The identifier itself, e.g. "example.org".
|
|
}
|
|
|
|
// wireAuthz is ACME JSON representation of Authorization objects.
|
|
type wireAuthz struct {
|
|
Status string
|
|
Challenges []wireChallenge
|
|
Combinations [][]int
|
|
Identifier struct {
|
|
Type string
|
|
Value string
|
|
}
|
|
}
|
|
|
|
func (z *wireAuthz) authorization(uri string) *Authorization {
|
|
a := &Authorization{
|
|
URI: uri,
|
|
Status: z.Status,
|
|
Identifier: AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value},
|
|
Combinations: z.Combinations, // shallow copy
|
|
Challenges: make([]*Challenge, len(z.Challenges)),
|
|
}
|
|
for i, v := range z.Challenges {
|
|
a.Challenges[i] = v.challenge()
|
|
}
|
|
return a
|
|
}
|
|
|
|
// wireChallenge is ACME JSON challenge representation.
|
|
type wireChallenge struct {
|
|
URI string `json:"uri"`
|
|
Type string
|
|
Token string
|
|
Status string
|
|
}
|
|
|
|
func (c *wireChallenge) challenge() *Challenge {
|
|
v := &Challenge{
|
|
URI: c.URI,
|
|
Type: c.Type,
|
|
Token: c.Token,
|
|
Status: c.Status,
|
|
}
|
|
if v.Status == "" {
|
|
v.Status = StatusPending
|
|
}
|
|
return v
|
|
}
|