report.go 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. package hpkp
  2. import (
  3. "bytes"
  4. "crypto/tls"
  5. "crypto/x509"
  6. "encoding/pem"
  7. "time"
  8. )
  9. // PinFailure hold fields required for POSTing a pin validation failure JSON message
  10. // to a host's report-uri.
  11. type PinFailure struct {
  12. DateTime string `json:"date-time"`
  13. Hostname string `json:"hostname"`
  14. Port int `json:"port"`
  15. EffectiveExpirationDate string `json:"effective-expiration-date"`
  16. IncludeSubdomains bool `json:"include-subdomains"`
  17. NotedHostname string `json:"noted-hostname"`
  18. ServedCertificateChain []string `json:"served-certificate-chain"`
  19. ValidatedCertificateChain []string `json:"validated-certificate-chain"`
  20. KnownPins []string `json:"known-pins"`
  21. }
  22. // NewPinFailure creates a struct to report information on failed hpkp connections
  23. func NewPinFailure(host string, port int, h *Header, c tls.ConnectionState) (*PinFailure, string) {
  24. if h == nil {
  25. return nil, ""
  26. }
  27. verifiedChain := []*x509.Certificate{}
  28. if len(c.VerifiedChains) > 0 {
  29. verifiedChain = c.VerifiedChains[len(c.VerifiedChains)-1]
  30. }
  31. return &PinFailure{
  32. DateTime: time.Now().Format(time.RFC3339),
  33. Hostname: host,
  34. Port: port,
  35. EffectiveExpirationDate: time.Unix(h.Created+h.MaxAge, 0).UTC().Format(time.RFC3339),
  36. IncludeSubdomains: h.IncludeSubDomains,
  37. NotedHostname: c.ServerName,
  38. ServedCertificateChain: encodeCertificatesPEM(c.PeerCertificates),
  39. ValidatedCertificateChain: encodeCertificatesPEM(verifiedChain),
  40. KnownPins: h.Sha256Pins,
  41. }, h.ReportURI
  42. }
  43. // encodeCertificatesPEM converts a slice of x509 certficates to a slice of PEM encoded strings
  44. func encodeCertificatesPEM(certs []*x509.Certificate) []string {
  45. var pemCerts []string
  46. var buffer bytes.Buffer
  47. for _, cert := range certs {
  48. pem.Encode(&buffer, &pem.Block{
  49. Type: "CERTIFICATE",
  50. Bytes: cert.Raw,
  51. })
  52. pemCerts = append(pemCerts, string(buffer.Bytes()))
  53. buffer.Reset()
  54. }
  55. return pemCerts
  56. }