cert.go 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. //go:build !ios && !android && !js
  4. package localapi
  5. import (
  6. "fmt"
  7. "net/http"
  8. "strings"
  9. "time"
  10. "tailscale.com/ipn/ipnlocal"
  11. )
  12. func (h *Handler) serveCert(w http.ResponseWriter, r *http.Request) {
  13. if !h.PermitWrite && !h.PermitCert {
  14. http.Error(w, "cert access denied", http.StatusForbidden)
  15. return
  16. }
  17. domain, ok := strings.CutPrefix(r.URL.Path, "/localapi/v0/cert/")
  18. if !ok {
  19. http.Error(w, "internal handler config wired wrong", 500)
  20. return
  21. }
  22. var minValidity time.Duration
  23. if minValidityStr := r.URL.Query().Get("min_validity"); minValidityStr != "" {
  24. var err error
  25. minValidity, err = time.ParseDuration(minValidityStr)
  26. if err != nil {
  27. http.Error(w, fmt.Sprintf("invalid validity parameter: %v", err), http.StatusBadRequest)
  28. return
  29. }
  30. }
  31. pair, err := h.b.GetCertPEMWithValidity(r.Context(), domain, minValidity)
  32. if err != nil {
  33. // TODO(bradfitz): 500 is a little lazy here. The errors returned from
  34. // GetCertPEM (and everywhere) should carry info info to get whether
  35. // they're 400 vs 403 vs 500 at minimum. And then we should have helpers
  36. // (in tsweb probably) to return an error that looks at the error value
  37. // to determine the HTTP status code.
  38. http.Error(w, fmt.Sprint(err), 500)
  39. return
  40. }
  41. serveKeyPair(w, r, pair)
  42. }
  43. func serveKeyPair(w http.ResponseWriter, r *http.Request, p *ipnlocal.TLSCertKeyPair) {
  44. w.Header().Set("Content-Type", "text/plain")
  45. switch r.URL.Query().Get("type") {
  46. case "", "crt", "cert":
  47. w.Write(p.CertPEM)
  48. case "key":
  49. w.Write(p.KeyPEM)
  50. case "pair":
  51. w.Write(p.KeyPEM)
  52. w.Write(p.CertPEM)
  53. default:
  54. http.Error(w, `invalid type; want "cert" (default), "key", or "pair"`, 400)
  55. }
  56. }