Skip to content

Commit

Permalink
Merge branch 'master' into e_cab_dv_subject_invalid_values
Browse files Browse the repository at this point in the history
  • Loading branch information
christopher-henderson authored Mar 10, 2024
2 parents 25bc371 + e76cc77 commit c994c6a
Show file tree
Hide file tree
Showing 32 changed files with 2,076 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func init() {
lint.RegisterCertificateLint(&lint.CertificateLint{
LintMetadata: lint.LintMetadata{
Name: "w_ext_subject_key_identifier_not_recommended_subscriber",
Description: "Subcriber certificates use of Subject Key Identifier is NOT RECOMMENDED",
Description: "Subscriber certificates use of Subject Key Identifier is NOT RECOMMENDED",
Citation: "BRs v2: 7.1.2.7.6",
Source: lint.CABFBaselineRequirements,
EffectiveDate: util.SC62EffectiveDate,
Expand Down
145 changes: 145 additions & 0 deletions v3/lints/cabf_br/lint_invalid_subject_rdn_order.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* 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 <adriano.santoni@staff.aruba.it>
* of ACTALIS S.p.A. (www.actalis.com).
*/

package cabf_br

import (
"crypto/x509/pkix"
"encoding/asn1"

"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
)

func init() {
lint.RegisterCertificateLint(&lint.CertificateLint{
LintMetadata: lint.LintMetadata{
Name: "e_invalid_subject_rdn_order",
Description: "Subject field attributes (RDNs) SHALL be encoded in a specific order",
Citation: "BRs: 7.1.4.2",
Source: lint.CABFBaselineRequirements,
EffectiveDate: util.CABFBRs_2_0_0_Date,
},
Lint: NewInvalidSubjectRDNOrder,
})
}

type invalidSubjectRDNOrder struct{}

func NewInvalidSubjectRDNOrder() lint.LintInterface {
return &invalidSubjectRDNOrder{}
}

func (l *invalidSubjectRDNOrder) CheckApplies(c *x509.Certificate) bool {
return util.IsSubscriberCert(c)
}

func getShortOIDName(oid string) string {
switch oid {
case "0.9.2342.19200300.100.1.25":
return "DC"
case "2.5.4.6":
return "C"
case "2.5.4.8":
return "ST"
case "2.5.4.7":
return "L"
case "2.5.4.17":
return "postalCode"
case "2.5.4.9":
return "street"
case "2.5.4.10":
return "O"
case "2.5.4.4":
return "SN"
case "2.5.4.42":
return "givenName"
case "2.5.4.11":
return "OU"
case "2.5.4.3":
return "CN"
default:
return ""
}
}

func findElement(arr []string, target string) (int, bool) {
for i, value := range arr {
if value == target {
return i, true
}
}
return -1, false
}

func checkOrder(actualOrder []string, expectedOrder []string) bool {
var prevPosition int
prevPosition = 0

for _, targetElement := range actualOrder {
position, found := findElement(expectedOrder, targetElement)
if found {
if position < prevPosition {
return false
}
prevPosition = position
}
}
return true
}

func checkSubjectRDNOrder(cert *x509.Certificate) bool {

rawSubject := cert.RawSubject

var rdnSequence pkix.RDNSequence
_, err := asn1.Unmarshal(rawSubject, &rdnSequence)
if err != nil {
return false
}

var rdnOrder []string

for _, rdn := range rdnSequence {
for _, atv := range rdn {
rdnShortName := getShortOIDName(atv.Type.String())
if rdnShortName != "" {
rdnOrder = append(rdnOrder, rdnShortName)
}
}
}

// Expected order of RDNs as per CABF BR section 7.1.4.2
expectedRDNOrder := []string{"DC", "C", "ST", "L", "postalCode", "street", "O", "SN", "givenName", "OU", "CN"}

return checkOrder(rdnOrder, expectedRDNOrder)
}

func (l *invalidSubjectRDNOrder) Execute(c *x509.Certificate) *lint.LintResult {

var out lint.LintResult

if checkSubjectRDNOrder(c) {
out.Status = lint.Pass
} else {
out.Status = lint.Error
}
return &out
}
122 changes: 122 additions & 0 deletions v3/lints/cabf_br/lint_invalid_subject_rdn_order_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* 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 <adriano.santoni@staff.aruba.it>
* of ACTALIS S.p.A. (www.actalis.com).
*/

package cabf_br

import (
"testing"

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

//nolint:all
/*
=== Proper RDN order test cases
subject_rdn_order_ok_01.pem C, ST, L, O, CN
subject_rdn_order_ok_02.pem C, ST, L, postalCode, street, O, CN
subject_rdn_order_ok_03.pem <empty subject>
subject_rdn_order_ok_04.pem DC, DC, C, ST, L, O, CN
subject_rdn_order_ok_05.pem C, ST, L, street, O, CN, serialNumber, businessCategory, jurisdictionCountry
subject_rdn_order_ok_06.pem C, ST, L, SN, givenName, CN
subject_rdn_order_ok_07.pem CN
=== Wrong RDN order test cases
subject_rdn_order_ko_01.pem C, ST, L, CN, O
subject_rdn_order_ko_02.pem CN, O, L, ST, C
subject_rdn_order_ko_03.pem C, ST, L, O, CN, street
subject_rdn_order_ko_04.pem C, ST, L, O, CN, DC, DC
subject_rdn_order_ko_05.pem C, ST, L, givenName, SN, CN
subject_rdn_order_ko_06.pem C, ST, L, street, postalCode, O
subject_rdn_order_ko_07.pem CN, C
*/

func TestInvalidSubjectRDNOrder(t *testing.T) {
type Data struct {
input string
want lint.LintStatus
}
data := []Data{
{
input: "subject_rdn_order_ok_01.pem",
want: lint.Pass,
},
{
input: "subject_rdn_order_ok_02.pem",
want: lint.Pass,
},
{
input: "subject_rdn_order_ok_03.pem",
want: lint.Pass,
},
{
input: "subject_rdn_order_ok_04.pem",
want: lint.Pass,
},
{
input: "subject_rdn_order_ok_05.pem",
want: lint.Pass,
},
{
input: "subject_rdn_order_ok_06.pem",
want: lint.Pass,
},
{
input: "subject_rdn_order_ok_07.pem",
want: lint.Pass,
},
{
input: "subject_rdn_order_ko_01.pem",
want: lint.Error,
},
{
input: "subject_rdn_order_ko_02.pem",
want: lint.Error,
},
{
input: "subject_rdn_order_ko_03.pem",
want: lint.Error,
},
{
input: "subject_rdn_order_ko_04.pem",
want: lint.Error,
},
{
input: "subject_rdn_order_ko_05.pem",
want: lint.Error,
},
{
input: "subject_rdn_order_ko_06.pem",
want: lint.Error,
},
{
input: "subject_rdn_order_ko_07.pem",
want: lint.Error,
},
}
for _, testData := range data {
testData := testData
t.Run(testData.input, func(t *testing.T) {
out := test.TestLint("e_invalid_subject_rdn_order", testData.input)
if out.Status != testData.want {
t.Errorf("expected %s, got %s", testData.want, out.Status)
}
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* 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.
*/

package cabf_smime_br

import (
"net/url"

"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
)

func init() {
lint.RegisterCertificateLint(&lint.CertificateLint{
LintMetadata: lint.LintMetadata{
Name: "e_subscribers_crl_distribution_points_are_http",
Description: "cRLDistributionPoints SHALL have URI scheme HTTP.",
Citation: "7.1.2.3.b",
Source: lint.CABFSMIMEBaselineRequirements,
EffectiveDate: util.CABF_SMIME_BRs_1_0_0_Date,
},
Lint: NewSubscriberCrlDistributionPointsHTTP,
})
}

type subscriberCrlDistributionPointsHTTP struct{}

func NewSubscriberCrlDistributionPointsHTTP() lint.LintInterface {
return &subscriberCrlDistributionPointsHTTP{}
}

func (l *subscriberCrlDistributionPointsHTTP) CheckApplies(c *x509.Certificate) bool {
return util.IsSubscriberCert(c) && util.IsSMIMEBRCertificate(c)
}

func (l *subscriberCrlDistributionPointsHTTP) Execute(c *x509.Certificate) *lint.LintResult {
httpCount := 0
for _, dp := range c.CRLDistributionPoints {
parsed, err := url.Parse(dp)
if err != nil {
return &lint.LintResult{
Status: lint.Error,
Details: "SMIME certificate contains invalid CRL distribution point",
}
}
if parsed.Scheme == "http" {
httpCount++
}
}

if (util.IsMultipurposeSMIMECertificate(c) || util.IsStrictSMIMECertificate(c)) && httpCount != len(c.CRLDistributionPoints) {
return &lint.LintResult{
Status: lint.Error,
Details: "SMIME certificate contains invalid URI scheme in CRL distribution point",
}
}
if util.IsLegacySMIMECertificate(c) && httpCount == 0 {
return &lint.LintResult{
Status: lint.Error,
Details: "SMIME certificate contains no HTTP URI schemes as CRL distribution points",
}
}

return &lint.LintResult{Status: lint.Pass}
}
Loading

0 comments on commit c994c6a

Please sign in to comment.