forked from cloudflare/cfssl
/
sha1.go
153 lines (142 loc) · 5.62 KB
/
sha1.go
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".
SHA1DeprecationPolicy{
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".
SHA1DeprecationPolicy{
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.
SHA1DeprecationPolicy{
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.
SHA1DeprecationPolicy{
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
SHA1DeprecationPolicy{
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
SHA1DeprecationPolicy{
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
}