sha1.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. package ubiquity
  2. import (
  3. "crypto/x509"
  4. "fmt"
  5. "time"
  6. "github.com/cloudflare/cfssl/helpers"
  7. )
  8. // DeprecationSeverity encodes the severity of a deprecation policy
  9. type DeprecationSeverity int
  10. const (
  11. // None indicates there is no deprecation
  12. None DeprecationSeverity = iota
  13. // Low indicates the deprecation policy won't affect user experience
  14. Low
  15. // Medium indicates the deprecation policy will affect user experience
  16. // either in a minor way or for a limited scope of users.
  17. Medium
  18. // High indicates the deprecation policy will strongly affect user experience
  19. High
  20. )
  21. // SHA1DeprecationPolicy encodes how a platform deprecates the support of SHA1
  22. type SHA1DeprecationPolicy struct {
  23. // the name of platform
  24. Platform string `json:"platform"`
  25. // policy severity, policies of the same platform will only trigger the one of highest severity
  26. Severity DeprecationSeverity `json:"severity"`
  27. // a human readable message describing the deprecation effects
  28. Description string `json:"description"`
  29. // the date when the policy is effective. zero value means effective immediately
  30. EffectiveDate time.Time `json:"effective_date"`
  31. // the expiry deadline indicates the latest date which a end-entity
  32. // certificate with SHA1 can be valid through.
  33. ExpiryDeadline time.Time `json:"expiry_deadline"`
  34. // the date beyond which SHA1 cert should not be issued.
  35. NeverIssueAfter time.Time `json:"never_issue_after"`
  36. }
  37. // SHA1DeprecationPolicys ia a list of various SHA1DeprecationPolicy's
  38. // proposed by major browser producers
  39. var SHA1DeprecationPolicys = []SHA1DeprecationPolicy{
  40. // Chrome:
  41. // if the leaf certificate expires between 01-01-2016 and 01-01-2017
  42. // and the chain (excluding root) contains SHA-1 cert, show "minor errors".
  43. {
  44. Platform: "Google Chrome",
  45. Description: "shows the SSL connection has minor problems",
  46. Severity: Medium,
  47. ExpiryDeadline: time.Date(2016, time.January, 1, 0, 0, 0, 0, time.UTC),
  48. },
  49. // Chrome:
  50. // if the leaf certificate expires after Jan. 1st 2017
  51. // and the chain (excluding root) contains SHA-1 cert, show "untrusted SSL".
  52. {
  53. Platform: "Google Chrome",
  54. Description: "shows the SSL connection is untrusted",
  55. Severity: High,
  56. ExpiryDeadline: time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC),
  57. },
  58. // Mozilla Firefox:
  59. // if the leaf certificate expires after Jan. 1st 2017, and
  60. // the chain (excluding root) contains SHA-1 cert, show a warning in the developer console.
  61. {
  62. Platform: "Mozilla Firefox",
  63. Description: "gives warning in the developer console",
  64. Severity: Low,
  65. ExpiryDeadline: time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC),
  66. },
  67. // Mozilla Firefox:
  68. // if a new certificate is issued after Jan. 1st 2016, and
  69. // it is a SHA-1 cert, reject it.
  70. {
  71. Platform: "Mozilla Firefox",
  72. Description: "shows the SSL connection is untrusted",
  73. Severity: Medium,
  74. EffectiveDate: time.Date(2016, time.January, 1, 0, 0, 0, 0, time.UTC),
  75. NeverIssueAfter: time.Date(2016, time.January, 1, 0, 0, 0, 0, time.UTC),
  76. },
  77. // Mozilla Firefox:
  78. // deprecate all valid SHA-1 cert chain on Jan. 1st 2017
  79. {
  80. Platform: "Mozilla Firefox",
  81. Description: "shows the SSL connection is untrusted",
  82. Severity: High,
  83. EffectiveDate: time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC),
  84. ExpiryDeadline: time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC),
  85. },
  86. // Microsoft Windows:
  87. // deprecate all valid SHA-1 cert chain on Jan. 1st 2017
  88. {
  89. Platform: "Microsoft Windows Vista and later",
  90. Description: "shows the SSL connection is untrusted",
  91. Severity: High,
  92. EffectiveDate: time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC),
  93. ExpiryDeadline: time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC),
  94. },
  95. }
  96. // Flag returns whether the policy flags the cert chain as deprecated for matching its deprecation criteria
  97. func (p SHA1DeprecationPolicy) Flag(chain []*x509.Certificate) bool {
  98. leaf := chain[0]
  99. if time.Now().After(p.EffectiveDate) {
  100. // Reject newly issued leaf certificate with SHA-1 after the specified deadline.
  101. if !p.NeverIssueAfter.IsZero() && leaf.NotBefore.After(p.NeverIssueAfter) {
  102. // Check hash algorithm of non-root leaf cert.
  103. if len(chain) > 1 && helpers.HashAlgoString(leaf.SignatureAlgorithm) == "SHA1" {
  104. return true
  105. }
  106. }
  107. // Reject certificate chain with SHA-1 that are still valid after expiry deadline.
  108. if !p.ExpiryDeadline.IsZero() && leaf.NotAfter.After(p.ExpiryDeadline) {
  109. // Check hash algorithm of non-root certs.
  110. for i, cert := range chain {
  111. if i < len(chain)-1 {
  112. if helpers.HashAlgoString(cert.SignatureAlgorithm) == "SHA1" {
  113. return true
  114. }
  115. }
  116. }
  117. }
  118. }
  119. return false
  120. }
  121. // SHA1DeprecationMessages returns a list of human-readable messages. Each message describes
  122. // how one platform rejects the chain based on SHA1 deprecation policies.
  123. func SHA1DeprecationMessages(chain []*x509.Certificate) []string {
  124. // record the most severe deprecation policy by each platform
  125. selectedPolicies := map[string]SHA1DeprecationPolicy{}
  126. for _, policy := range SHA1DeprecationPolicys {
  127. if policy.Flag(chain) {
  128. // only keep the policy with highest severity
  129. if selectedPolicies[policy.Platform].Severity < policy.Severity {
  130. selectedPolicies[policy.Platform] = policy
  131. }
  132. }
  133. }
  134. // build the message list
  135. list := []string{}
  136. for _, policy := range selectedPolicies {
  137. if policy.Severity > None {
  138. list = append(list, fmt.Sprintf("%s %s due to SHA-1 deprecation", policy.Platform, policy.Description))
  139. }
  140. }
  141. return list
  142. }