rfc8555.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. // Copyright 2019 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. "context"
  7. "crypto"
  8. "encoding/base64"
  9. "encoding/json"
  10. "encoding/pem"
  11. "errors"
  12. "fmt"
  13. "io"
  14. "io/ioutil"
  15. "net/http"
  16. "time"
  17. )
  18. // DeactivateReg permanently disables an existing account associated with c.Key.
  19. // A deactivated account can no longer request certificate issuance or access
  20. // resources related to the account, such as orders or authorizations.
  21. //
  22. // It only works with CAs implementing RFC 8555.
  23. func (c *Client) DeactivateReg(ctx context.Context) error {
  24. url := string(c.accountKID(ctx))
  25. if url == "" {
  26. return ErrNoAccount
  27. }
  28. req := json.RawMessage(`{"status": "deactivated"}`)
  29. res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
  30. if err != nil {
  31. return err
  32. }
  33. res.Body.Close()
  34. return nil
  35. }
  36. // registerRFC is quivalent to c.Register but for CAs implementing RFC 8555.
  37. // It expects c.Discover to have already been called.
  38. // TODO: Implement externalAccountBinding.
  39. func (c *Client) registerRFC(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) {
  40. c.cacheMu.Lock() // guard c.kid access
  41. defer c.cacheMu.Unlock()
  42. req := struct {
  43. TermsAgreed bool `json:"termsOfServiceAgreed,omitempty"`
  44. Contact []string `json:"contact,omitempty"`
  45. }{
  46. Contact: acct.Contact,
  47. }
  48. if c.dir.Terms != "" {
  49. req.TermsAgreed = prompt(c.dir.Terms)
  50. }
  51. res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus(
  52. http.StatusOK, // account with this key already registered
  53. http.StatusCreated, // new account created
  54. ))
  55. if err != nil {
  56. return nil, err
  57. }
  58. defer res.Body.Close()
  59. a, err := responseAccount(res)
  60. if err != nil {
  61. return nil, err
  62. }
  63. // Cache Account URL even if we return an error to the caller.
  64. // It is by all means a valid and usable "kid" value for future requests.
  65. c.kid = keyID(a.URI)
  66. if res.StatusCode == http.StatusOK {
  67. return nil, ErrAccountAlreadyExists
  68. }
  69. return a, nil
  70. }
  71. // updateGegRFC is equivalent to c.UpdateReg but for CAs implementing RFC 8555.
  72. // It expects c.Discover to have already been called.
  73. func (c *Client) updateRegRFC(ctx context.Context, a *Account) (*Account, error) {
  74. url := string(c.accountKID(ctx))
  75. if url == "" {
  76. return nil, ErrNoAccount
  77. }
  78. req := struct {
  79. Contact []string `json:"contact,omitempty"`
  80. }{
  81. Contact: a.Contact,
  82. }
  83. res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
  84. if err != nil {
  85. return nil, err
  86. }
  87. defer res.Body.Close()
  88. return responseAccount(res)
  89. }
  90. // getGegRFC is equivalent to c.GetReg but for CAs implementing RFC 8555.
  91. // It expects c.Discover to have already been called.
  92. func (c *Client) getRegRFC(ctx context.Context) (*Account, error) {
  93. req := json.RawMessage(`{"onlyReturnExisting": true}`)
  94. res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus(http.StatusOK))
  95. if e, ok := err.(*Error); ok && e.ProblemType == "urn:ietf:params:acme:error:accountDoesNotExist" {
  96. return nil, ErrNoAccount
  97. }
  98. if err != nil {
  99. return nil, err
  100. }
  101. defer res.Body.Close()
  102. return responseAccount(res)
  103. }
  104. func responseAccount(res *http.Response) (*Account, error) {
  105. var v struct {
  106. Status string
  107. Contact []string
  108. Orders string
  109. }
  110. if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
  111. return nil, fmt.Errorf("acme: invalid account response: %v", err)
  112. }
  113. return &Account{
  114. URI: res.Header.Get("Location"),
  115. Status: v.Status,
  116. Contact: v.Contact,
  117. OrdersURL: v.Orders,
  118. }, nil
  119. }
  120. // AuthorizeOrder initiates the order-based application for certificate issuance,
  121. // as opposed to pre-authorization in Authorize.
  122. // It is only supported by CAs implementing RFC 8555.
  123. //
  124. // The caller then needs to fetch each authorization with GetAuthorization,
  125. // identify those with StatusPending status and fulfill a challenge using Accept.
  126. // Once all authorizations are satisfied, the caller will typically want to poll
  127. // order status using WaitOrder until it's in StatusReady state.
  128. // To finalize the order and obtain a certificate, the caller submits a CSR with CreateOrderCert.
  129. func (c *Client) AuthorizeOrder(ctx context.Context, id []AuthzID, opt ...OrderOption) (*Order, error) {
  130. dir, err := c.Discover(ctx)
  131. if err != nil {
  132. return nil, err
  133. }
  134. req := struct {
  135. Identifiers []wireAuthzID `json:"identifiers"`
  136. NotBefore string `json:"notBefore,omitempty"`
  137. NotAfter string `json:"notAfter,omitempty"`
  138. }{}
  139. for _, v := range id {
  140. req.Identifiers = append(req.Identifiers, wireAuthzID{
  141. Type: v.Type,
  142. Value: v.Value,
  143. })
  144. }
  145. for _, o := range opt {
  146. switch o := o.(type) {
  147. case orderNotBeforeOpt:
  148. req.NotBefore = time.Time(o).Format(time.RFC3339)
  149. case orderNotAfterOpt:
  150. req.NotAfter = time.Time(o).Format(time.RFC3339)
  151. default:
  152. // Package's fault if we let this happen.
  153. panic(fmt.Sprintf("unsupported order option type %T", o))
  154. }
  155. }
  156. res, err := c.post(ctx, nil, dir.OrderURL, req, wantStatus(http.StatusCreated))
  157. if err != nil {
  158. return nil, err
  159. }
  160. defer res.Body.Close()
  161. return responseOrder(res)
  162. }
  163. // GetOrder retrives an order identified by the given URL.
  164. // For orders created with AuthorizeOrder, the url value is Order.URI.
  165. //
  166. // If a caller needs to poll an order until its status is final,
  167. // see the WaitOrder method.
  168. func (c *Client) GetOrder(ctx context.Context, url string) (*Order, error) {
  169. if _, err := c.Discover(ctx); err != nil {
  170. return nil, err
  171. }
  172. res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
  173. if err != nil {
  174. return nil, err
  175. }
  176. defer res.Body.Close()
  177. return responseOrder(res)
  178. }
  179. // WaitOrder polls an order from the given URL until it is in one of the final states,
  180. // StatusReady, StatusValid or StatusInvalid, the CA responded with a non-retryable error
  181. // or the context is done.
  182. //
  183. // It returns a non-nil Order only if its Status is StatusReady or StatusValid.
  184. // In all other cases WaitOrder returns an error.
  185. // If the Status is StatusInvalid, the returned error is of type *OrderError.
  186. func (c *Client) WaitOrder(ctx context.Context, url string) (*Order, error) {
  187. if _, err := c.Discover(ctx); err != nil {
  188. return nil, err
  189. }
  190. for {
  191. res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
  192. if err != nil {
  193. return nil, err
  194. }
  195. o, err := responseOrder(res)
  196. res.Body.Close()
  197. switch {
  198. case err != nil:
  199. // Skip and retry.
  200. case o.Status == StatusInvalid:
  201. return nil, &OrderError{OrderURL: o.URI, Status: o.Status}
  202. case o.Status == StatusReady || o.Status == StatusValid:
  203. return o, nil
  204. }
  205. d := retryAfter(res.Header.Get("Retry-After"))
  206. if d == 0 {
  207. // Default retry-after.
  208. // Same reasoning as in WaitAuthorization.
  209. d = time.Second
  210. }
  211. t := time.NewTimer(d)
  212. select {
  213. case <-ctx.Done():
  214. t.Stop()
  215. return nil, ctx.Err()
  216. case <-t.C:
  217. // Retry.
  218. }
  219. }
  220. }
  221. func responseOrder(res *http.Response) (*Order, error) {
  222. var v struct {
  223. Status string
  224. Expires time.Time
  225. Identifiers []wireAuthzID
  226. NotBefore time.Time
  227. NotAfter time.Time
  228. Error *wireError
  229. Authorizations []string
  230. Finalize string
  231. Certificate string
  232. }
  233. if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
  234. return nil, fmt.Errorf("acme: error reading order: %v", err)
  235. }
  236. o := &Order{
  237. URI: res.Header.Get("Location"),
  238. Status: v.Status,
  239. Expires: v.Expires,
  240. NotBefore: v.NotBefore,
  241. NotAfter: v.NotAfter,
  242. AuthzURLs: v.Authorizations,
  243. FinalizeURL: v.Finalize,
  244. CertURL: v.Certificate,
  245. }
  246. for _, id := range v.Identifiers {
  247. o.Identifiers = append(o.Identifiers, AuthzID{Type: id.Type, Value: id.Value})
  248. }
  249. if v.Error != nil {
  250. o.Error = v.Error.error(nil /* headers */)
  251. }
  252. return o, nil
  253. }
  254. // CreateOrderCert submits the CSR (Certificate Signing Request) to a CA at the specified URL.
  255. // The URL is the FinalizeURL field of an Order created with AuthorizeOrder.
  256. //
  257. // If the bundle argument is true, the returned value also contain the CA (issuer)
  258. // certificate chain. Otherwise, only a leaf certificate is returned.
  259. // The returned URL can be used to re-fetch the certificate using FetchCert.
  260. //
  261. // This method is only supported by CAs implementing RFC 8555. See CreateCert for pre-RFC CAs.
  262. //
  263. // CreateOrderCert returns an error if the CA's response is unreasonably large.
  264. // Callers are encouraged to parse the returned value to ensure the certificate is valid and has the expected features.
  265. func (c *Client) CreateOrderCert(ctx context.Context, url string, csr []byte, bundle bool) (der [][]byte, certURL string, err error) {
  266. if _, err := c.Discover(ctx); err != nil { // required by c.accountKID
  267. return nil, "", err
  268. }
  269. // RFC describes this as "finalize order" request.
  270. req := struct {
  271. CSR string `json:"csr"`
  272. }{
  273. CSR: base64.RawURLEncoding.EncodeToString(csr),
  274. }
  275. res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
  276. if err != nil {
  277. return nil, "", err
  278. }
  279. defer res.Body.Close()
  280. o, err := responseOrder(res)
  281. if err != nil {
  282. return nil, "", err
  283. }
  284. // Wait for CA to issue the cert if they haven't.
  285. if o.Status != StatusValid {
  286. o, err = c.WaitOrder(ctx, o.URI)
  287. }
  288. if err != nil {
  289. return nil, "", err
  290. }
  291. // The only acceptable status post finalize and WaitOrder is "valid".
  292. if o.Status != StatusValid {
  293. return nil, "", &OrderError{OrderURL: o.URI, Status: o.Status}
  294. }
  295. crt, err := c.fetchCertRFC(ctx, o.CertURL, bundle)
  296. return crt, o.CertURL, err
  297. }
  298. // fetchCertRFC downloads issued certificate from the given URL.
  299. // It expects the CA to respond with PEM-encoded certificate chain.
  300. //
  301. // The URL argument is the CertURL field of Order.
  302. func (c *Client) fetchCertRFC(ctx context.Context, url string, bundle bool) ([][]byte, error) {
  303. res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
  304. if err != nil {
  305. return nil, err
  306. }
  307. defer res.Body.Close()
  308. // Get all the bytes up to a sane maximum.
  309. // Account very roughly for base64 overhead.
  310. const max = maxCertChainSize + maxCertChainSize/33
  311. b, err := ioutil.ReadAll(io.LimitReader(res.Body, max+1))
  312. if err != nil {
  313. return nil, fmt.Errorf("acme: fetch cert response stream: %v", err)
  314. }
  315. if len(b) > max {
  316. return nil, errors.New("acme: certificate chain is too big")
  317. }
  318. // Decode PEM chain.
  319. var chain [][]byte
  320. for {
  321. var p *pem.Block
  322. p, b = pem.Decode(b)
  323. if p == nil {
  324. break
  325. }
  326. if p.Type != "CERTIFICATE" {
  327. return nil, fmt.Errorf("acme: invalid PEM cert type %q", p.Type)
  328. }
  329. chain = append(chain, p.Bytes)
  330. if !bundle {
  331. return chain, nil
  332. }
  333. if len(chain) > maxChainLen {
  334. return nil, errors.New("acme: certificate chain is too long")
  335. }
  336. }
  337. if len(chain) == 0 {
  338. return nil, errors.New("acme: certificate chain is empty")
  339. }
  340. return chain, nil
  341. }
  342. // sends a cert revocation request in either JWK form when key is non-nil or KID form otherwise.
  343. func (c *Client) revokeCertRFC(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error {
  344. req := &struct {
  345. Cert string `json:"certificate"`
  346. Reason int `json:"reason"`
  347. }{
  348. Cert: base64.RawURLEncoding.EncodeToString(cert),
  349. Reason: int(reason),
  350. }
  351. res, err := c.post(ctx, key, c.dir.RevokeURL, req, wantStatus(http.StatusOK))
  352. if err != nil {
  353. if isAlreadyRevoked(err) {
  354. // Assume it is not an error to revoke an already revoked cert.
  355. return nil
  356. }
  357. return err
  358. }
  359. defer res.Body.Close()
  360. return nil
  361. }
  362. func isAlreadyRevoked(err error) bool {
  363. e, ok := err.(*Error)
  364. return ok && e.ProblemType == "urn:ietf:params:acme:error:alreadyRevoked"
  365. }