Skip to content

Commit

Permalink
Add CRL Lints for the ReasonCode extension from the baseline requirem…
Browse files Browse the repository at this point in the history
…ents and RFC 5280.
  • Loading branch information
aaomidi committed May 6, 2023
1 parent 997ad51 commit d871b51
Show file tree
Hide file tree
Showing 14 changed files with 464 additions and 0 deletions.
65 changes: 65 additions & 0 deletions v3/lints/cabf_br/lint_cabf_crl_reason_code_not_critical.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package cabf_br

/*
* ZLint Copyright 2023 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 (
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
)

type crlReasonCodeNotCritical struct{}

func init() {
lint.RegisterRevocationListLint(&lint.RevocationListLint{
LintMetadata: lint.LintMetadata{
Name: "e_cab_crl_reason_code_not_critical",
Description: "If present, CRL Reason Code extension MUST NOT be marked critical.",
Citation: "BRs: 7.2.2",
Source: lint.CABFBaselineRequirements,
EffectiveDate: util.CABEffectiveDate,
},
Lint: NewCrlReasonCodeNotCritical,
})
}

func NewCrlReasonCodeNotCritical() lint.RevocationListLintInterface {
return &crlReasonCodeNotCritical{}
}

func (l *crlReasonCodeNotCritical) CheckApplies(c *x509.RevocationList) bool {
for _, c := range c.RevokedCertificates {
if c.ReasonCode != nil {
return true
}
}
return false
}

func (l *crlReasonCodeNotCritical) Execute(c *x509.RevocationList) *lint.LintResult {
for _, c := range c.RevokedCertificates {
if c.ReasonCode == nil {
continue
}
for _, ext := range c.Extensions {
if ext.Id.Equal(util.ReasonCodeOID) {
if ext.Critical {
return &lint.LintResult{Status: lint.Error, Details: "CRL Reason Code extension MUST NOT be marked as critical."}
}
}
}
}
return &lint.LintResult{Status: lint.Pass}
}
59 changes: 59 additions & 0 deletions v3/lints/cabf_br/lint_cabf_crl_reason_code_not_critical_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package cabf_br

import (
"strings"
"testing"

"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/test"
)

/*
* ZLint Copyright 2023 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.
*/

func TestCrlReasonCodeNotCrit(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
path string
want lint.LintStatus
wantSubStr string
}{
{
name: "CRL reason code critical",
path: "crlReasonCodeCrit.pem",
want: lint.Error,
wantSubStr: "MUST NOT be marked as critical",
},
{
name: "CRL with reason code 5",
path: "crlWithReasonCode5.pem",
want: lint.Pass,
},
}

for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
gotStatus := test.TestRevocationListLint(t, "e_cab_crl_reason_code_not_critical", tc.path)
if tc.want != gotStatus.Status {
t.Errorf("%s: expected %s, got %s", tc.path, tc.want, gotStatus.Status)
}
if !strings.Contains(gotStatus.Details, tc.wantSubStr) {
t.Errorf("%s: expected %s, got %s", tc.path, tc.wantSubStr, gotStatus.Details)
}
})
}

}
73 changes: 73 additions & 0 deletions v3/lints/cabf_br/lint_cabf_crl_valid_reason_codes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package cabf_br

/*
* ZLint Copyright 2023 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 (
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
)

type crlHasValidReasonCode struct{}

func init() {
lint.RegisterRevocationListLint(&lint.RevocationListLint{
LintMetadata: lint.LintMetadata{
Name: "e_cab_crl_has_valid_reason_code",
Description: "CRL Reason codes 1, 3, 4, 5, 9.",
Citation: "BRs: 7.2.2",
Source: lint.CABFBaselineRequirements,
EffectiveDate: util.CABFBRs_SC61_CRL_Date,
},
Lint: NewCrlHasValidReasonCode,
})
}

func NewCrlHasValidReasonCode() lint.RevocationListLintInterface {
return &crlHasValidReasonCode{}
}

func (l *crlHasValidReasonCode) CheckApplies(c *x509.RevocationList) bool {
for _, c := range c.RevokedCertificates {
if c.ReasonCode != nil {
return true
}
}
return false
}

var validReasons = map[int]bool{
1: true,
3: true,
4: true,
5: true,
9: true,
}

func (l *crlHasValidReasonCode) Execute(c *x509.RevocationList) *lint.LintResult {
for _, c := range c.RevokedCertificates {
if c.ReasonCode == nil {
continue
}
code := *c.ReasonCode
if code == 0 {
return &lint.LintResult{Status: lint.Error, Details: "The reason code CRL entry extension SHOULD be absent instead of using the unspecified (0) reasonCode value."}
}
if _, ok := validReasons[code]; !ok {
return &lint.LintResult{Status: lint.Error, Details: "Reason code not included in BR: 7.2.2"}
}
}
return &lint.LintResult{Status: lint.Pass}
}
76 changes: 76 additions & 0 deletions v3/lints/cabf_br/lint_cabf_crl_valid_reason_codes_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package cabf_br

import (
"strings"
"testing"

"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/test"
)

/*
* ZLint Copyright 2023 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.
*/

func TestCrlValidReasonCodes(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
path string
want lint.LintStatus
wantSubStr string
}{
{
name: "CRL with reason code 0",
path: "crlWithReasonCode0.pem",
want: lint.Error,
wantSubStr: "The reason code CRL entry extension SHOULD be absent instead of using the unspecified",
},
{
// This test case is significant since reason code 2 is not allowed by CABF
name: "CRL with reason code 2",
path: "crlWithReasonCode2.pem",
want: lint.Error,
wantSubStr: "Reason code not included in BR: 7.2.2",
},
{
name: "CRL with reason code 5",
path: "crlWithReasonCode5.pem",
want: lint.Pass,
},
{
name: "CRL with reason code 7",
path: "crlWithReasonCode7.pem",
want: lint.Error,
wantSubStr: "Reason code not included in BR: 7.2.2",
},
{
name: "CRL thisUpdate before enforcement",
path: "crlThisUpdate20230505.pem",
want: lint.NE,
},
}

for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
gotStatus := test.TestRevocationListLint(t, "e_cab_crl_has_valid_reason_code", tc.path)
if tc.want != gotStatus.Status {
t.Errorf("%s: expected %s, got %s", tc.path, tc.want, gotStatus.Status)
}
if !strings.Contains(gotStatus.Details, tc.wantSubStr) {
t.Errorf("%s: expected %s, got %s", tc.path, tc.wantSubStr, gotStatus.Details)
}
})
}
}
76 changes: 76 additions & 0 deletions v3/lints/rfc/lint_crl_valid_reason_codes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package rfc

/*
* ZLint Copyright 2023 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 (
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
)

type crlHasValidReasonCode struct{}

/*
***********************************************
RFC 5280: 5.3.1
CRL issuers are strongly
encouraged to include meaningful reason codes in CRL entries;
however, the reason code CRL entry extension SHOULD be absent instead
of using the unspecified (0) reasonCode value.
***********************************************
*/
func init() {
lint.RegisterRevocationListLint(&lint.RevocationListLint{
LintMetadata: lint.LintMetadata{
Name: "e_crl_has_valid_reason_code",
Description: "If CRL has a reason code, it must be in 5.3.1 and not be 0.",
Citation: "RFC 5280: 5.3.1",
Source: lint.RFC5280,
EffectiveDate: util.RFC5280Date,
},
Lint: NewCrlHasValidReasonCode,
})
}

func NewCrlHasValidReasonCode() lint.RevocationListLintInterface {
return &crlHasValidReasonCode{}
}

func (l *crlHasValidReasonCode) CheckApplies(c *x509.RevocationList) bool {
for _, c := range c.RevokedCertificates {
if c.ReasonCode != nil {
return true
}
}
return false
}

func (l *crlHasValidReasonCode) Execute(c *x509.RevocationList) *lint.LintResult {
for _, c := range c.RevokedCertificates {
if c.ReasonCode == nil {
continue
}
code := *c.ReasonCode
if code == 0 {
return &lint.LintResult{Status: lint.Error, Details: "The reason code CRL entry extension SHOULD be absent instead of using the unspecified (0) reasonCode value."}
}
if code == 7 || code > 10 {
return &lint.LintResult{Status: lint.Error, Details: "Reason code not included in RFC 5280: 5.3.1"}
}
}
return &lint.LintResult{Status: lint.Pass}
}
Loading

0 comments on commit d871b51

Please sign in to comment.