167 lines
4.9 KiB
Go
167 lines
4.9 KiB
Go
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
|
|
}
|