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
}
|