github.com/letsencrypt/boulder@v0.20251208.0/linter/lints/chrome/e_scts_from_same_operator.go (about) 1 package chrome 2 3 import ( 4 "time" 5 6 "github.com/zmap/zcrypto/x509" 7 "github.com/zmap/zcrypto/x509/ct" 8 "github.com/zmap/zlint/v3/lint" 9 "github.com/zmap/zlint/v3/util" 10 11 "github.com/letsencrypt/boulder/ctpolicy/loglist" 12 "github.com/letsencrypt/boulder/linter/lints" 13 ) 14 15 type sctsFromSameOperator struct { 16 logList loglist.List 17 } 18 19 func init() { 20 lint.RegisterCertificateLint(&lint.CertificateLint{ 21 LintMetadata: lint.LintMetadata{ 22 Name: "e_scts_from_same_operator", 23 Description: "Let's Encrypt Subscriber Certificates have two SCTs from logs run by different operators", 24 Citation: "Chrome CT Policy", 25 Source: lints.ChromeCTPolicy, 26 EffectiveDate: time.Date(2022, time.April, 15, 0, 0, 0, 0, time.UTC), 27 }, 28 Lint: NewSCTsFromSameOperator, 29 }) 30 } 31 32 func NewSCTsFromSameOperator() lint.CertificateLintInterface { 33 return &sctsFromSameOperator{logList: loglist.GetLintList()} 34 } 35 36 func (l *sctsFromSameOperator) CheckApplies(c *x509.Certificate) bool { 37 return util.IsSubscriberCert(c) && !util.IsExtInCert(c, util.CtPoisonOID) 38 } 39 40 func (l *sctsFromSameOperator) Execute(c *x509.Certificate) *lint.LintResult { 41 if len(l.logList) == 0 { 42 return &lint.LintResult{ 43 Status: lint.NE, 44 Details: "Failed to load log list, unable to check Certificate SCTs.", 45 } 46 } 47 48 if len(c.SignedCertificateTimestampList) < 2 { 49 return &lint.LintResult{ 50 Status: lint.Error, 51 Details: "Certificate had too few embedded SCTs; browser policy requires 2.", 52 } 53 } 54 55 logIDs := make(map[ct.SHA256Hash]struct{}) 56 for _, sct := range c.SignedCertificateTimestampList { 57 logIDs[sct.LogID] = struct{}{} 58 } 59 60 if len(logIDs) < 2 { 61 return &lint.LintResult{ 62 Status: lint.Error, 63 Details: "Certificate SCTs from too few distinct logs; browser policy requires 2.", 64 } 65 } 66 67 rfc6962Compliant := false 68 operatorNames := make(map[string]struct{}) 69 for logID := range logIDs { 70 log, err := l.logList.GetByID(logID.Base64String()) 71 if err != nil { 72 // This certificate *may* have more than 2 SCTs, so missing one now isn't 73 // a problem. 74 continue 75 } 76 if !log.Tiled { 77 rfc6962Compliant = true 78 } 79 operatorNames[log.Operator] = struct{}{} 80 } 81 82 if !rfc6962Compliant { 83 return &lint.LintResult{ 84 Status: lint.Error, 85 Details: "At least one certificate SCT must be from an RFC6962-compliant log.", 86 } 87 } 88 89 if len(operatorNames) < 2 { 90 return &lint.LintResult{ 91 Status: lint.Error, 92 Details: "Certificate SCTs from too few distinct log operators; browser policy requires 2.", 93 } 94 } 95 96 return &lint.LintResult{ 97 Status: lint.Pass, 98 } 99 }