ubiquity_crypto.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package ubiquity
  2. // In this file, we mainly cover crypto ubiquity.
  3. import (
  4. "crypto/ecdsa"
  5. "crypto/elliptic"
  6. "crypto/rsa"
  7. "crypto/x509"
  8. "github.com/cloudflare/cfssl/helpers"
  9. "math"
  10. )
  11. // HashUbiquity represents a score for how ubiquitous a given hash
  12. // algorithm is; the higher the score, the more preferable the algorithm
  13. // is.
  14. type HashUbiquity int
  15. // KeyAlgoUbiquity represents a score for how ubiquitous a given
  16. // public-key algorithm is; the higher the score, the more preferable
  17. // the algorithm is.
  18. type KeyAlgoUbiquity int
  19. // SHA1 is ubiquitous. SHA2 is not supported on some legacy platforms.
  20. // We consider MD2/MD5 is harmful and thus assign them lowest ubiquity.
  21. const (
  22. UnknownHashUbiquity HashUbiquity = 0
  23. SHA2Ubiquity HashUbiquity = 70
  24. SHA1Ubiquity HashUbiquity = 100
  25. MD5Ubiquity HashUbiquity = 0
  26. MD2Ubiquity HashUbiquity = 0
  27. )
  28. // RSA and DSA are considered ubiquitous. ECDSA256 and ECDSA384 should be
  29. // supported by TLS 1.2 and have limited support from TLS 1.0 and
  30. // 1.1, based on RFC6460, but ECDSA521 is less well-supported as
  31. // a standard.
  32. const (
  33. RSAUbiquity KeyAlgoUbiquity = 100
  34. DSAUbiquity KeyAlgoUbiquity = 100
  35. ECDSA256Ubiquity KeyAlgoUbiquity = 70
  36. ECDSA384Ubiquity KeyAlgoUbiquity = 70
  37. ECDSA521Ubiquity KeyAlgoUbiquity = 30
  38. UnknownAlgoUbiquity KeyAlgoUbiquity = 0
  39. )
  40. // hashUbiquity computes the ubiquity of the hash algorithm in the
  41. // signature algorithm of a cert.
  42. // SHA1 > SHA2 > MD > Others
  43. func hashUbiquity(cert *x509.Certificate) HashUbiquity {
  44. switch cert.SignatureAlgorithm {
  45. case x509.ECDSAWithSHA1, x509.DSAWithSHA1, x509.SHA1WithRSA:
  46. return SHA1Ubiquity
  47. case x509.ECDSAWithSHA256, x509.ECDSAWithSHA384, x509.ECDSAWithSHA512,
  48. x509.DSAWithSHA256, x509.SHA256WithRSA, x509.SHA384WithRSA,
  49. x509.SHA512WithRSA:
  50. return SHA2Ubiquity
  51. case x509.MD5WithRSA, x509.MD2WithRSA:
  52. return MD5Ubiquity
  53. default:
  54. return UnknownHashUbiquity
  55. }
  56. }
  57. // keyAlgoUbiquity compute the ubiquity of the cert's public key algorithm
  58. // RSA, DSA>ECDSA>Unknown
  59. func keyAlgoUbiquity(cert *x509.Certificate) KeyAlgoUbiquity {
  60. switch cert.PublicKeyAlgorithm {
  61. case x509.ECDSA:
  62. switch cert.PublicKey.(*ecdsa.PublicKey).Curve {
  63. case elliptic.P256():
  64. return ECDSA256Ubiquity
  65. case elliptic.P384():
  66. return ECDSA384Ubiquity
  67. case elliptic.P521():
  68. return ECDSA521Ubiquity
  69. default:
  70. return UnknownAlgoUbiquity
  71. }
  72. case x509.RSA:
  73. if cert.PublicKey.(*rsa.PublicKey).N.BitLen() >= 1024 {
  74. return RSAUbiquity
  75. }
  76. return UnknownAlgoUbiquity
  77. case x509.DSA:
  78. return DSAUbiquity
  79. default:
  80. return UnknownAlgoUbiquity
  81. }
  82. }
  83. // ChainHashUbiquity scores a chain based on the hash algorithms used
  84. // by the certificates in the chain.
  85. func ChainHashUbiquity(chain []*x509.Certificate) HashUbiquity {
  86. ret := math.MaxInt32
  87. for _, cert := range chain {
  88. uscore := int(hashUbiquity(cert))
  89. if ret > uscore {
  90. ret = uscore
  91. }
  92. }
  93. return HashUbiquity(ret)
  94. }
  95. // ChainKeyAlgoUbiquity scores a chain based on the public-key algorithms
  96. // used by the certificates in the chain.
  97. func ChainKeyAlgoUbiquity(chain []*x509.Certificate) KeyAlgoUbiquity {
  98. ret := math.MaxInt32
  99. for _, cert := range chain {
  100. uscore := int(keyAlgoUbiquity(cert))
  101. if ret > uscore {
  102. ret = uscore
  103. }
  104. }
  105. return KeyAlgoUbiquity(ret)
  106. }
  107. // CompareChainHashUbiquity returns a positive, zero, or negative value
  108. // if the hash ubiquity of the first chain is greater, equal, or less
  109. // than the second chain.
  110. func CompareChainHashUbiquity(chain1, chain2 []*x509.Certificate) int {
  111. hu1 := ChainHashUbiquity(chain1)
  112. hu2 := ChainHashUbiquity(chain2)
  113. return int(hu1) - int(hu2)
  114. }
  115. // CompareChainKeyAlgoUbiquity returns a positive, zero, or negative value
  116. // if the public-key ubiquity of the first chain is greater, equal,
  117. // or less than the second chain.
  118. func CompareChainKeyAlgoUbiquity(chain1, chain2 []*x509.Certificate) int {
  119. kau1 := ChainKeyAlgoUbiquity(chain1)
  120. kau2 := ChainKeyAlgoUbiquity(chain2)
  121. return int(kau1) - int(kau2)
  122. }
  123. // CompareExpiryUbiquity ranks two certificate chains based on the exiry dates of intermediates and roots.
  124. // Certs expire later are ranked higher than ones expire earlier. The ranking between chains are determined by
  125. // the first pair of intermediates, scanned from the root level, that ar ranked differently.
  126. func CompareExpiryUbiquity(chain1, chain2 []*x509.Certificate) int {
  127. for i := 0; ; i++ {
  128. if i >= len(chain1) || i >= len(chain2) {
  129. break
  130. }
  131. c1 := chain1[len(chain1)-1-i]
  132. c2 := chain2[len(chain2)-1-i]
  133. t1 := c1.NotAfter
  134. t2 := c2.NotAfter
  135. // Check if expiry dates valid. Return if one or other is invalid.
  136. // Otherwise rank by expiry date. Later is ranked higher.
  137. c1Valid := helpers.ValidExpiry(c1)
  138. c2Valid := helpers.ValidExpiry(c2)
  139. if c1Valid && !c2Valid {
  140. return 1
  141. }
  142. if !c1Valid && c2Valid {
  143. return -1
  144. }
  145. r := compareTime(t1, t2)
  146. // Return when we find rank difference.
  147. if r != 0 {
  148. return r
  149. }
  150. }
  151. return 0
  152. }