Repository: zmap/zlint (go)

Issue:
ct_sct_policy_count_unsatisfied should ignore precertificates
Follow up to https://github.com/zmap/zlint/pull/278. Since precertificates never have SCTs, the ct_sct_policy_count_unsatisfied linter should ignore precertificates.

Related also to https://github.com/letsencrypt/boulder/pull/4378.

Pull request:
lints: ct_sct_policy_count_unsatisfied NA for precerts.
The `ct_sct_policy_count_unsatisfied` lint should return NA when asked to lint a precertificate (e.g. a "poisoned" cert containing the `util.CtPoisonOID` extension defined in [RFC 6962](https://tools.ietf.org/html/rfc6962#section-3.1)).

The [`sctTestCerts.go`](https://gist.github.com/cpu/6d26b2718f29e184ff88a90f02d7cbcb) gist referenced by the test data was updated to support a `-poison` flag to make the `ctNoSCTsPoisoned.pem` test cert reproducible.

Before the `lints/lint_ct_sct_policy_count_unsatisified.go` `CheckApplies` function was updated the "No SCTs, poisoned" test case fails as described in https://github.com/zmap/zlint/issues/298:

```
    --- FAIL: TestSCTCountPolicyUnsatisified/No_SCTs,_poisoned (0.00s)
        lint_ct_sct_policy_count_unsatisfied_test.go:107: expected result NA was info
```

After the update it passes:

```
    --- PASS: TestSCTCountPolicyUnsatisified/No_SCTs,_poisoned (0.00s)
```

Resolves #298

Patch:
diff --git a/lints/lint_ct_sct_policy_count_unsatisfied.go b/lints/lint_ct_sct_policy_count_unsatisfied.go
index ef2d72af..b9edc426 100644
--- a/lints/lint_ct_sct_policy_count_unsatisfied.go
+++ b/lints/lint_ct_sct_policy_count_unsatisfied.go
@@ -30,9 +30,11 @@ func (l *sctPolicyCount) Initialize() error {
 	return nil
 }
 
-// CheckApplies returns true for any subscriber certificates.
+// CheckApplies returns true for any subscriber certificates that are not
+// precertificates (e.g. that do not have the CT poison extension defined in RFC
+// 6962.
 func (l *sctPolicyCount) CheckApplies(c *x509.Certificate) bool {
-	return util.IsSubscriberCert(c)
+	return util.IsSubscriberCert(c) && !util.IsExtInCert(c, util.CtPoisonOID)
 }
 
 // Execute checks if the provided certificate has embedded SCTs from


Test patch:
diff --git a/lints/lint_ct_sct_policy_count_unsatisfied_test.go b/lints/lint_ct_sct_policy_count_unsatisfied_test.go
index ffa03408..8b7c29fe 100644
--- a/lints/lint_ct_sct_policy_count_unsatisfied_test.go
+++ b/lints/lint_ct_sct_policy_count_unsatisfied_test.go
@@ -32,7 +32,13 @@ func TestSCTCountPolicyUnsatisified(t *testing.T) {
 		ExpectedResult LintStatus
 	}{
 		{
-			Name: "No SCTs",
+			Name: "No SCTs, poisoned",
+			// go run sctTestCerts.go -lifetime 3 -scts 0 -poison > testlint/testCerts/ctNoSCTsPoisoned.pem
+			Filename:       "ctNoSCTsPoisoned.pem",
+			ExpectedResult: NA,
+		},
+		{
+			Name: "No SCTs, no poison",
 			// go run sctTestCerts.go -lifetime 3 -scts 0 > testlint/testCerts/ctNoSCTs.pem
 			Filename:       "ctNoSCTs.pem",
 			ExpectedResult: Notice,
diff --git a/testlint/testCerts/ctNoSCTsPoisoned.pem b/testlint/testCerts/ctNoSCTsPoisoned.pem
new file mode 100644
index 00000000..6bf9989c
--- /dev/null
+++ b/testlint/testCerts/ctNoSCTsPoisoned.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBqjCCAVSgAwIBAgIIdekjUjPwZlAwDQYJKoZIhvcNAQELBQAwODE2MDQGA1UE
+AwwtbGludF9jdF9zY3RfcG9saWN5X2NvdW50X3Vuc2F0aXNpZmllZF90ZXN0IENB
+MB4XDTE5MDgwMTE1MTI1OFoXDTE5MTEwMTE1MTI1OFowEjEQMA4GA1UEAxMHem1h
+cC5pbzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC/7OeV5hQMd9bHYbbMa9Ztu56E
+EN4qppo0vDzbNnZ6LOqmX3wnlOtoXBpmeA6QUiBC5Dv6BcEat1QK/xPfYn8vAgMB
+AAGjaDBmMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
+BQUHAwIwDAYDVR0TAQH/BAIwADASBgNVHREECzAJggd6bWFwLmlvMBMGCisGAQQB
+1nkCBAMBAf8EAgUAMA0GCSqGSIb3DQEBCwUAA0EArQ9sDzTfmTnbi1QU7u0e45cs
+EF76gnwXlniTsoU+YykQ61r/Z92o3UNbJGTu2NKF9aoOhsA/QzK35Om8y90MbA==
+-----END CERTIFICATE-----