forked from cloudflare/cfssl
/
ubiquity_crypto.go
166 lines (152 loc) · 4.88 KB
/
ubiquity_crypto.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
154
155
156
157
158
159
160
161
162
163
164
165
166
package ubiquity
// In this file, we mainly cover crypto ubiquity.
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/x509"
"github.com/cloudflare/cfssl/helpers"
"math"
)
// HashUbiquity represents a score for how ubiquitous a given hash
// algorithm is; the higher the score, the more preferable the algorithm
// is.
type HashUbiquity int
// KeyAlgoUbiquity represents a score for how ubiquitous a given
// public-key algorithm is; the higher the score, the more preferable
// the algorithm is.
type KeyAlgoUbiquity int
// SHA1 is ubiquitous. SHA2 is not supported on some legacy platforms.
// We consider MD2/MD5 is harmful and thus assign them lowest ubiquity.
const (
UnknownHashUbiquity HashUbiquity = 0
SHA2Ubiquity HashUbiquity = 70
SHA1Ubiquity HashUbiquity = 100
MD5Ubiquity HashUbiquity = 0
MD2Ubiquity HashUbiquity = 0
)
// RSA and DSA are considered ubiquitous. ECDSA256 and ECDSA384 should be
// supported by TLS 1.2 and have limited support from TLS 1.0 and
// 1.1, based on RFC6460, but ECDSA521 is less well-supported as
// a standard.
const (
RSAUbiquity KeyAlgoUbiquity = 100
DSAUbiquity KeyAlgoUbiquity = 100
ECDSA256Ubiquity KeyAlgoUbiquity = 70
ECDSA384Ubiquity KeyAlgoUbiquity = 70
ECDSA521Ubiquity KeyAlgoUbiquity = 30
UnknownAlgoUbiquity KeyAlgoUbiquity = 0
)
// hashUbiquity computes the ubiquity of the hash algorithm in the
// signature algorithm of a cert.
// SHA1 > SHA2 > MD > Others
func hashUbiquity(cert *x509.Certificate) HashUbiquity {
switch cert.SignatureAlgorithm {
case x509.ECDSAWithSHA1, x509.DSAWithSHA1, x509.SHA1WithRSA:
return SHA1Ubiquity
case x509.ECDSAWithSHA256, x509.ECDSAWithSHA384, x509.ECDSAWithSHA512,
x509.DSAWithSHA256, x509.SHA256WithRSA, x509.SHA384WithRSA,
x509.SHA512WithRSA:
return SHA2Ubiquity
case x509.MD5WithRSA, x509.MD2WithRSA:
return MD5Ubiquity
default:
return UnknownHashUbiquity
}
}
// keyAlgoUbiquity compute the ubiquity of the cert's public key algorithm
// RSA, DSA>ECDSA>Unknown
func keyAlgoUbiquity(cert *x509.Certificate) KeyAlgoUbiquity {
switch cert.PublicKeyAlgorithm {
case x509.ECDSA:
switch cert.PublicKey.(*ecdsa.PublicKey).Curve {
case elliptic.P256():
return ECDSA256Ubiquity
case elliptic.P384():
return ECDSA384Ubiquity
case elliptic.P521():
return ECDSA521Ubiquity
default:
return UnknownAlgoUbiquity
}
case x509.RSA:
if cert.PublicKey.(*rsa.PublicKey).N.BitLen() >= 1024 {
return RSAUbiquity
}
return UnknownAlgoUbiquity
case x509.DSA:
return DSAUbiquity
default:
return UnknownAlgoUbiquity
}
}
// ChainHashUbiquity scores a chain based on the hash algorithms used
// by the certificates in the chain.
func ChainHashUbiquity(chain []*x509.Certificate) HashUbiquity {
ret := math.MaxInt32
for _, cert := range chain {
uscore := int(hashUbiquity(cert))
if ret > uscore {
ret = uscore
}
}
return HashUbiquity(ret)
}
// ChainKeyAlgoUbiquity scores a chain based on the public-key algorithms
// used by the certificates in the chain.
func ChainKeyAlgoUbiquity(chain []*x509.Certificate) KeyAlgoUbiquity {
ret := math.MaxInt32
for _, cert := range chain {
uscore := int(keyAlgoUbiquity(cert))
if ret > uscore {
ret = uscore
}
}
return KeyAlgoUbiquity(ret)
}
// CompareChainHashUbiquity returns a positive, zero, or negative value
// if the hash ubiquity of the first chain is greater, equal, or less
// than the second chain.
func CompareChainHashUbiquity(chain1, chain2 []*x509.Certificate) int {
hu1 := ChainHashUbiquity(chain1)
hu2 := ChainHashUbiquity(chain2)
return int(hu1) - int(hu2)
}
// CompareChainKeyAlgoUbiquity returns a positive, zero, or negative value
// if the public-key ubiquity of the first chain is greater, equal,
// or less than the second chain.
func CompareChainKeyAlgoUbiquity(chain1, chain2 []*x509.Certificate) int {
kau1 := ChainKeyAlgoUbiquity(chain1)
kau2 := ChainKeyAlgoUbiquity(chain2)
return int(kau1) - int(kau2)
}
// CompareExpiryUbiquity ranks two certificate chains based on the exiry dates of intermediates and roots.
// Certs expire later are ranked higher than ones expire earlier. The ranking between chains are determined by
// the first pair of intermediates, scanned from the root level, that ar ranked differently.
func CompareExpiryUbiquity(chain1, chain2 []*x509.Certificate) int {
for i := 0; ; i++ {
if i >= len(chain1) || i >= len(chain2) {
break
}
c1 := chain1[len(chain1)-1-i]
c2 := chain2[len(chain2)-1-i]
t1 := c1.NotAfter
t2 := c2.NotAfter
// Check if expiry dates valid. Return if one or other is invalid.
// Otherwise rank by expiry date. Later is ranked higher.
c1Valid := helpers.ValidExpiry(c1)
c2Valid := helpers.ValidExpiry(c2)
if c1Valid && !c2Valid {
return 1
}
if !c1Valid && c2Valid {
return -1
}
r := compareTime(t1, t2)
// Return when we find rank difference.
if r != 0 {
return r
}
}
return 0
}