ACMEv2 client library for Go.

types.go 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. package acmeapi
  2. import (
  3. "crypto"
  4. "encoding/json"
  5. "fmt"
  6. "gopkg.in/square/go-jose.v2"
  7. "time"
  8. )
  9. // RFC7807 problem document. These structures are used by an ACME endpoint to
  10. // return error information.
  11. type Problem struct {
  12. // URI representing the problem type. Typically an URN.
  13. Type string `json:"type,omitempty"`
  14. // One-line summary of the error.
  15. Title string `json:"title,omitempty"`
  16. // HTTP status code (optional). If present, this should match the actual HTTP
  17. // status code returned. Advisory use only.
  18. Status int `json:"status,omitempty"`
  19. // More detailed explanation of the error.
  20. Detail string `json:"detail,omitempty"`
  21. // Optional, potentially relative URI identifying the specific problem.
  22. // May refer to an object which relates to the problem, etc.
  23. Instance string `json:"instance,omitempty"`
  24. // ACME-specific. Optional. List of problems which constitute components of
  25. // this problem.
  26. Subproblem []*Problem `json:"subproblems,omitempty"`
  27. // ACME-specific. Optional. Identifier relating to this problem.
  28. Identifier *Identifier `json:"identifier,omitempty"`
  29. }
  30. func (p *Problem) Error() string {
  31. extra := ""
  32. for _, sp := range p.Subproblem {
  33. extra += ";\n " + sp.Error()
  34. }
  35. return fmt.Sprintf("problem of type %q (%q, %v): %v: %v%s", p.Type, p.Instance, p.Identifier, p.Title, p.Detail, extra)
  36. }
  37. // Represents an identifier for a resource for which authorization is required.
  38. type Identifier struct {
  39. // The type of the identifier.
  40. Type IdentifierType `json:"type"`
  41. // The identifier string. The format is determined by Type.
  42. Value string `json:"value"`
  43. }
  44. func (id *Identifier) String() string {
  45. return fmt.Sprintf("Identifier(%q, %q)", id.Type, id.Value)
  46. }
  47. // A type of Identifier. Currently, the only supported value is "dns".
  48. type IdentifierType string
  49. const (
  50. // Indicates that the identifier value is a DNS name.
  51. IdentifierTypeDNS IdentifierType = "dns"
  52. )
  53. // ---------------------------------------------------------------------------------------------------------
  54. // Represents an account.
  55. type Account struct {
  56. // The URL of the account.
  57. URL string `json:"-"`
  58. // Private key used to authorize requests. This is never sent to any server,
  59. // but is used to sign requests when passed as an argument to RealmClient
  60. // methods.
  61. PrivateKey crypto.PrivateKey `json:"-"`
  62. // Account public key.
  63. //
  64. // Always sent by the server; cannot be modified directly by client (use the
  65. // ChangeKey method).
  66. Key *jose.JSONWebKey `json:"key,omitempty"`
  67. // Account status.
  68. //
  69. // Always sent by server. Cannot be directly modified by client in general,
  70. // except that a client may set this to AccountDeactivated ("deactivated") to
  71. // request deactivation. This is the only client-initiated change to this
  72. // field allowed.
  73. Status AccountStatus `json:"status,omitempty"`
  74. // Contact URIs which may be used to contact the accountholder.
  75. //
  76. // Most realms will accept e. mail addresses expressed as “mailto:” URIs
  77. // here. Some realms may accept “tel:” URIs. Acceptance of other URIs is in
  78. // practice unlikely, and may result in rejection by the server.
  79. //
  80. // Always sent by the server, and may be sent by client to modify the current
  81. // value. If this field is not specified when registering, the account will
  82. // have no contact URIs, and if the field is not specified when updating the
  83. // account, the current set of contact URIs will be left unchanged.
  84. ContactURIs []string `json:"contact,omitempty"`
  85. // Whether the client agrees/has agreed to the terms of service.
  86. //
  87. // Always sent by the server, and may be sent by client to indicate assent.
  88. TermsOfServiceAgreed bool `json:"termsOfServiceAgreed,omitempty"`
  89. // URL at which the orders attached to the account can be enumerated.
  90. //
  91. // Always sent by server, if enumeration is supported. Read only.
  92. OrdersURL string `json:"orders,omitempty"`
  93. }
  94. // Specifies a current account status.
  95. type AccountStatus string
  96. const (
  97. // The account is usable. This is the initial state.
  98. AccountValid AccountStatus = "valid"
  99. // The account is no longer usable, by accountholder request. This is a final
  100. // state. This is the only state which can be explicitly requested by the
  101. // client by setting it as the Status field.
  102. AccountDeactivated = "deactivated"
  103. // The account is no longer usable, due to administrative action.
  104. // This is a final state.
  105. AccountRevoked = "revoked"
  106. )
  107. // Returns true iff the account status is a recognised account status value.
  108. func (s AccountStatus) IsWellFormed() bool {
  109. switch s {
  110. case "valid", "deactivated", "revoked":
  111. return true
  112. default:
  113. return false
  114. }
  115. }
  116. // Returns true iff the account status is a final status.
  117. func (s AccountStatus) IsFinal() bool {
  118. switch s {
  119. case "deactivated", "revoked":
  120. return true
  121. default:
  122. return false
  123. }
  124. }
  125. // Implements encoding/json.Unmarshaler.
  126. func (s *AccountStatus) UnmarshalJSON(data []byte) error {
  127. var ss string
  128. err := json.Unmarshal(data, &ss)
  129. if err != nil {
  130. return err
  131. }
  132. if !AccountStatus(ss).IsWellFormed() {
  133. return fmt.Errorf("not a valid status: %#v", ss)
  134. }
  135. *s = AccountStatus(ss)
  136. return nil
  137. }
  138. // ---------------------------------------------------------------------------------------------------------
  139. // Represents a request for a certificate.
  140. type Order struct {
  141. // The URL of the order.
  142. URL string `json:"-"`
  143. // Order status.
  144. //
  145. // Always sent by server; read-only.
  146. Status OrderStatus `json:"status,omitempty"`
  147. // Time at which the order expires.
  148. //
  149. // Sent by server if status is "pending" or "valid". Read only.
  150. Expires time.Time `json:"expires,omitempty"` // RFC 3339
  151. // The identifiers that the order pertains to.
  152. Identifiers []Identifier `json:"identifiers,omitempty"`
  153. // DER-encoded X.509 CSR.
  154. //
  155. // Must be sent by client at resource creation time. Always sent by server
  156. // and is immutable after resource creation.
  157. //CSR denet.Base64up `json:"csr,omitempty"`
  158. // Optionally sent by client at order creation time to constrain certificate
  159. // validity period.
  160. //
  161. // Always sent by server and is immutable after resource creation.
  162. NotBefore time.Time `json:"notBefore,omitempty"` // RFC 3339
  163. NotAfter time.Time `json:"notAfter,omitempty"` // RFC 3339
  164. // An error which occurred during the processing of the order, if any.
  165. Error *Problem `json:"error,omitempty"` // RFC7807
  166. // List of URLs to authorization objects. All of the authorizations must be
  167. // completed to cause issuance. Issuance will commence as soon as all
  168. // authorizations are completed. Some authorizations may already be completed
  169. // when the order is created.
  170. //
  171. // Always sent by server. Read only.
  172. AuthorizationURLs []string `json:"authorizations,omitempty"`
  173. // An URL for submitting a CSR.
  174. FinalizeURL string `json:"finalize,omitempty"`
  175. // URL from which the certificate can be downloaded.
  176. //
  177. // Sent by server, but only when state is "valid". Read only.
  178. CertificateURL string `json:"certificate,omitempty"`
  179. retryAt time.Time
  180. }
  181. // Specifies an order status.
  182. type OrderStatus string
  183. const (
  184. // The order is waiting for one or more client actions before issuance
  185. // occurs. This is the initial state.
  186. OrderPending OrderStatus = "pending"
  187. // All preconditions to order fulfilment have been completed, and now the
  188. // order is simply waiting for a client to invoke the finalize operation. The
  189. // order will then transition to "processing".
  190. OrderReady = "ready"
  191. // Issuance is underway, and the state will transition to "valid" or
  192. // "invalid" automatically.
  193. OrderProcessing = "processing"
  194. // The order is valid. The certificate has been issued and can be retrieved.
  195. // This is a final state.
  196. OrderValid = "valid"
  197. // The certificate issuance request has failed.
  198. // This is a final state.
  199. OrderInvalid = "invalid"
  200. )
  201. // Returns true iff the order status is a recognised order status value.
  202. func (s OrderStatus) IsWellFormed() bool {
  203. switch s {
  204. case "pending", "ready", "processing", "valid", "invalid":
  205. return true
  206. default:
  207. return false
  208. }
  209. }
  210. // Returns true iff the order status is a final status.
  211. func (s OrderStatus) IsFinal() bool {
  212. switch s {
  213. case "valid", "invalid": // TODO
  214. return true
  215. default:
  216. return false
  217. }
  218. }
  219. // Implements encoding/json.Unmarshaler.
  220. func (s *OrderStatus) UnmarshalJSON(data []byte) error {
  221. var ss string
  222. err := json.Unmarshal(data, &ss)
  223. if err != nil {
  224. return err
  225. }
  226. if !OrderStatus(ss).IsWellFormed() {
  227. return fmt.Errorf("not a valid status: %#v", ss)
  228. }
  229. *s = OrderStatus(ss)
  230. return nil
  231. }
  232. // ---------------------------------------------------------------------------------------------------------
  233. // Represents an authorization which must be completed to enable certificate
  234. // issuance.
  235. type Authorization struct {
  236. // The URL of the authorization.
  237. URL string `json:"-"`
  238. // The identifier for which authorization is required.
  239. //
  240. // Sent by server. Read only.
  241. Identifier Identifier `json:"identifier,omitempty"`
  242. // The status of the authorization.
  243. //
  244. // Sent by server. Read only.
  245. Status AuthorizationStatus `json:"status,omitempty"`
  246. // The expiry time of the authorization.
  247. //
  248. // May be sent by server; always sent if status is "valid". Read only.
  249. Expires time.Time `json:"expires,omitempty"`
  250. // True if the authorization is for a wildcard domain name.
  251. Wildcard bool `json:"wildcard,omitempty"`
  252. // Array of Challenge objects. Any one challenge in the array must be
  253. // completed to complete the authorization.
  254. //
  255. // Always sent by server. Read only.
  256. Challenges []Challenge `json:"challenges,omitempty"`
  257. retryAt time.Time
  258. }
  259. // Specifies an authorization status.
  260. type AuthorizationStatus string
  261. const (
  262. // The authorization is waiting for one or more client actions before
  263. // it becomes valid. This is the initial state.
  264. AuthorizationPending AuthorizationStatus = "pending"
  265. // The authorization is valid.
  266. // The only state transition possible is to "revoked".
  267. AuthorizationValid = "valid"
  268. // The authorization is invalid.
  269. // This is a final state.
  270. AuthorizationInvalid = "invalid"
  271. // The authorization is deactivated.
  272. // This is a final state.
  273. AuthorizationDeactivated = "deactivated"
  274. // The authorization has been revoked.
  275. // This is a final state.
  276. AuthorizationRevoked = "revoked"
  277. )
  278. // Returns true iff the authorization status is a recognised authorization
  279. // status value.
  280. func (s AuthorizationStatus) IsWellFormed() bool {
  281. switch s {
  282. case "pending", "valid", "invalid", "deactivated", "revoked":
  283. return true
  284. default:
  285. return false
  286. }
  287. }
  288. // Returns true iff the authorization status is a final status.
  289. func (s AuthorizationStatus) IsFinal() bool {
  290. switch s {
  291. case "valid", "invalid", "deactivated", "revoked":
  292. return true
  293. default:
  294. return false
  295. }
  296. }
  297. // Implements encoding/json.Unmarshaler.
  298. func (s *AuthorizationStatus) UnmarshalJSON(data []byte) error {
  299. var ss string
  300. err := json.Unmarshal(data, &ss)
  301. if err != nil {
  302. return err
  303. }
  304. if !AuthorizationStatus(ss).IsWellFormed() {
  305. return fmt.Errorf("not a valid status: %#v", ss)
  306. }
  307. *s = AuthorizationStatus(ss)
  308. return nil
  309. }
  310. // ---------------------------------------------------------------------------------------------------------
  311. // Represents a challenge which may be completed to satisfy an authorization
  312. // requirement.
  313. type Challenge struct {
  314. // The URL of the challenge object.
  315. //
  316. // Always sent by server. Read only.
  317. URL string `json:"url,omitempty"`
  318. // The challenge type.
  319. //
  320. // Always sent by server. Read only.
  321. Type string `json:"type,omitempty"`
  322. // The challenge status. Always sent by the server.
  323. Status ChallengeStatus `json:"status,omitempty"`
  324. // The time at which the challenge was successfully validated. Optional
  325. // unless Status is ChallengeValid.
  326. Validated time.Time `json:"validated,omitempty"` // RFC 3339
  327. // Error that occurred while the server was validating the challenge, if any.
  328. // Multiple errors are indicated using subproblems. This should (but is not
  329. // guaranteed to) be present if Status is StatusInvalid.
  330. Error *Problem `json:"error,omitempty"`
  331. // Sent for http-01, tls-sni-02, dns-01.
  332. Token string `json:"token,omitempty"`
  333. retryAt time.Time
  334. }
  335. // Specifies a challenge status.
  336. type ChallengeStatus string
  337. const (
  338. // The challenge is waiting to be initiated by client action before
  339. // verification occurs. This is the initial state.
  340. ChallengePending ChallengeStatus = "pending"
  341. // The challenge moves from the pending state to the processing state once
  342. // the client has initiated the challenge. The status will autonomously
  343. // advance to ChallengeValid or ChallengeInvalid.
  344. ChallengeProcessing = "processing"
  345. // Verification has succeeded. This is a final state.
  346. ChallengeValid = "valid"
  347. // Verification has failed. This is a final state.
  348. ChallengeInvalid = "invalid"
  349. )
  350. // Returns true iff the challenge status is a recognised challenge status
  351. // value.
  352. func (s ChallengeStatus) IsWellFormed() bool {
  353. switch s {
  354. case "pending", "processing", "valid", "invalid":
  355. return true
  356. default:
  357. return false
  358. }
  359. }
  360. // Returns true iff the challenge status is a final status.
  361. func (s ChallengeStatus) IsFinal() bool {
  362. switch s {
  363. case "valid", "invalid":
  364. return true
  365. default:
  366. return false
  367. }
  368. }
  369. // Implements encoding/json.Unmarshaler.
  370. func (s *ChallengeStatus) UnmarshalJSON(data []byte) error {
  371. var ss string
  372. err := json.Unmarshal(data, &ss)
  373. if err != nil {
  374. return err
  375. }
  376. if !ChallengeStatus(ss).IsWellFormed() {
  377. return fmt.Errorf("not a valid status: %#v", ss)
  378. }
  379. *s = ChallengeStatus(ss)
  380. return nil
  381. }
  382. // ---------------------------------------------------------------------------------------------------------
  383. // Represents a certificate which has been issued.
  384. type Certificate struct {
  385. // The URL of the certificate resource.
  386. URL string `json:"-"`
  387. // The chain of certificates which a TLS server should send to a client in
  388. // order to facilitate client verification. A slice of DER-encoded
  389. // certificates. The first certificate is the end-entity certificate, the
  390. // second certificate if any is the issuing intermediate certificate, etc.
  391. //
  392. // Does not generally include the root certificate. If you need it (e.g.
  393. // because you are using DANE) you must append it yourself.
  394. CertificateChain [][]byte `json:"-"`
  395. }