github.com/zmap/zlint@v1.1.0/lints/lint_ecdsa_ee_invalid_ku.go (about)

     1  /*
     2   * ZLint Copyright 2019 Regents of the University of Michigan
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License"); you may not
     5   * use this file except in compliance with the License. You may obtain a copy
     6   * of the License at http://www.apache.org/licenses/LICENSE-2.0
     7   *
     8   * Unless required by applicable law or agreed to in writing, software
     9   * distributed under the License is distributed on an "AS IS" BASIS,
    10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    11   * implied. See the License for the specific language governing
    12   * permissions and limitations under the License.
    13   */
    14  
    15  package lints
    16  
    17  import (
    18  	"fmt"
    19  	"sort"
    20  	"strings"
    21  
    22  	"github.com/zmap/zcrypto/x509"
    23  	"github.com/zmap/zlint/util"
    24  )
    25  
    26  type ecdsaInvalidKU struct{}
    27  
    28  // Initialize is a no-op for this lint.
    29  func (l *ecdsaInvalidKU) Initialize() error {
    30  	return nil
    31  }
    32  
    33  // CheckApplies returns true when the certificate is a subscriber cert using an
    34  // ECDSA public key algorithm.
    35  func (l *ecdsaInvalidKU) CheckApplies(c *x509.Certificate) bool {
    36  	return util.IsSubscriberCert(c) && c.PublicKeyAlgorithm == x509.ECDSA
    37  }
    38  
    39  // Execute returns a Notice level LintResult if the ECDSA end entity certificate
    40  // being linted has Key Usage bits set other than digitalSignature,
    41  // nonRepudiation/contentCommentment, and keyAgreement.
    42  func (l *ecdsaInvalidKU) Execute(c *x509.Certificate) *LintResult {
    43  	// RFC 5480, Section 3 "Key Usage Bits" says:
    44  	//
    45  	//   If the keyUsage extension is present in an End Entity (EE)
    46  	//   certificate that indicates id-ecPublicKey in SubjectPublicKeyInfo,
    47  	//   then any combination of the following values MAY be present:
    48  	//
    49  	//     digitalSignature;
    50  	//     nonRepudiation; and
    51  	//     keyAgreement.
    52  	//
    53  	// So we set up `allowedKUs` to match. Note that per RFC 5280: recent editions
    54  	// of X.509 renamed "nonRepudiation" to "contentCommitment", which is the name
    55  	// of the Go x509 constant we use here alongside the digitalSignature and
    56  	// keyAgreement constants.
    57  	allowedKUs := map[x509.KeyUsage]bool{
    58  		x509.KeyUsageDigitalSignature:  true,
    59  		x509.KeyUsageContentCommitment: true,
    60  		x509.KeyUsageKeyAgreement:      true,
    61  	}
    62  
    63  	var invalidKUs []string
    64  	for ku, kuName := range util.KeyUsageToString {
    65  		if c.KeyUsage&ku != 0 {
    66  			if !allowedKUs[ku] {
    67  				invalidKUs = append(invalidKUs, kuName)
    68  			}
    69  		}
    70  	}
    71  
    72  	if len(invalidKUs) > 0 {
    73  		// Sort the invalid KUs to allow consistent ordering of Details messages for
    74  		// unit testing
    75  		sort.Strings(invalidKUs)
    76  		return &LintResult{
    77  			Status: Notice,
    78  			Details: fmt.Sprintf(
    79  				"Certificate had unexpected key usage(s): %s",
    80  				strings.Join(invalidKUs, ", ")),
    81  		}
    82  	}
    83  
    84  	return &LintResult{
    85  		Status: Pass,
    86  	}
    87  }
    88  
    89  func init() {
    90  	RegisterLint(&Lint{
    91  		Name:          "n_ecdsa_ee_invalid_ku",
    92  		Description:   "ECDSA end-entity certificates MAY have key usages: digitalSignature, nonRepudiation and keyAgreement",
    93  		Citation:      "RFC 5480 Section 3",
    94  		Source:        RFC5480,
    95  		EffectiveDate: util.CABEffectiveDate,
    96  		Lint:          &ecdsaInvalidKU{},
    97  	})
    98  }