autocert_test.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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 autocert
  5. import (
  6. "bytes"
  7. "crypto/ecdsa"
  8. "crypto/elliptic"
  9. "crypto/rand"
  10. "crypto/tls"
  11. "crypto/x509"
  12. "crypto/x509/pkix"
  13. "encoding/pem"
  14. "fmt"
  15. "html/template"
  16. "math/big"
  17. "net/http"
  18. "net/http/httptest"
  19. "testing"
  20. "time"
  21. "golang.org/x/crypto/acme/internal/acme"
  22. "golang.org/x/net/context"
  23. )
  24. var discoTmpl = template.Must(template.New("disco").Parse(`{
  25. "new-reg": "{{.}}/new-reg",
  26. "new-authz": "{{.}}/new-authz",
  27. "new-cert": "{{.}}/new-cert"
  28. }`))
  29. var authzTmpl = template.Must(template.New("authz").Parse(`{
  30. "status": "pending",
  31. "challenges": [
  32. {
  33. "uri": "{{.}}/challenge/1",
  34. "type": "tls-sni-01",
  35. "token": "token-01"
  36. },
  37. {
  38. "uri": "{{.}}/challenge/2",
  39. "type": "tls-sni-02",
  40. "token": "token-02"
  41. }
  42. ]
  43. }`))
  44. func dummyCert(san ...string) ([]byte, error) {
  45. // use EC key to run faster on 386
  46. key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  47. if err != nil {
  48. return nil, err
  49. }
  50. t := &x509.Certificate{
  51. SerialNumber: big.NewInt(1),
  52. NotBefore: time.Now(),
  53. NotAfter: time.Now().Add(24 * time.Hour),
  54. BasicConstraintsValid: true,
  55. KeyUsage: x509.KeyUsageKeyEncipherment,
  56. DNSNames: san,
  57. }
  58. return x509.CreateCertificate(rand.Reader, t, t, &key.PublicKey, key)
  59. }
  60. func TestGetCertificate(t *testing.T) {
  61. const domain = "example.org"
  62. man := &Manager{Prompt: AcceptTOS}
  63. // echo token-02 | shasum -a 256
  64. // then divide result in 2 parts separated by dot
  65. tokenCertName := "4e8eb87631187e9ff2153b56b13a4dec.13a35d002e485d60ff37354b32f665d9.token.acme.invalid"
  66. verifyTokenCert := func() {
  67. hello := &tls.ClientHelloInfo{ServerName: tokenCertName}
  68. _, err := man.GetCertificate(hello)
  69. if err != nil {
  70. t.Errorf("verifyTokenCert: GetCertificate(%q): %v", tokenCertName, err)
  71. return
  72. }
  73. }
  74. // ACME CA server stub
  75. var ca *httptest.Server
  76. ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  77. w.Header().Set("replay-nonce", "nonce")
  78. switch r.URL.Path {
  79. // discovery
  80. case "/":
  81. if err := discoTmpl.Execute(w, ca.URL); err != nil {
  82. t.Fatalf("discoTmpl: %v", err)
  83. }
  84. // client key registration
  85. case "/new-reg":
  86. w.Write([]byte("{}"))
  87. // domain authorization
  88. case "/new-authz":
  89. w.Header().Set("location", ca.URL+"/authz/1")
  90. w.WriteHeader(http.StatusCreated)
  91. if err := authzTmpl.Execute(w, ca.URL); err != nil {
  92. t.Fatalf("authzTmpl: %v", err)
  93. }
  94. // accept tls-sni-02 challenge
  95. case "/challenge/2":
  96. verifyTokenCert()
  97. w.Write([]byte("{}"))
  98. // authorization status
  99. case "/authz/1":
  100. w.Write([]byte(`{"status": "valid"}`))
  101. // cert request
  102. case "/new-cert":
  103. der, err := dummyCert(domain)
  104. if err != nil {
  105. t.Fatalf("new-cert: dummyCert: %v", err)
  106. }
  107. chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL)
  108. w.Header().Set("link", chainUp)
  109. w.WriteHeader(http.StatusCreated)
  110. w.Write(der)
  111. // CA chain cert
  112. case "/ca-cert":
  113. der, err := dummyCert("ca")
  114. if err != nil {
  115. t.Fatalf("ca-cert: dummyCert: %v", err)
  116. }
  117. w.Write(der)
  118. default:
  119. t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
  120. }
  121. }))
  122. defer ca.Close()
  123. // use EC key to run faster on 386
  124. key, kerr := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  125. if kerr != nil {
  126. t.Fatal(kerr)
  127. }
  128. man.Client = &acme.Client{
  129. Key: key,
  130. DirectoryURL: ca.URL,
  131. }
  132. // simulate tls.Config.GetCertificate
  133. var (
  134. tlscert *tls.Certificate
  135. err error
  136. done = make(chan struct{})
  137. )
  138. go func() {
  139. hello := &tls.ClientHelloInfo{ServerName: domain}
  140. tlscert, err = man.GetCertificate(hello)
  141. close(done)
  142. }()
  143. select {
  144. case <-time.After(time.Minute):
  145. t.Fatal("man.GetCertificate took too long to return")
  146. case <-done:
  147. }
  148. if err != nil {
  149. t.Fatalf("man.GetCertificate: %v", err)
  150. }
  151. // verify the tlscert is the same we responded with from the CA stub
  152. if len(tlscert.Certificate) == 0 {
  153. t.Fatal("len(tlscert.Certificate) is 0")
  154. }
  155. cert, err := x509.ParseCertificate(tlscert.Certificate[0])
  156. if err != nil {
  157. t.Fatalf("x509.ParseCertificate: %v", err)
  158. }
  159. if len(cert.DNSNames) == 0 || cert.DNSNames[0] != domain {
  160. t.Errorf("cert.DNSNames = %v; want %q", cert.DNSNames, domain)
  161. }
  162. // make sure token cert was removed
  163. done = make(chan struct{})
  164. go func() {
  165. for {
  166. hello := &tls.ClientHelloInfo{ServerName: tokenCertName}
  167. if _, err := man.GetCertificate(hello); err != nil {
  168. break
  169. }
  170. time.Sleep(100 * time.Millisecond)
  171. }
  172. close(done)
  173. }()
  174. select {
  175. case <-time.After(5 * time.Second):
  176. t.Error("token cert was not removed")
  177. case <-done:
  178. }
  179. }
  180. type memCache map[string][]byte
  181. func (m memCache) Get(ctx context.Context, key string) ([]byte, error) {
  182. v, ok := m[key]
  183. if !ok {
  184. return nil, ErrCacheMiss
  185. }
  186. return v, nil
  187. }
  188. func (m memCache) Put(ctx context.Context, key string, data []byte) error {
  189. m[key] = data
  190. return nil
  191. }
  192. func (m memCache) Delete(ctx context.Context, key string) error {
  193. delete(m, key)
  194. return nil
  195. }
  196. func TestCache(t *testing.T) {
  197. privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  198. if err != nil {
  199. t.Fatal(err)
  200. }
  201. tmpl := &x509.Certificate{
  202. SerialNumber: big.NewInt(1),
  203. Subject: pkix.Name{CommonName: "example.org"},
  204. NotAfter: time.Now().Add(time.Hour),
  205. }
  206. pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &privKey.PublicKey, privKey)
  207. if err != nil {
  208. t.Fatal(err)
  209. }
  210. tlscert := &tls.Certificate{
  211. Certificate: [][]byte{pub},
  212. PrivateKey: privKey,
  213. }
  214. cache := make(memCache)
  215. man := Manager{Cache: cache}
  216. if err := man.cachePut("example.org", tlscert); err != nil {
  217. t.Fatalf("man.cachePut: %v", err)
  218. }
  219. res, err := man.cacheGet("example.org")
  220. if err != nil {
  221. t.Fatalf("man.cacheGet: %v", err)
  222. }
  223. if res == nil {
  224. t.Fatal("res is nil")
  225. }
  226. priv, err := x509.MarshalECPrivateKey(privKey)
  227. if err != nil {
  228. t.Fatalf("MarshalECPrivateKey: %v", err)
  229. }
  230. dummy, err := dummyCert("dummy")
  231. if err != nil {
  232. t.Fatalf("dummyCert: %v", err)
  233. }
  234. tt := []struct {
  235. key string
  236. prv, pub []byte
  237. }{
  238. {"dummy", priv, dummy},
  239. {"bad1", priv, []byte{1}},
  240. {"bad2", []byte{1}, pub},
  241. }
  242. for i, test := range tt {
  243. var buf bytes.Buffer
  244. pb := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: test.prv}
  245. if err := pem.Encode(&buf, pb); err != nil {
  246. t.Errorf("%d: pem.Encode: %v", i, err)
  247. }
  248. pb = &pem.Block{Type: "CERTIFICATE", Bytes: test.pub}
  249. if err := pem.Encode(&buf, pb); err != nil {
  250. t.Errorf("%d: pem.Encode: %v", i, err)
  251. }
  252. cache.Put(nil, test.key, buf.Bytes())
  253. if _, err := man.cacheGet(test.key); err == nil {
  254. t.Errorf("%d: err is nil", i)
  255. }
  256. }
  257. }
  258. func TestHostWhitelist(t *testing.T) {
  259. policy := HostWhitelist("example.com", "example.org", "*.example.net")
  260. tt := []struct {
  261. host string
  262. allow bool
  263. }{
  264. {"example.com", true},
  265. {"example.org", true},
  266. {"one.example.com", false},
  267. {"two.example.org", false},
  268. {"three.example.net", false},
  269. {"dummy", false},
  270. }
  271. for i, test := range tt {
  272. err := policy(nil, test.host)
  273. if err != nil && test.allow {
  274. t.Errorf("%d: policy(%q): %v; want nil", i, test.host, err)
  275. }
  276. if err == nil && !test.allow {
  277. t.Errorf("%d: policy(%q): nil; want an error", i, test.host)
  278. }
  279. }
  280. }