acme_test.go 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432
  1. // Copyright 2015 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. "bytes"
  7. "context"
  8. "crypto/rand"
  9. "crypto/rsa"
  10. "crypto/tls"
  11. "crypto/x509"
  12. "crypto/x509/pkix"
  13. "encoding/base64"
  14. "encoding/hex"
  15. "encoding/json"
  16. "fmt"
  17. "io"
  18. "math/big"
  19. "net/http"
  20. "net/http/httptest"
  21. "reflect"
  22. "sort"
  23. "strings"
  24. "testing"
  25. "time"
  26. )
  27. // newTestClient creates a client with a non-nil Directory so that it skips
  28. // the discovery which is otherwise done on the first call of almost every
  29. // exported method.
  30. func newTestClient() *Client {
  31. return &Client{
  32. Key: testKeyEC,
  33. dir: &Directory{}, // skip discovery
  34. }
  35. }
  36. // Decodes a JWS-encoded request and unmarshals the decoded JSON into a provided
  37. // interface.
  38. func decodeJWSRequest(t *testing.T, v interface{}, r io.Reader) {
  39. // Decode request
  40. var req struct{ Payload string }
  41. if err := json.NewDecoder(r).Decode(&req); err != nil {
  42. t.Fatal(err)
  43. }
  44. payload, err := base64.RawURLEncoding.DecodeString(req.Payload)
  45. if err != nil {
  46. t.Fatal(err)
  47. }
  48. err = json.Unmarshal(payload, v)
  49. if err != nil {
  50. t.Fatal(err)
  51. }
  52. }
  53. type jwsHead struct {
  54. Alg string
  55. Nonce string
  56. URL string `json:"url"`
  57. KID string `json:"kid"`
  58. JWK map[string]string `json:"jwk"`
  59. }
  60. func decodeJWSHead(r io.Reader) (*jwsHead, error) {
  61. var req struct{ Protected string }
  62. if err := json.NewDecoder(r).Decode(&req); err != nil {
  63. return nil, err
  64. }
  65. b, err := base64.RawURLEncoding.DecodeString(req.Protected)
  66. if err != nil {
  67. return nil, err
  68. }
  69. var head jwsHead
  70. if err := json.Unmarshal(b, &head); err != nil {
  71. return nil, err
  72. }
  73. return &head, nil
  74. }
  75. func TestDiscover(t *testing.T) {
  76. const (
  77. reg = "https://example.com/acme/new-reg"
  78. authz = "https://example.com/acme/new-authz"
  79. cert = "https://example.com/acme/new-cert"
  80. revoke = "https://example.com/acme/revoke-cert"
  81. )
  82. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  83. w.Header().Set("Content-Type", "application/json")
  84. w.Header().Set("Replay-Nonce", "testnonce")
  85. fmt.Fprintf(w, `{
  86. "new-reg": %q,
  87. "new-authz": %q,
  88. "new-cert": %q,
  89. "revoke-cert": %q
  90. }`, reg, authz, cert, revoke)
  91. }))
  92. defer ts.Close()
  93. c := Client{DirectoryURL: ts.URL}
  94. dir, err := c.Discover(context.Background())
  95. if err != nil {
  96. t.Fatal(err)
  97. }
  98. if dir.RegURL != reg {
  99. t.Errorf("dir.RegURL = %q; want %q", dir.RegURL, reg)
  100. }
  101. if dir.AuthzURL != authz {
  102. t.Errorf("dir.AuthzURL = %q; want %q", dir.AuthzURL, authz)
  103. }
  104. if dir.CertURL != cert {
  105. t.Errorf("dir.CertURL = %q; want %q", dir.CertURL, cert)
  106. }
  107. if dir.RevokeURL != revoke {
  108. t.Errorf("dir.RevokeURL = %q; want %q", dir.RevokeURL, revoke)
  109. }
  110. if _, exist := c.nonces["testnonce"]; !exist {
  111. t.Errorf("c.nonces = %q; want 'testnonce' in the map", c.nonces)
  112. }
  113. }
  114. func TestRegister(t *testing.T) {
  115. contacts := []string{"mailto:admin@example.com"}
  116. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  117. if r.Method == "HEAD" {
  118. w.Header().Set("Replay-Nonce", "test-nonce")
  119. return
  120. }
  121. if r.Method != "POST" {
  122. t.Errorf("r.Method = %q; want POST", r.Method)
  123. }
  124. var j struct {
  125. Resource string
  126. Contact []string
  127. Agreement string
  128. }
  129. decodeJWSRequest(t, &j, r.Body)
  130. // Test request
  131. if j.Resource != "new-reg" {
  132. t.Errorf("j.Resource = %q; want new-reg", j.Resource)
  133. }
  134. if !reflect.DeepEqual(j.Contact, contacts) {
  135. t.Errorf("j.Contact = %v; want %v", j.Contact, contacts)
  136. }
  137. w.Header().Set("Location", "https://ca.tld/acme/reg/1")
  138. w.Header().Set("Link", `<https://ca.tld/acme/new-authz>;rel="next"`)
  139. w.Header().Add("Link", `<https://ca.tld/acme/recover-reg>;rel="recover"`)
  140. w.Header().Add("Link", `<https://ca.tld/acme/terms>;rel="terms-of-service"`)
  141. w.WriteHeader(http.StatusCreated)
  142. b, _ := json.Marshal(contacts)
  143. fmt.Fprintf(w, `{"contact": %s}`, b)
  144. }))
  145. defer ts.Close()
  146. prompt := func(url string) bool {
  147. const terms = "https://ca.tld/acme/terms"
  148. if url != terms {
  149. t.Errorf("prompt url = %q; want %q", url, terms)
  150. }
  151. return false
  152. }
  153. c := Client{
  154. Key: testKeyEC,
  155. DirectoryURL: ts.URL,
  156. dir: &Directory{RegURL: ts.URL},
  157. }
  158. a := &Account{Contact: contacts}
  159. var err error
  160. if a, err = c.Register(context.Background(), a, prompt); err != nil {
  161. t.Fatal(err)
  162. }
  163. if a.URI != "https://ca.tld/acme/reg/1" {
  164. t.Errorf("a.URI = %q; want https://ca.tld/acme/reg/1", a.URI)
  165. }
  166. if a.Authz != "https://ca.tld/acme/new-authz" {
  167. t.Errorf("a.Authz = %q; want https://ca.tld/acme/new-authz", a.Authz)
  168. }
  169. if a.CurrentTerms != "https://ca.tld/acme/terms" {
  170. t.Errorf("a.CurrentTerms = %q; want https://ca.tld/acme/terms", a.CurrentTerms)
  171. }
  172. if !reflect.DeepEqual(a.Contact, contacts) {
  173. t.Errorf("a.Contact = %v; want %v", a.Contact, contacts)
  174. }
  175. }
  176. func TestUpdateReg(t *testing.T) {
  177. const terms = "https://ca.tld/acme/terms"
  178. contacts := []string{"mailto:admin@example.com"}
  179. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  180. if r.Method == "HEAD" {
  181. w.Header().Set("Replay-Nonce", "test-nonce")
  182. return
  183. }
  184. if r.Method != "POST" {
  185. t.Errorf("r.Method = %q; want POST", r.Method)
  186. }
  187. var j struct {
  188. Resource string
  189. Contact []string
  190. Agreement string
  191. }
  192. decodeJWSRequest(t, &j, r.Body)
  193. // Test request
  194. if j.Resource != "reg" {
  195. t.Errorf("j.Resource = %q; want reg", j.Resource)
  196. }
  197. if j.Agreement != terms {
  198. t.Errorf("j.Agreement = %q; want %q", j.Agreement, terms)
  199. }
  200. if !reflect.DeepEqual(j.Contact, contacts) {
  201. t.Errorf("j.Contact = %v; want %v", j.Contact, contacts)
  202. }
  203. w.Header().Set("Link", `<https://ca.tld/acme/new-authz>;rel="next"`)
  204. w.Header().Add("Link", `<https://ca.tld/acme/recover-reg>;rel="recover"`)
  205. w.Header().Add("Link", fmt.Sprintf(`<%s>;rel="terms-of-service"`, terms))
  206. w.WriteHeader(http.StatusOK)
  207. b, _ := json.Marshal(contacts)
  208. fmt.Fprintf(w, `{"contact":%s, "agreement":%q}`, b, terms)
  209. }))
  210. defer ts.Close()
  211. c := Client{
  212. Key: testKeyEC,
  213. DirectoryURL: ts.URL, // don't dial outside of localhost
  214. dir: &Directory{}, // don't do discovery
  215. }
  216. a := &Account{URI: ts.URL, Contact: contacts, AgreedTerms: terms}
  217. var err error
  218. if a, err = c.UpdateReg(context.Background(), a); err != nil {
  219. t.Fatal(err)
  220. }
  221. if a.Authz != "https://ca.tld/acme/new-authz" {
  222. t.Errorf("a.Authz = %q; want https://ca.tld/acme/new-authz", a.Authz)
  223. }
  224. if a.AgreedTerms != terms {
  225. t.Errorf("a.AgreedTerms = %q; want %q", a.AgreedTerms, terms)
  226. }
  227. if a.CurrentTerms != terms {
  228. t.Errorf("a.CurrentTerms = %q; want %q", a.CurrentTerms, terms)
  229. }
  230. if a.URI != ts.URL {
  231. t.Errorf("a.URI = %q; want %q", a.URI, ts.URL)
  232. }
  233. }
  234. func TestGetReg(t *testing.T) {
  235. const terms = "https://ca.tld/acme/terms"
  236. const newTerms = "https://ca.tld/acme/new-terms"
  237. contacts := []string{"mailto:admin@example.com"}
  238. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  239. if r.Method == "HEAD" {
  240. w.Header().Set("Replay-Nonce", "test-nonce")
  241. return
  242. }
  243. if r.Method != "POST" {
  244. t.Errorf("r.Method = %q; want POST", r.Method)
  245. }
  246. var j struct {
  247. Resource string
  248. Contact []string
  249. Agreement string
  250. }
  251. decodeJWSRequest(t, &j, r.Body)
  252. // Test request
  253. if j.Resource != "reg" {
  254. t.Errorf("j.Resource = %q; want reg", j.Resource)
  255. }
  256. if len(j.Contact) != 0 {
  257. t.Errorf("j.Contact = %v", j.Contact)
  258. }
  259. if j.Agreement != "" {
  260. t.Errorf("j.Agreement = %q", j.Agreement)
  261. }
  262. w.Header().Set("Link", `<https://ca.tld/acme/new-authz>;rel="next"`)
  263. w.Header().Add("Link", `<https://ca.tld/acme/recover-reg>;rel="recover"`)
  264. w.Header().Add("Link", fmt.Sprintf(`<%s>;rel="terms-of-service"`, newTerms))
  265. w.WriteHeader(http.StatusOK)
  266. b, _ := json.Marshal(contacts)
  267. fmt.Fprintf(w, `{"contact":%s, "agreement":%q}`, b, terms)
  268. }))
  269. defer ts.Close()
  270. c := Client{
  271. Key: testKeyEC,
  272. DirectoryURL: ts.URL, // don't dial outside of localhost
  273. dir: &Directory{}, // don't do discovery
  274. }
  275. a, err := c.GetReg(context.Background(), ts.URL)
  276. if err != nil {
  277. t.Fatal(err)
  278. }
  279. if a.Authz != "https://ca.tld/acme/new-authz" {
  280. t.Errorf("a.AuthzURL = %q; want https://ca.tld/acme/new-authz", a.Authz)
  281. }
  282. if a.AgreedTerms != terms {
  283. t.Errorf("a.AgreedTerms = %q; want %q", a.AgreedTerms, terms)
  284. }
  285. if a.CurrentTerms != newTerms {
  286. t.Errorf("a.CurrentTerms = %q; want %q", a.CurrentTerms, newTerms)
  287. }
  288. if a.URI != ts.URL {
  289. t.Errorf("a.URI = %q; want %q", a.URI, ts.URL)
  290. }
  291. }
  292. func TestAuthorize(t *testing.T) {
  293. tt := []struct{ typ, value string }{
  294. {"dns", "example.com"},
  295. {"ip", "1.2.3.4"},
  296. }
  297. for _, test := range tt {
  298. t.Run(test.typ, func(t *testing.T) {
  299. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  300. if r.Method == "HEAD" {
  301. w.Header().Set("Replay-Nonce", "test-nonce")
  302. return
  303. }
  304. if r.Method != "POST" {
  305. t.Errorf("r.Method = %q; want POST", r.Method)
  306. }
  307. var j struct {
  308. Resource string
  309. Identifier struct {
  310. Type string
  311. Value string
  312. }
  313. }
  314. decodeJWSRequest(t, &j, r.Body)
  315. // Test request
  316. if j.Resource != "new-authz" {
  317. t.Errorf("j.Resource = %q; want new-authz", j.Resource)
  318. }
  319. if j.Identifier.Type != test.typ {
  320. t.Errorf("j.Identifier.Type = %q; want %q", j.Identifier.Type, test.typ)
  321. }
  322. if j.Identifier.Value != test.value {
  323. t.Errorf("j.Identifier.Value = %q; want %q", j.Identifier.Value, test.value)
  324. }
  325. w.Header().Set("Location", "https://ca.tld/acme/auth/1")
  326. w.WriteHeader(http.StatusCreated)
  327. fmt.Fprintf(w, `{
  328. "identifier": {"type":%q,"value":%q},
  329. "status":"pending",
  330. "challenges":[
  331. {
  332. "type":"http-01",
  333. "status":"pending",
  334. "uri":"https://ca.tld/acme/challenge/publickey/id1",
  335. "token":"token1"
  336. },
  337. {
  338. "type":"tls-sni-01",
  339. "status":"pending",
  340. "uri":"https://ca.tld/acme/challenge/publickey/id2",
  341. "token":"token2"
  342. }
  343. ],
  344. "combinations":[[0],[1]]
  345. }`, test.typ, test.value)
  346. }))
  347. defer ts.Close()
  348. var (
  349. auth *Authorization
  350. err error
  351. )
  352. cl := Client{
  353. Key: testKeyEC,
  354. DirectoryURL: ts.URL,
  355. dir: &Directory{AuthzURL: ts.URL},
  356. }
  357. switch test.typ {
  358. case "dns":
  359. auth, err = cl.Authorize(context.Background(), test.value)
  360. case "ip":
  361. auth, err = cl.AuthorizeIP(context.Background(), test.value)
  362. default:
  363. t.Fatalf("unknown identifier type: %q", test.typ)
  364. }
  365. if err != nil {
  366. t.Fatal(err)
  367. }
  368. if auth.URI != "https://ca.tld/acme/auth/1" {
  369. t.Errorf("URI = %q; want https://ca.tld/acme/auth/1", auth.URI)
  370. }
  371. if auth.Status != "pending" {
  372. t.Errorf("Status = %q; want pending", auth.Status)
  373. }
  374. if auth.Identifier.Type != test.typ {
  375. t.Errorf("Identifier.Type = %q; want %q", auth.Identifier.Type, test.typ)
  376. }
  377. if auth.Identifier.Value != test.value {
  378. t.Errorf("Identifier.Value = %q; want %q", auth.Identifier.Value, test.value)
  379. }
  380. if n := len(auth.Challenges); n != 2 {
  381. t.Fatalf("len(auth.Challenges) = %d; want 2", n)
  382. }
  383. c := auth.Challenges[0]
  384. if c.Type != "http-01" {
  385. t.Errorf("c.Type = %q; want http-01", c.Type)
  386. }
  387. if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
  388. t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
  389. }
  390. if c.Token != "token1" {
  391. t.Errorf("c.Token = %q; want token1", c.Token)
  392. }
  393. c = auth.Challenges[1]
  394. if c.Type != "tls-sni-01" {
  395. t.Errorf("c.Type = %q; want tls-sni-01", c.Type)
  396. }
  397. if c.URI != "https://ca.tld/acme/challenge/publickey/id2" {
  398. t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id2", c.URI)
  399. }
  400. if c.Token != "token2" {
  401. t.Errorf("c.Token = %q; want token2", c.Token)
  402. }
  403. combs := [][]int{{0}, {1}}
  404. if !reflect.DeepEqual(auth.Combinations, combs) {
  405. t.Errorf("auth.Combinations: %+v\nwant: %+v\n", auth.Combinations, combs)
  406. }
  407. })
  408. }
  409. }
  410. func TestAuthorizeValid(t *testing.T) {
  411. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  412. if r.Method == "HEAD" {
  413. w.Header().Set("Replay-Nonce", "nonce")
  414. return
  415. }
  416. w.WriteHeader(http.StatusCreated)
  417. w.Write([]byte(`{"status":"valid"}`))
  418. }))
  419. defer ts.Close()
  420. client := Client{
  421. Key: testKey,
  422. DirectoryURL: ts.URL,
  423. dir: &Directory{AuthzURL: ts.URL},
  424. }
  425. _, err := client.Authorize(context.Background(), "example.com")
  426. if err != nil {
  427. t.Errorf("err = %v", err)
  428. }
  429. }
  430. func TestGetAuthorization(t *testing.T) {
  431. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  432. if r.Method != "GET" {
  433. t.Errorf("r.Method = %q; want GET", r.Method)
  434. }
  435. w.WriteHeader(http.StatusOK)
  436. fmt.Fprintf(w, `{
  437. "identifier": {"type":"dns","value":"example.com"},
  438. "status":"pending",
  439. "challenges":[
  440. {
  441. "type":"http-01",
  442. "status":"pending",
  443. "uri":"https://ca.tld/acme/challenge/publickey/id1",
  444. "token":"token1"
  445. },
  446. {
  447. "type":"tls-sni-01",
  448. "status":"pending",
  449. "uri":"https://ca.tld/acme/challenge/publickey/id2",
  450. "token":"token2"
  451. }
  452. ],
  453. "combinations":[[0],[1]]}`)
  454. }))
  455. defer ts.Close()
  456. cl := Client{Key: testKeyEC, DirectoryURL: ts.URL}
  457. auth, err := cl.GetAuthorization(context.Background(), ts.URL)
  458. if err != nil {
  459. t.Fatal(err)
  460. }
  461. if auth.Status != "pending" {
  462. t.Errorf("Status = %q; want pending", auth.Status)
  463. }
  464. if auth.Identifier.Type != "dns" {
  465. t.Errorf("Identifier.Type = %q; want dns", auth.Identifier.Type)
  466. }
  467. if auth.Identifier.Value != "example.com" {
  468. t.Errorf("Identifier.Value = %q; want example.com", auth.Identifier.Value)
  469. }
  470. if n := len(auth.Challenges); n != 2 {
  471. t.Fatalf("len(set.Challenges) = %d; want 2", n)
  472. }
  473. c := auth.Challenges[0]
  474. if c.Type != "http-01" {
  475. t.Errorf("c.Type = %q; want http-01", c.Type)
  476. }
  477. if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
  478. t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
  479. }
  480. if c.Token != "token1" {
  481. t.Errorf("c.Token = %q; want token1", c.Token)
  482. }
  483. c = auth.Challenges[1]
  484. if c.Type != "tls-sni-01" {
  485. t.Errorf("c.Type = %q; want tls-sni-01", c.Type)
  486. }
  487. if c.URI != "https://ca.tld/acme/challenge/publickey/id2" {
  488. t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id2", c.URI)
  489. }
  490. if c.Token != "token2" {
  491. t.Errorf("c.Token = %q; want token2", c.Token)
  492. }
  493. combs := [][]int{{0}, {1}}
  494. if !reflect.DeepEqual(auth.Combinations, combs) {
  495. t.Errorf("auth.Combinations: %+v\nwant: %+v\n", auth.Combinations, combs)
  496. }
  497. }
  498. func TestWaitAuthorization(t *testing.T) {
  499. t.Run("wait loop", func(t *testing.T) {
  500. var count int
  501. authz, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
  502. count++
  503. w.Header().Set("Retry-After", "0")
  504. if count > 1 {
  505. fmt.Fprintf(w, `{"status":"valid"}`)
  506. return
  507. }
  508. fmt.Fprintf(w, `{"status":"pending"}`)
  509. })
  510. if err != nil {
  511. t.Fatalf("non-nil error: %v", err)
  512. }
  513. if authz == nil {
  514. t.Fatal("authz is nil")
  515. }
  516. })
  517. t.Run("invalid status", func(t *testing.T) {
  518. _, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
  519. fmt.Fprintf(w, `{"status":"invalid"}`)
  520. })
  521. if _, ok := err.(*AuthorizationError); !ok {
  522. t.Errorf("err is %v (%T); want non-nil *AuthorizationError", err, err)
  523. }
  524. })
  525. t.Run("non-retriable error", func(t *testing.T) {
  526. const code = http.StatusBadRequest
  527. _, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
  528. w.WriteHeader(code)
  529. })
  530. res, ok := err.(*Error)
  531. if !ok {
  532. t.Fatalf("err is %v (%T); want a non-nil *Error", err, err)
  533. }
  534. if res.StatusCode != code {
  535. t.Errorf("res.StatusCode = %d; want %d", res.StatusCode, code)
  536. }
  537. })
  538. for _, code := range []int{http.StatusTooManyRequests, http.StatusInternalServerError} {
  539. t.Run(fmt.Sprintf("retriable %d error", code), func(t *testing.T) {
  540. var count int
  541. authz, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
  542. count++
  543. w.Header().Set("Retry-After", "0")
  544. if count > 1 {
  545. fmt.Fprintf(w, `{"status":"valid"}`)
  546. return
  547. }
  548. w.WriteHeader(code)
  549. })
  550. if err != nil {
  551. t.Fatalf("non-nil error: %v", err)
  552. }
  553. if authz == nil {
  554. t.Fatal("authz is nil")
  555. }
  556. })
  557. }
  558. t.Run("context cancel", func(t *testing.T) {
  559. ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
  560. defer cancel()
  561. _, err := runWaitAuthorization(ctx, t, func(w http.ResponseWriter, r *http.Request) {
  562. w.Header().Set("Retry-After", "60")
  563. fmt.Fprintf(w, `{"status":"pending"}`)
  564. })
  565. if err == nil {
  566. t.Error("err is nil")
  567. }
  568. })
  569. }
  570. func runWaitAuthorization(ctx context.Context, t *testing.T, h http.HandlerFunc) (*Authorization, error) {
  571. t.Helper()
  572. ts := httptest.NewServer(h)
  573. defer ts.Close()
  574. type res struct {
  575. authz *Authorization
  576. err error
  577. }
  578. ch := make(chan res, 1)
  579. go func() {
  580. var client = Client{DirectoryURL: ts.URL}
  581. a, err := client.WaitAuthorization(ctx, ts.URL)
  582. ch <- res{a, err}
  583. }()
  584. select {
  585. case <-time.After(3 * time.Second):
  586. t.Fatal("WaitAuthorization took too long to return")
  587. case v := <-ch:
  588. return v.authz, v.err
  589. }
  590. panic("runWaitAuthorization: out of select")
  591. }
  592. func TestRevokeAuthorization(t *testing.T) {
  593. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  594. if r.Method == "HEAD" {
  595. w.Header().Set("Replay-Nonce", "nonce")
  596. return
  597. }
  598. switch r.URL.Path {
  599. case "/1":
  600. var req struct {
  601. Resource string
  602. Status string
  603. Delete bool
  604. }
  605. decodeJWSRequest(t, &req, r.Body)
  606. if req.Resource != "authz" {
  607. t.Errorf("req.Resource = %q; want authz", req.Resource)
  608. }
  609. if req.Status != "deactivated" {
  610. t.Errorf("req.Status = %q; want deactivated", req.Status)
  611. }
  612. if !req.Delete {
  613. t.Errorf("req.Delete is false")
  614. }
  615. case "/2":
  616. w.WriteHeader(http.StatusBadRequest)
  617. }
  618. }))
  619. defer ts.Close()
  620. client := &Client{
  621. Key: testKey,
  622. DirectoryURL: ts.URL, // don't dial outside of localhost
  623. dir: &Directory{}, // don't do discovery
  624. }
  625. ctx := context.Background()
  626. if err := client.RevokeAuthorization(ctx, ts.URL+"/1"); err != nil {
  627. t.Errorf("err = %v", err)
  628. }
  629. if client.RevokeAuthorization(ctx, ts.URL+"/2") == nil {
  630. t.Error("nil error")
  631. }
  632. }
  633. func TestPollChallenge(t *testing.T) {
  634. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  635. if r.Method != "GET" {
  636. t.Errorf("r.Method = %q; want GET", r.Method)
  637. }
  638. w.WriteHeader(http.StatusOK)
  639. fmt.Fprintf(w, `{
  640. "type":"http-01",
  641. "status":"pending",
  642. "uri":"https://ca.tld/acme/challenge/publickey/id1",
  643. "token":"token1"}`)
  644. }))
  645. defer ts.Close()
  646. cl := Client{Key: testKeyEC, DirectoryURL: ts.URL}
  647. chall, err := cl.GetChallenge(context.Background(), ts.URL)
  648. if err != nil {
  649. t.Fatal(err)
  650. }
  651. if chall.Status != "pending" {
  652. t.Errorf("Status = %q; want pending", chall.Status)
  653. }
  654. if chall.Type != "http-01" {
  655. t.Errorf("c.Type = %q; want http-01", chall.Type)
  656. }
  657. if chall.URI != "https://ca.tld/acme/challenge/publickey/id1" {
  658. t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", chall.URI)
  659. }
  660. if chall.Token != "token1" {
  661. t.Errorf("c.Token = %q; want token1", chall.Token)
  662. }
  663. }
  664. func TestAcceptChallenge(t *testing.T) {
  665. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  666. if r.Method == "HEAD" {
  667. w.Header().Set("Replay-Nonce", "test-nonce")
  668. return
  669. }
  670. if r.Method != "POST" {
  671. t.Errorf("r.Method = %q; want POST", r.Method)
  672. }
  673. var j struct {
  674. Resource string
  675. Type string
  676. Auth string `json:"keyAuthorization"`
  677. }
  678. decodeJWSRequest(t, &j, r.Body)
  679. // Test request
  680. if j.Resource != "challenge" {
  681. t.Errorf(`resource = %q; want "challenge"`, j.Resource)
  682. }
  683. if j.Type != "http-01" {
  684. t.Errorf(`type = %q; want "http-01"`, j.Type)
  685. }
  686. keyAuth := "token1." + testKeyECThumbprint
  687. if j.Auth != keyAuth {
  688. t.Errorf(`keyAuthorization = %q; want %q`, j.Auth, keyAuth)
  689. }
  690. // Respond to request
  691. w.WriteHeader(http.StatusAccepted)
  692. fmt.Fprintf(w, `{
  693. "type":"http-01",
  694. "status":"pending",
  695. "uri":"https://ca.tld/acme/challenge/publickey/id1",
  696. "token":"token1",
  697. "keyAuthorization":%q
  698. }`, keyAuth)
  699. }))
  700. defer ts.Close()
  701. cl := Client{
  702. Key: testKeyEC,
  703. DirectoryURL: ts.URL, // don't dial outside of localhost
  704. dir: &Directory{}, // don't do discovery
  705. }
  706. c, err := cl.Accept(context.Background(), &Challenge{
  707. URI: ts.URL,
  708. Token: "token1",
  709. Type: "http-01",
  710. })
  711. if err != nil {
  712. t.Fatal(err)
  713. }
  714. if c.Type != "http-01" {
  715. t.Errorf("c.Type = %q; want http-01", c.Type)
  716. }
  717. if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
  718. t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
  719. }
  720. if c.Token != "token1" {
  721. t.Errorf("c.Token = %q; want token1", c.Token)
  722. }
  723. }
  724. func TestNewCert(t *testing.T) {
  725. notBefore := time.Now()
  726. notAfter := notBefore.AddDate(0, 2, 0)
  727. timeNow = func() time.Time { return notBefore }
  728. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  729. if r.Method == "HEAD" {
  730. w.Header().Set("Replay-Nonce", "test-nonce")
  731. return
  732. }
  733. if r.Method != "POST" {
  734. t.Errorf("r.Method = %q; want POST", r.Method)
  735. }
  736. var j struct {
  737. Resource string `json:"resource"`
  738. CSR string `json:"csr"`
  739. NotBefore string `json:"notBefore,omitempty"`
  740. NotAfter string `json:"notAfter,omitempty"`
  741. }
  742. decodeJWSRequest(t, &j, r.Body)
  743. // Test request
  744. if j.Resource != "new-cert" {
  745. t.Errorf(`resource = %q; want "new-cert"`, j.Resource)
  746. }
  747. if j.NotBefore != notBefore.Format(time.RFC3339) {
  748. t.Errorf(`notBefore = %q; wanted %q`, j.NotBefore, notBefore.Format(time.RFC3339))
  749. }
  750. if j.NotAfter != notAfter.Format(time.RFC3339) {
  751. t.Errorf(`notAfter = %q; wanted %q`, j.NotAfter, notAfter.Format(time.RFC3339))
  752. }
  753. // Respond to request
  754. template := x509.Certificate{
  755. SerialNumber: big.NewInt(int64(1)),
  756. Subject: pkix.Name{
  757. Organization: []string{"goacme"},
  758. },
  759. NotBefore: notBefore,
  760. NotAfter: notAfter,
  761. KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
  762. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
  763. BasicConstraintsValid: true,
  764. }
  765. sampleCert, err := x509.CreateCertificate(rand.Reader, &template, &template, &testKeyEC.PublicKey, testKeyEC)
  766. if err != nil {
  767. t.Fatalf("Error creating certificate: %v", err)
  768. }
  769. w.Header().Set("Location", "https://ca.tld/acme/cert/1")
  770. w.WriteHeader(http.StatusCreated)
  771. w.Write(sampleCert)
  772. }))
  773. defer ts.Close()
  774. csr := x509.CertificateRequest{
  775. Version: 0,
  776. Subject: pkix.Name{
  777. CommonName: "example.com",
  778. Organization: []string{"goacme"},
  779. },
  780. }
  781. csrb, err := x509.CreateCertificateRequest(rand.Reader, &csr, testKeyEC)
  782. if err != nil {
  783. t.Fatal(err)
  784. }
  785. c := Client{Key: testKeyEC, dir: &Directory{CertURL: ts.URL}}
  786. cert, certURL, err := c.CreateCert(context.Background(), csrb, notAfter.Sub(notBefore), false)
  787. if err != nil {
  788. t.Fatal(err)
  789. }
  790. if cert == nil {
  791. t.Errorf("cert is nil")
  792. }
  793. if certURL != "https://ca.tld/acme/cert/1" {
  794. t.Errorf("certURL = %q; want https://ca.tld/acme/cert/1", certURL)
  795. }
  796. }
  797. func TestFetchCert(t *testing.T) {
  798. var count byte
  799. var ts *httptest.Server
  800. ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  801. count++
  802. if count < 3 {
  803. up := fmt.Sprintf("<%s>;rel=up", ts.URL)
  804. w.Header().Set("Link", up)
  805. }
  806. w.Write([]byte{count})
  807. }))
  808. defer ts.Close()
  809. cl := newTestClient()
  810. res, err := cl.FetchCert(context.Background(), ts.URL, true)
  811. if err != nil {
  812. t.Fatalf("FetchCert: %v", err)
  813. }
  814. cert := [][]byte{{1}, {2}, {3}}
  815. if !reflect.DeepEqual(res, cert) {
  816. t.Errorf("res = %v; want %v", res, cert)
  817. }
  818. }
  819. func TestFetchCertRetry(t *testing.T) {
  820. var count int
  821. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  822. if count < 1 {
  823. w.Header().Set("Retry-After", "0")
  824. w.WriteHeader(http.StatusTooManyRequests)
  825. count++
  826. return
  827. }
  828. w.Write([]byte{1})
  829. }))
  830. defer ts.Close()
  831. cl := newTestClient()
  832. res, err := cl.FetchCert(context.Background(), ts.URL, false)
  833. if err != nil {
  834. t.Fatalf("FetchCert: %v", err)
  835. }
  836. cert := [][]byte{{1}}
  837. if !reflect.DeepEqual(res, cert) {
  838. t.Errorf("res = %v; want %v", res, cert)
  839. }
  840. }
  841. func TestFetchCertCancel(t *testing.T) {
  842. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  843. w.Header().Set("Retry-After", "0")
  844. w.WriteHeader(http.StatusBadRequest)
  845. }))
  846. defer ts.Close()
  847. ctx, cancel := context.WithCancel(context.Background())
  848. done := make(chan struct{})
  849. var err error
  850. go func() {
  851. cl := newTestClient()
  852. _, err = cl.FetchCert(ctx, ts.URL, false)
  853. close(done)
  854. }()
  855. cancel()
  856. <-done
  857. if err != context.Canceled {
  858. t.Errorf("err = %v; want %v", err, context.Canceled)
  859. }
  860. }
  861. func TestFetchCertDepth(t *testing.T) {
  862. var count byte
  863. var ts *httptest.Server
  864. ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  865. count++
  866. if count > maxChainLen+1 {
  867. t.Errorf("count = %d; want at most %d", count, maxChainLen+1)
  868. w.WriteHeader(http.StatusInternalServerError)
  869. }
  870. w.Header().Set("Link", fmt.Sprintf("<%s>;rel=up", ts.URL))
  871. w.Write([]byte{count})
  872. }))
  873. defer ts.Close()
  874. cl := newTestClient()
  875. _, err := cl.FetchCert(context.Background(), ts.URL, true)
  876. if err == nil {
  877. t.Errorf("err is nil")
  878. }
  879. }
  880. func TestFetchCertBreadth(t *testing.T) {
  881. var ts *httptest.Server
  882. ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  883. for i := 0; i < maxChainLen+1; i++ {
  884. w.Header().Add("Link", fmt.Sprintf("<%s>;rel=up", ts.URL))
  885. }
  886. w.Write([]byte{1})
  887. }))
  888. defer ts.Close()
  889. cl := newTestClient()
  890. _, err := cl.FetchCert(context.Background(), ts.URL, true)
  891. if err == nil {
  892. t.Errorf("err is nil")
  893. }
  894. }
  895. func TestFetchCertSize(t *testing.T) {
  896. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  897. b := bytes.Repeat([]byte{1}, maxCertSize+1)
  898. w.Write(b)
  899. }))
  900. defer ts.Close()
  901. cl := newTestClient()
  902. _, err := cl.FetchCert(context.Background(), ts.URL, false)
  903. if err == nil {
  904. t.Errorf("err is nil")
  905. }
  906. }
  907. func TestRevokeCert(t *testing.T) {
  908. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  909. if r.Method == "HEAD" {
  910. w.Header().Set("Replay-Nonce", "nonce")
  911. return
  912. }
  913. var req struct {
  914. Resource string
  915. Certificate string
  916. Reason int
  917. }
  918. decodeJWSRequest(t, &req, r.Body)
  919. if req.Resource != "revoke-cert" {
  920. t.Errorf("req.Resource = %q; want revoke-cert", req.Resource)
  921. }
  922. if req.Reason != 1 {
  923. t.Errorf("req.Reason = %d; want 1", req.Reason)
  924. }
  925. // echo -n cert | base64 | tr -d '=' | tr '/+' '_-'
  926. cert := "Y2VydA"
  927. if req.Certificate != cert {
  928. t.Errorf("req.Certificate = %q; want %q", req.Certificate, cert)
  929. }
  930. }))
  931. defer ts.Close()
  932. client := &Client{
  933. Key: testKeyEC,
  934. dir: &Directory{RevokeURL: ts.URL},
  935. }
  936. ctx := context.Background()
  937. if err := client.RevokeCert(ctx, nil, []byte("cert"), CRLReasonKeyCompromise); err != nil {
  938. t.Fatal(err)
  939. }
  940. }
  941. func TestNonce_add(t *testing.T) {
  942. var c Client
  943. c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
  944. c.addNonce(http.Header{"Replay-Nonce": {}})
  945. c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
  946. nonces := map[string]struct{}{"nonce": {}}
  947. if !reflect.DeepEqual(c.nonces, nonces) {
  948. t.Errorf("c.nonces = %q; want %q", c.nonces, nonces)
  949. }
  950. }
  951. func TestNonce_addMax(t *testing.T) {
  952. c := &Client{nonces: make(map[string]struct{})}
  953. for i := 0; i < maxNonces; i++ {
  954. c.nonces[fmt.Sprintf("%d", i)] = struct{}{}
  955. }
  956. c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
  957. if n := len(c.nonces); n != maxNonces {
  958. t.Errorf("len(c.nonces) = %d; want %d", n, maxNonces)
  959. }
  960. }
  961. func TestNonce_fetch(t *testing.T) {
  962. tests := []struct {
  963. code int
  964. nonce string
  965. }{
  966. {http.StatusOK, "nonce1"},
  967. {http.StatusBadRequest, "nonce2"},
  968. {http.StatusOK, ""},
  969. }
  970. var i int
  971. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  972. if r.Method != "HEAD" {
  973. t.Errorf("%d: r.Method = %q; want HEAD", i, r.Method)
  974. }
  975. w.Header().Set("Replay-Nonce", tests[i].nonce)
  976. w.WriteHeader(tests[i].code)
  977. }))
  978. defer ts.Close()
  979. for ; i < len(tests); i++ {
  980. test := tests[i]
  981. c := newTestClient()
  982. n, err := c.fetchNonce(context.Background(), ts.URL)
  983. if n != test.nonce {
  984. t.Errorf("%d: n=%q; want %q", i, n, test.nonce)
  985. }
  986. switch {
  987. case err == nil && test.nonce == "":
  988. t.Errorf("%d: n=%q, err=%v; want non-nil error", i, n, err)
  989. case err != nil && test.nonce != "":
  990. t.Errorf("%d: n=%q, err=%v; want %q", i, n, err, test.nonce)
  991. }
  992. }
  993. }
  994. func TestNonce_fetchError(t *testing.T) {
  995. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  996. w.WriteHeader(http.StatusTooManyRequests)
  997. }))
  998. defer ts.Close()
  999. c := newTestClient()
  1000. _, err := c.fetchNonce(context.Background(), ts.URL)
  1001. e, ok := err.(*Error)
  1002. if !ok {
  1003. t.Fatalf("err is %T; want *Error", err)
  1004. }
  1005. if e.StatusCode != http.StatusTooManyRequests {
  1006. t.Errorf("e.StatusCode = %d; want %d", e.StatusCode, http.StatusTooManyRequests)
  1007. }
  1008. }
  1009. func TestNonce_popWhenEmpty(t *testing.T) {
  1010. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1011. if r.Method != "HEAD" {
  1012. t.Errorf("r.Method = %q; want HEAD", r.Method)
  1013. }
  1014. switch r.URL.Path {
  1015. case "/dir-with-nonce":
  1016. w.Header().Set("Replay-Nonce", "dirnonce")
  1017. case "/new-nonce":
  1018. w.Header().Set("Replay-Nonce", "newnonce")
  1019. case "/dir-no-nonce", "/empty":
  1020. // No nonce in the header.
  1021. default:
  1022. t.Errorf("Unknown URL: %s", r.URL)
  1023. }
  1024. }))
  1025. defer ts.Close()
  1026. ctx := context.Background()
  1027. tt := []struct {
  1028. dirURL, popURL, nonce string
  1029. wantOK bool
  1030. }{
  1031. {ts.URL + "/dir-with-nonce", ts.URL + "/new-nonce", "dirnonce", true},
  1032. {ts.URL + "/dir-no-nonce", ts.URL + "/new-nonce", "newnonce", true},
  1033. {ts.URL + "/dir-no-nonce", ts.URL + "/empty", "", false},
  1034. }
  1035. for _, test := range tt {
  1036. t.Run(fmt.Sprintf("nonce:%s wantOK:%v", test.nonce, test.wantOK), func(t *testing.T) {
  1037. c := Client{DirectoryURL: test.dirURL}
  1038. v, err := c.popNonce(ctx, test.popURL)
  1039. if !test.wantOK {
  1040. if err == nil {
  1041. t.Fatalf("c.popNonce(%q) returned nil error", test.popURL)
  1042. }
  1043. return
  1044. }
  1045. if err != nil {
  1046. t.Fatalf("c.popNonce(%q): %v", test.popURL, err)
  1047. }
  1048. if v != test.nonce {
  1049. t.Errorf("c.popNonce(%q) = %q; want %q", test.popURL, v, test.nonce)
  1050. }
  1051. })
  1052. }
  1053. }
  1054. func TestNonce_postJWS(t *testing.T) {
  1055. var count int
  1056. seen := make(map[string]bool)
  1057. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1058. count++
  1059. w.Header().Set("Replay-Nonce", fmt.Sprintf("nonce%d", count))
  1060. if r.Method == "HEAD" {
  1061. // We expect the client do a HEAD request
  1062. // but only to fetch the first nonce.
  1063. return
  1064. }
  1065. // Make client.Authorize happy; we're not testing its result.
  1066. defer func() {
  1067. w.WriteHeader(http.StatusCreated)
  1068. w.Write([]byte(`{"status":"valid"}`))
  1069. }()
  1070. head, err := decodeJWSHead(r.Body)
  1071. if err != nil {
  1072. t.Errorf("decodeJWSHead: %v", err)
  1073. return
  1074. }
  1075. if head.Nonce == "" {
  1076. t.Error("head.Nonce is empty")
  1077. return
  1078. }
  1079. if seen[head.Nonce] {
  1080. t.Errorf("nonce is already used: %q", head.Nonce)
  1081. }
  1082. seen[head.Nonce] = true
  1083. }))
  1084. defer ts.Close()
  1085. client := Client{
  1086. Key: testKey,
  1087. DirectoryURL: ts.URL, // nonces are fetched from here first
  1088. dir: &Directory{AuthzURL: ts.URL},
  1089. }
  1090. if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
  1091. t.Errorf("client.Authorize 1: %v", err)
  1092. }
  1093. // The second call should not generate another extra HEAD request.
  1094. if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
  1095. t.Errorf("client.Authorize 2: %v", err)
  1096. }
  1097. if count != 3 {
  1098. t.Errorf("total requests count: %d; want 3", count)
  1099. }
  1100. if n := len(client.nonces); n != 1 {
  1101. t.Errorf("len(client.nonces) = %d; want 1", n)
  1102. }
  1103. for k := range seen {
  1104. if _, exist := client.nonces[k]; exist {
  1105. t.Errorf("used nonce %q in client.nonces", k)
  1106. }
  1107. }
  1108. }
  1109. func TestLinkHeader(t *testing.T) {
  1110. h := http.Header{"Link": {
  1111. `<https://example.com/acme/new-authz>;rel="next"`,
  1112. `<https://example.com/acme/recover-reg>; rel=recover`,
  1113. `<https://example.com/acme/terms>; foo=bar; rel="terms-of-service"`,
  1114. `<dup>;rel="next"`,
  1115. }}
  1116. tests := []struct {
  1117. rel string
  1118. out []string
  1119. }{
  1120. {"next", []string{"https://example.com/acme/new-authz", "dup"}},
  1121. {"recover", []string{"https://example.com/acme/recover-reg"}},
  1122. {"terms-of-service", []string{"https://example.com/acme/terms"}},
  1123. {"empty", nil},
  1124. }
  1125. for i, test := range tests {
  1126. if v := linkHeader(h, test.rel); !reflect.DeepEqual(v, test.out) {
  1127. t.Errorf("%d: linkHeader(%q): %v; want %v", i, test.rel, v, test.out)
  1128. }
  1129. }
  1130. }
  1131. func TestTLSSNI01ChallengeCert(t *testing.T) {
  1132. const (
  1133. token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
  1134. // echo -n <token.testKeyECThumbprint> | shasum -a 256
  1135. san = "dbbd5eefe7b4d06eb9d1d9f5acb4c7cd.a27d320e4b30332f0b6cb441734ad7b0.acme.invalid"
  1136. )
  1137. tlscert, name, err := newTestClient().TLSSNI01ChallengeCert(token)
  1138. if err != nil {
  1139. t.Fatal(err)
  1140. }
  1141. if n := len(tlscert.Certificate); n != 1 {
  1142. t.Fatalf("len(tlscert.Certificate) = %d; want 1", n)
  1143. }
  1144. cert, err := x509.ParseCertificate(tlscert.Certificate[0])
  1145. if err != nil {
  1146. t.Fatal(err)
  1147. }
  1148. if len(cert.DNSNames) != 1 || cert.DNSNames[0] != san {
  1149. t.Fatalf("cert.DNSNames = %v; want %q", cert.DNSNames, san)
  1150. }
  1151. if cert.DNSNames[0] != name {
  1152. t.Errorf("cert.DNSNames[0] != name: %q vs %q", cert.DNSNames[0], name)
  1153. }
  1154. if cn := cert.Subject.CommonName; cn != san {
  1155. t.Errorf("cert.Subject.CommonName = %q; want %q", cn, san)
  1156. }
  1157. }
  1158. func TestTLSSNI02ChallengeCert(t *testing.T) {
  1159. const (
  1160. token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
  1161. // echo -n evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA | shasum -a 256
  1162. sanA = "7ea0aaa69214e71e02cebb18bb867736.09b730209baabf60e43d4999979ff139.token.acme.invalid"
  1163. // echo -n <token.testKeyECThumbprint> | shasum -a 256
  1164. sanB = "dbbd5eefe7b4d06eb9d1d9f5acb4c7cd.a27d320e4b30332f0b6cb441734ad7b0.ka.acme.invalid"
  1165. )
  1166. tlscert, name, err := newTestClient().TLSSNI02ChallengeCert(token)
  1167. if err != nil {
  1168. t.Fatal(err)
  1169. }
  1170. if n := len(tlscert.Certificate); n != 1 {
  1171. t.Fatalf("len(tlscert.Certificate) = %d; want 1", n)
  1172. }
  1173. cert, err := x509.ParseCertificate(tlscert.Certificate[0])
  1174. if err != nil {
  1175. t.Fatal(err)
  1176. }
  1177. names := []string{sanA, sanB}
  1178. if !reflect.DeepEqual(cert.DNSNames, names) {
  1179. t.Fatalf("cert.DNSNames = %v;\nwant %v", cert.DNSNames, names)
  1180. }
  1181. sort.Strings(cert.DNSNames)
  1182. i := sort.SearchStrings(cert.DNSNames, name)
  1183. if i >= len(cert.DNSNames) || cert.DNSNames[i] != name {
  1184. t.Errorf("%v doesn't have %q", cert.DNSNames, name)
  1185. }
  1186. if cn := cert.Subject.CommonName; cn != sanA {
  1187. t.Errorf("CommonName = %q; want %q", cn, sanA)
  1188. }
  1189. }
  1190. func TestTLSALPN01ChallengeCert(t *testing.T) {
  1191. const (
  1192. token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
  1193. keyAuth = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA." + testKeyECThumbprint
  1194. // echo -n <token.testKeyECThumbprint> | shasum -a 256
  1195. h = "0420dbbd5eefe7b4d06eb9d1d9f5acb4c7cda27d320e4b30332f0b6cb441734ad7b0"
  1196. domain = "example.com"
  1197. )
  1198. extValue, err := hex.DecodeString(h)
  1199. if err != nil {
  1200. t.Fatal(err)
  1201. }
  1202. tlscert, err := newTestClient().TLSALPN01ChallengeCert(token, domain)
  1203. if err != nil {
  1204. t.Fatal(err)
  1205. }
  1206. if n := len(tlscert.Certificate); n != 1 {
  1207. t.Fatalf("len(tlscert.Certificate) = %d; want 1", n)
  1208. }
  1209. cert, err := x509.ParseCertificate(tlscert.Certificate[0])
  1210. if err != nil {
  1211. t.Fatal(err)
  1212. }
  1213. names := []string{domain}
  1214. if !reflect.DeepEqual(cert.DNSNames, names) {
  1215. t.Fatalf("cert.DNSNames = %v;\nwant %v", cert.DNSNames, names)
  1216. }
  1217. if cn := cert.Subject.CommonName; cn != domain {
  1218. t.Errorf("CommonName = %q; want %q", cn, domain)
  1219. }
  1220. acmeExts := []pkix.Extension{}
  1221. for _, ext := range cert.Extensions {
  1222. if idPeACMEIdentifierV1.Equal(ext.Id) {
  1223. acmeExts = append(acmeExts, ext)
  1224. }
  1225. }
  1226. if len(acmeExts) != 1 {
  1227. t.Errorf("acmeExts = %v; want exactly one", acmeExts)
  1228. }
  1229. if !acmeExts[0].Critical {
  1230. t.Errorf("acmeExt.Critical = %v; want true", acmeExts[0].Critical)
  1231. }
  1232. if bytes.Compare(acmeExts[0].Value, extValue) != 0 {
  1233. t.Errorf("acmeExt.Value = %v; want %v", acmeExts[0].Value, extValue)
  1234. }
  1235. }
  1236. func TestTLSChallengeCertOpt(t *testing.T) {
  1237. key, err := rsa.GenerateKey(rand.Reader, 512)
  1238. if err != nil {
  1239. t.Fatal(err)
  1240. }
  1241. tmpl := &x509.Certificate{
  1242. SerialNumber: big.NewInt(2),
  1243. Subject: pkix.Name{Organization: []string{"Test"}},
  1244. DNSNames: []string{"should-be-overwritten"},
  1245. }
  1246. opts := []CertOption{WithKey(key), WithTemplate(tmpl)}
  1247. client := newTestClient()
  1248. cert1, _, err := client.TLSSNI01ChallengeCert("token", opts...)
  1249. if err != nil {
  1250. t.Fatal(err)
  1251. }
  1252. cert2, _, err := client.TLSSNI02ChallengeCert("token", opts...)
  1253. if err != nil {
  1254. t.Fatal(err)
  1255. }
  1256. for i, tlscert := range []tls.Certificate{cert1, cert2} {
  1257. // verify generated cert private key
  1258. tlskey, ok := tlscert.PrivateKey.(*rsa.PrivateKey)
  1259. if !ok {
  1260. t.Errorf("%d: tlscert.PrivateKey is %T; want *rsa.PrivateKey", i, tlscert.PrivateKey)
  1261. continue
  1262. }
  1263. if tlskey.D.Cmp(key.D) != 0 {
  1264. t.Errorf("%d: tlskey.D = %v; want %v", i, tlskey.D, key.D)
  1265. }
  1266. // verify generated cert public key
  1267. x509Cert, err := x509.ParseCertificate(tlscert.Certificate[0])
  1268. if err != nil {
  1269. t.Errorf("%d: %v", i, err)
  1270. continue
  1271. }
  1272. tlspub, ok := x509Cert.PublicKey.(*rsa.PublicKey)
  1273. if !ok {
  1274. t.Errorf("%d: x509Cert.PublicKey is %T; want *rsa.PublicKey", i, x509Cert.PublicKey)
  1275. continue
  1276. }
  1277. if tlspub.N.Cmp(key.N) != 0 {
  1278. t.Errorf("%d: tlspub.N = %v; want %v", i, tlspub.N, key.N)
  1279. }
  1280. // verify template option
  1281. sn := big.NewInt(2)
  1282. if x509Cert.SerialNumber.Cmp(sn) != 0 {
  1283. t.Errorf("%d: SerialNumber = %v; want %v", i, x509Cert.SerialNumber, sn)
  1284. }
  1285. org := []string{"Test"}
  1286. if !reflect.DeepEqual(x509Cert.Subject.Organization, org) {
  1287. t.Errorf("%d: Subject.Organization = %+v; want %+v", i, x509Cert.Subject.Organization, org)
  1288. }
  1289. for _, v := range x509Cert.DNSNames {
  1290. if !strings.HasSuffix(v, ".acme.invalid") {
  1291. t.Errorf("%d: invalid DNSNames element: %q", i, v)
  1292. }
  1293. }
  1294. }
  1295. }
  1296. func TestHTTP01Challenge(t *testing.T) {
  1297. const (
  1298. token = "xxx"
  1299. // thumbprint is precomputed for testKeyEC in jws_test.go
  1300. value = token + "." + testKeyECThumbprint
  1301. urlpath = "/.well-known/acme-challenge/" + token
  1302. )
  1303. client := newTestClient()
  1304. val, err := client.HTTP01ChallengeResponse(token)
  1305. if err != nil {
  1306. t.Fatal(err)
  1307. }
  1308. if val != value {
  1309. t.Errorf("val = %q; want %q", val, value)
  1310. }
  1311. if path := client.HTTP01ChallengePath(token); path != urlpath {
  1312. t.Errorf("path = %q; want %q", path, urlpath)
  1313. }
  1314. }
  1315. func TestDNS01ChallengeRecord(t *testing.T) {
  1316. // echo -n xxx.<testKeyECThumbprint> | \
  1317. // openssl dgst -binary -sha256 | \
  1318. // base64 | tr -d '=' | tr '/+' '_-'
  1319. const value = "8DERMexQ5VcdJ_prpPiA0mVdp7imgbCgjsG4SqqNMIo"
  1320. val, err := newTestClient().DNS01ChallengeRecord("xxx")
  1321. if err != nil {
  1322. t.Fatal(err)
  1323. }
  1324. if val != value {
  1325. t.Errorf("val = %q; want %q", val, value)
  1326. }
  1327. }