diff --git a/v3/lints/rfc/lint_crl_has_authority_key_identifier.go b/v3/lints/rfc/lint_crl_has_authority_key_identifier.go new file mode 100644 index 000000000..8f6af37f5 --- /dev/null +++ b/v3/lints/rfc/lint_crl_has_authority_key_identifier.go @@ -0,0 +1,54 @@ +package rfc + +/* + * ZLint Copyright 2024 Regents of the University of Michigan + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +/* + * Contributed by Adriano Santoni + * of ACTALIS S.p.A. (www.actalis.com). + */ + +import ( + "github.com/zmap/zcrypto/x509" + "github.com/zmap/zlint/v3/lint" + "github.com/zmap/zlint/v3/util" +) + +func init() { + lint.RegisterRevocationListLint(&lint.RevocationListLint{ + LintMetadata: lint.LintMetadata{ + Name: "e_crl_has_authority_key_identifier", + Description: "The CRL must include Authority Key Identifier extension.", + Citation: "RFC5280 ยง5.2,1", + Source: lint.RFC5280, + EffectiveDate: util.RFC5280Date, + }, + Lint: func() lint.RevocationListLintInterface { return &crlAuthKeyID{} }, + }) +} + +type crlAuthKeyID struct{} + +func (l *crlAuthKeyID) CheckApplies(_ *x509.RevocationList) bool { + return true +} + +func (l *crlAuthKeyID) Execute(c *x509.RevocationList) *lint.LintResult { + for _, ext := range c.Extensions { + if ext.Id.Equal(util.AuthkeyOID) { + return &lint.LintResult{Status: lint.Pass} + } + } + return &lint.LintResult{Status: lint.Error, Details: "The CRL lacks the mandatory Authority Key Identifier extension."} +} diff --git a/v3/lints/rfc/lint_crl_has_authority_key_identifier_test.go b/v3/lints/rfc/lint_crl_has_authority_key_identifier_test.go new file mode 100644 index 000000000..a3303fef0 --- /dev/null +++ b/v3/lints/rfc/lint_crl_has_authority_key_identifier_test.go @@ -0,0 +1,49 @@ +package rfc + +/* + * ZLint Copyright 2024 Regents of the University of Michigan + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import ( + "testing" + + "github.com/zmap/zlint/v3/lint" + "github.com/zmap/zlint/v3/test" +) + +func TestExecute(t *testing.T) { + tests := []struct { + name string + path string + want lint.LintStatus + }{ + { + name: "crlWithMissingAuthKeyID", + path: "crlWithMissingAuthKeyID.pem", + want: lint.Error, + }, + { + name: "crlWithAuthKeyID", + path: "crlWithAuthKeyID.pem", + want: lint.Pass, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got := test.TestRevocationListLint(t, "e_crl_has_authority_key_identifier", tc.path) + if got.Status != tc.want { + t.Errorf("Execute() = %v, want %v", got.Status, tc.want) + } + }) + } +} diff --git a/v3/testdata/crlWithAuthKeyID.pem b/v3/testdata/crlWithAuthKeyID.pem new file mode 100644 index 000000000..b80642b38 --- /dev/null +++ b/v3/testdata/crlWithAuthKeyID.pem @@ -0,0 +1,12 @@ +-----BEGIN X509 CRL----- +MIIBvDCBpQIBATANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDEwdSb290IENBFxEy +NDEwMjgyMzI5MzErMDEwMBcRMjUxMDI4MjMyOTMxKzAxMDAwJjAkAgEBFxEyNDEw +MjgyMzI5MzErMDEwMDAMMAoGA1UdFQQDCgEFoC8wLTAKBgNVHRQEAwIBATAfBgNV +HSMEGDAWgBRUsHutRbjiQH/7Cm77vjPJPKOE1TANBgkqhkiG9w0BAQsFAAOCAQEA +lz8TEEYTSCY633weMHkCMjJZoPgOmM5kIGBMg8Mgl6GNJA3pZYfwUhxpa+eb+M7U +WBo3JtXLWrIsu++YitTw16kLWIsUg2iEtDDZnPVagw+qtrYnifsihF+aSjbOUBQr +oaT5wnPbf3tG5I84TZ5/rTtkG7wtuU7bbSc2GdaG1x33cIG/EXMzgwxNWwoKSo2w +Z2spALtQFyPLTGxf9jhS7mYMDEAxu7njw5/10/BLGOWzmQhlkHaqdeqZqMk/y9gX +45y0z7F4T7SqpafacQHk4v6TD8vWVtCIU8gp0vNJTkJITZpdjm9IwgHexXsQXXrF +DXk+Gj9jgl9PQefJwSGTSg== +-----END X509 CRL----- diff --git a/v3/testdata/crlWithMissingAuthKeyID.pem b/v3/testdata/crlWithMissingAuthKeyID.pem new file mode 100644 index 000000000..e9d3c6462 --- /dev/null +++ b/v3/testdata/crlWithMissingAuthKeyID.pem @@ -0,0 +1,11 @@ +-----BEGIN X509 CRL----- +MIIBmzCBhAIBATANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDEwdSb290IENBFxEy +NDEwMjgyMzIxMjkrMDEwMBcRMjUxMDI4MjMyMTI5KzAxMDAwJjAkAgEBFxEyNDEw +MjgyMzIxMjkrMDEwMDAMMAoGA1UdFQQDCgEFoA4wDDAKBgNVHRQEAwIBATANBgkq +hkiG9w0BAQsFAAOCAQEACPLUGxlwMl/VViDPl/WXdUmOwemYhjgPsCqiyeh2m5ud +Ewp87b3rWpN/2xcTP6VNEgXDyVulX0OdKBI0t4UwXQoKnsXlIChQ8eJMTxvIDjcZ +hAOhtDjigKAlxQLzHcE/5C+dkZxK4McfwnA8Hd5MfasWqY9e8AWzaW04/V1gXZsT +v+6ivSpA0m1uS/oEhdqKg0x6WYWs8RnzgwMDZeg9UqOKq0J1xqQ96yZF4vfxWqCJ +kXajMAEerkWDK4ymxl6CgfGnAVzxxCtIuWJnto44j6QsOR1WvPSiD9NxGnfvEqPJ +7pTy0x7sF8IKkTFr4P66pttnrkcDvA+3ot1BbgB3GQ== +-----END X509 CRL-----