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