You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

330 lines
9.3 KiB

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