func (l *sctPolicyCount) Execute(c *x509.Certificate) *LintResult {
	// Determine the required number of SCTs from separate logs
	expected := appleCTPolicyExpectedSCTs(c)

	// If there are no SCTs then the job is easy. We can return a Notice
	// LintResult immediately.
	if len(c.SignedCertificateTimestampList) == 0 && expected > 0 {
		return &LintResult{
			Status: Notice,
			Details: fmt.Sprintf(
				"Certificate had 0 embedded SCTs. Browser policy may require %d for this certificate.",
				expected),
		}
	}

	// Build a map from LogID to SCT so that we can count embedded SCTs by unique
	// log.
	sctsByLogID := make(map[ct.SHA256Hash]*ct.SignedCertificateTimestamp)
	for _, sct := range c.SignedCertificateTimestampList {
		sctsByLogID[sct.LogID] = sct
	}

	// If the number of embedded SCTs from separate logs meets expected return
	// a Pass result.
	if len(sctsByLogID) >= expected {
		return &LintResult{Status: Pass}
	}

	// Otherwise return a Notice result - there weren't enough SCTs embedded in
	// the certificate. More must be provided by OCSP stapling if the certificate
	// is to meet Apple's CT policy.
	return &LintResult{
		Status: Notice,
		Details: fmt.Sprintf(
			"Certificate had %d embedded SCTs from distinct log IDs. "+
				"Browser policy may require %d for this certificate.",
			len(sctsByLogID), expected),
	}
}
func (l *sctPolicyCount) Execute(c *x509.Certificate) *LintResult {
	// Determine the required number of SCTs from separate logs
	expected := appleCTPolicyExpectedSCTs(c)

	// If there are no SCTs then the job is easy. We can return a Notice
	// LintResult immediately.
	if len(c.SignedCertificateTimestampList) == 0 && expected > 0 {
		return &LintResult{
			Status: Notice,
			Details: fmt.Sprintf(
				"Certificate had 0 embedded SCTs. Browser policy may require %d for this certificate.",
				expected),
		}
	}

	// Build a map from LogID to SCT so that we can count embedded SCTs by unique
	// log.
	sctsByLogID := make(map[ct.SHA256Hash]*ct.SignedCertificateTimestamp)
	for _, sct := range c.SignedCertificateTimestampList {
		sctsByLogID[sct.LogID] = sct
	}

	// If the number of embedded SCTs from separate logs meets expected return
	// a Pass result.
	if len(sctsByLogID) >= expected {
		return &LintResult{Status: Pass}
	}

	// Otherwise return a Notice result - there weren't enough SCTs embedded in
	// the certificate. More must be provided by OCSP stapling if the certificate
	// is to meet Apple's CT policy.
	return &LintResult{
		Status: Notice,
		Details: fmt.Sprintf(
			"Certificate had %d embedded SCTs from distinct log IDs. "+
				"Browser policy may require %d for this certificate.",
			len(sctsByLogID), expected),
	}
}
// Execute checks if the provided certificate has embedded SCTs from
// a sufficient number of unique CT logs to meet Apple's CT log policy[0],
// effective Oct 15th, 2018.
//
// The number of required SCTs from different logs is calculated based on the
// Certificate's lifetime. If the number of required SCTs are not embedded in
// the certificate a Notice level LintResult is returned.
//
// | Certificate lifetime | # of SCTs from separate logs |
// -------------------------------------------------------
// | Less than 15 months  | 2                            |
// | 15 to 27 months      | 3                            |
// | 27 to 39 months      | 4                            |
// | More than 39 months  | 5                            |
// -------------------------------------------------------
//
// Important note 1: We can't know whether additional SCTs were presented
// alongside the certificate via OCSP stapling. This linter assumes only
// embedded SCTs are used and ignores the portion of the Apple policy related to
// SCTs delivered via OCSP. This is one limitation that restricts the linter's
// findings to Notice level. See more background discussion in Issue 226[1].
//
// Important note 2: The linter doesn't maintain a list of Apple's trusted
// logs. The SCTs embedded in the certificate may not be from log's Apple
// actually trusts. Similarly the embedded SCT signatures are not validated
// in any way.
//
// [0]: https://support.apple.com/en-us/HT205280
// [1]: https://github.com/zmap/zlint/issues/226