types.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. package acme
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/http"
  6. "strings"
  7. )
  8. // ACME server response statuses used to describe Authorization and Challenge states.
  9. const (
  10. StatusUnknown = "unknown"
  11. StatusPending = "pending"
  12. StatusProcessing = "processing"
  13. StatusValid = "valid"
  14. StatusInvalid = "invalid"
  15. StatusRevoked = "revoked"
  16. )
  17. // CRLReasonCode identifies the reason for a certificate revocation.
  18. type CRLReasonCode int
  19. // CRL reason codes as defined in RFC 5280.
  20. const (
  21. CRLReasonUnspecified CRLReasonCode = 0
  22. CRLReasonKeyCompromise CRLReasonCode = 1
  23. CRLReasonCACompromise CRLReasonCode = 2
  24. CRLReasonAffiliationChanged CRLReasonCode = 3
  25. CRLReasonSuperseded CRLReasonCode = 4
  26. CRLReasonCessationOfOperation CRLReasonCode = 5
  27. CRLReasonCertificateHold CRLReasonCode = 6
  28. CRLReasonRemoveFromCRL CRLReasonCode = 8
  29. CRLReasonPrivilegeWithdrawn CRLReasonCode = 9
  30. CRLReasonAACompromise CRLReasonCode = 10
  31. )
  32. // ErrUnsupportedKey is returned when an unsupported key type is encountered.
  33. var ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported")
  34. // Error is an ACME error, defined in Problem Details for HTTP APIs doc
  35. // http://tools.ietf.org/html/draft-ietf-appsawg-http-problem.
  36. type Error struct {
  37. // StatusCode is The HTTP status code generated by the origin server.
  38. StatusCode int
  39. // ProblemType is a URI reference that identifies the problem type,
  40. // typically in a "urn:acme:error:xxx" form.
  41. ProblemType string
  42. // Detail is a human-readable explanation specific to this occurrence of the problem.
  43. Detail string
  44. // Header is the original server error response headers.
  45. // It may be nil.
  46. Header http.Header
  47. }
  48. func (e *Error) Error() string {
  49. return fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail)
  50. }
  51. // AuthorizationError indicates that an authorization for an identifier
  52. // did not succeed.
  53. // It contains all errors from Challenge items of the failed Authorization.
  54. type AuthorizationError struct {
  55. // URI uniquely identifies the failed Authorization.
  56. URI string
  57. // Identifier is an AuthzID.Value of the failed Authorization.
  58. Identifier string
  59. // Errors is a collection of non-nil error values of Challenge items
  60. // of the failed Authorization.
  61. Errors []error
  62. }
  63. func (a *AuthorizationError) Error() string {
  64. e := make([]string, len(a.Errors))
  65. for i, err := range a.Errors {
  66. e[i] = err.Error()
  67. }
  68. return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; "))
  69. }
  70. // Account is a user account. It is associated with a private key.
  71. type Account struct {
  72. // URI is the account unique ID, which is also a URL used to retrieve
  73. // account data from the CA.
  74. URI string
  75. // Contact is a slice of contact info used during registration.
  76. Contact []string
  77. // The terms user has agreed to.
  78. // A value not matching CurrentTerms indicates that the user hasn't agreed
  79. // to the actual Terms of Service of the CA.
  80. AgreedTerms string
  81. // Actual terms of a CA.
  82. CurrentTerms string
  83. // Authz is the authorization URL used to initiate a new authz flow.
  84. Authz string
  85. // Authorizations is a URI from which a list of authorizations
  86. // granted to this account can be fetched via a GET request.
  87. Authorizations string
  88. // Certificates is a URI from which a list of certificates
  89. // issued for this account can be fetched via a GET request.
  90. Certificates string
  91. }
  92. // Directory is ACME server discovery data.
  93. type Directory struct {
  94. // RegURL is an account endpoint URL, allowing for creating new
  95. // and modifying existing accounts.
  96. RegURL string
  97. // AuthzURL is used to initiate Identifier Authorization flow.
  98. AuthzURL string
  99. // CertURL is a new certificate issuance endpoint URL.
  100. CertURL string
  101. // RevokeURL is used to initiate a certificate revocation flow.
  102. RevokeURL string
  103. // Term is a URI identifying the current terms of service.
  104. Terms string
  105. // Website is an HTTP or HTTPS URL locating a website
  106. // providing more information about the ACME server.
  107. Website string
  108. // CAA consists of lowercase hostname elements, which the ACME server
  109. // recognises as referring to itself for the purposes of CAA record validation
  110. // as defined in RFC6844.
  111. CAA []string
  112. }
  113. // Challenge encodes a returned CA challenge.
  114. // Its Error field may be non-nil if the challenge is part of an Authorization
  115. // with StatusInvalid.
  116. type Challenge struct {
  117. // Type is the challenge type, e.g. "http-01", "tls-sni-02", "dns-01".
  118. Type string
  119. // URI is where a challenge response can be posted to.
  120. URI string
  121. // Token is a random value that uniquely identifies the challenge.
  122. Token string
  123. // Status identifies the status of this challenge.
  124. Status string
  125. // Error indicates the reason for an authorization failure
  126. // when this challenge was used.
  127. // The type of a non-nil value is *Error.
  128. Error error
  129. }
  130. // Authorization encodes an authorization response.
  131. type Authorization struct {
  132. // URI uniquely identifies a authorization.
  133. URI string
  134. // Status identifies the status of an authorization.
  135. Status string
  136. // Identifier is what the account is authorized to represent.
  137. Identifier AuthzID
  138. // Challenges that the client needs to fulfill in order to prove possession
  139. // of the identifier (for pending authorizations).
  140. // For final authorizations, the challenges that were used.
  141. Challenges []*Challenge
  142. // A collection of sets of challenges, each of which would be sufficient
  143. // to prove possession of the identifier.
  144. // Clients must complete a set of challenges that covers at least one set.
  145. // Challenges are identified by their indices in the challenges array.
  146. // If this field is empty, the client needs to complete all challenges.
  147. Combinations [][]int
  148. }
  149. // AuthzID is an identifier that an account is authorized to represent.
  150. type AuthzID struct {
  151. Type string // The type of identifier, e.g. "dns".
  152. Value string // The identifier itself, e.g. "example.org".
  153. }
  154. // wireAuthz is ACME JSON representation of Authorization objects.
  155. type wireAuthz struct {
  156. Status string
  157. Challenges []wireChallenge
  158. Combinations [][]int
  159. Identifier struct {
  160. Type string
  161. Value string
  162. }
  163. }
  164. func (z *wireAuthz) authorization(uri string) *Authorization {
  165. a := &Authorization{
  166. URI: uri,
  167. Status: z.Status,
  168. Identifier: AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value},
  169. Combinations: z.Combinations, // shallow copy
  170. Challenges: make([]*Challenge, len(z.Challenges)),
  171. }
  172. for i, v := range z.Challenges {
  173. a.Challenges[i] = v.challenge()
  174. }
  175. return a
  176. }
  177. func (z *wireAuthz) error(uri string) *AuthorizationError {
  178. err := &AuthorizationError{
  179. URI: uri,
  180. Identifier: z.Identifier.Value,
  181. }
  182. for _, raw := range z.Challenges {
  183. if raw.Error != nil {
  184. err.Errors = append(err.Errors, raw.Error.error(nil))
  185. }
  186. }
  187. return err
  188. }
  189. // wireChallenge is ACME JSON challenge representation.
  190. type wireChallenge struct {
  191. URI string `json:"uri"`
  192. Type string
  193. Token string
  194. Status string
  195. Error *wireError
  196. }
  197. func (c *wireChallenge) challenge() *Challenge {
  198. v := &Challenge{
  199. URI: c.URI,
  200. Type: c.Type,
  201. Token: c.Token,
  202. Status: c.Status,
  203. }
  204. if v.Status == "" {
  205. v.Status = StatusPending
  206. }
  207. if c.Error != nil {
  208. v.Error = c.Error.error(nil)
  209. }
  210. return v
  211. }
  212. // wireError is a subset of fields of the Problem Details object
  213. // as described in https://tools.ietf.org/html/rfc7807#section-3.1.
  214. type wireError struct {
  215. Status int
  216. Type string
  217. Detail string
  218. }
  219. func (e *wireError) error(h http.Header) *Error {
  220. return &Error{
  221. StatusCode: e.Status,
  222. ProblemType: e.Type,
  223. Detail: e.Detail,
  224. Header: h,
  225. }
  226. }