github.com/zmap/zlint@v1.1.0/README.md (about)

     1  ZLint
     2  =====
     3  
     4  [![Build Status](https://travis-ci.org/zmap/zlint.svg?branch=master)](https://travis-ci.org/zmap/zlint)
     5  [![Go Report Card](https://goreportcard.com/badge/github.com/zmap/zlint)](https://goreportcard.com/report/github.com/zmap/zlint)
     6  
     7  ZLint is a X.509 certificate linter written in Go that checks for consistency
     8  with [RFC 5280](https://www.ietf.org/rfc/rfc5280.txt) and the CA/Browser Forum
     9  Baseline Requirements
    10  ([v.1.4.8](https://cabforum.org/wp-content/uploads/CA-Browser-Forum-BR-1.4.8.pdf)).
    11  
    12  A detailed list of BR coverage can be found here:
    13  https://docs.google.com/spreadsheets/d/1ywp0op9mkTaggigpdF2YMTubepowJ50KQBhc_b00e-Y.
    14  
    15  Requirements
    16  ------------
    17  
    18  ZLint requires [Go 1.13.x or newer](https://golang.org/doc/install) be
    19  installed. The command line setup instructions assume the `go` command is in
    20  your `$PATH`.
    21  
    22  Versioning
    23  ----------
    24  
    25  ZLint aims to follow [semantic versioning](https://semver.org/). The addition of
    26  new lints will generally result in a MINOR version revision. Since downstream
    27  projects depend on lint results and names for policy decisions changes of this
    28  nature will result in MAJOR version revision.
    29  
    30  Command Line Usage
    31  ------------------
    32  
    33  ZLint can be used on the command-line through a simple bundled executable
    34  _ZLint_ as well as through
    35  [ZCertificate](https://github.com/zmap/zcertificate), a more full-fledged
    36  command-line certificate parser that links against ZLint.
    37  
    38  Example ZLint CLI usage:
    39  
    40  	go get github.com/zmap/zlint/cmd/zlint
    41  	zlint mycert.pem
    42  
    43  
    44  Library Usage
    45  -------------
    46  
    47  ZLint can also be used as a library:
    48  
    49  ```go
    50  import (
    51  	"github.com/zmap/zcrypto/x509"
    52  	"github.com/zmap/zlint"
    53  )
    54  
    55  parsed, err := x509.ParseCertificate(raw)
    56  if err != nil {
    57  	// The certificate could not be parsed. Either error or halt.
    58  	log.Fatalf("could not parse certificate: %s", err)
    59  }
    60  zlintResultSet := zlint.LintCertificate(parsed)
    61  ```
    62  
    63  
    64  See https://github.com/zmap/zlint/blob/master/cmd/zlint/main.go for an example.
    65  
    66  
    67  Adding New Lints
    68  ----------------
    69  
    70  **Generating Lint Scaffolding.** The scaffolding for a new lints can be created
    71  by running `./newLint.sh <lint_name> <structName>`. Lint names are generally of
    72  the form `e_subject_common_name_not_from_san` where the first letter is one of:
    73  `e`, `w`, or `n` (error, warning, or notice respectively). Struct names
    74  following Go conventions, e.g., `subjectCommonNameNotFromSAN`. Example:
    75  `./newLint.sh e_subject_common_name_not_from_san subjectCommonNameNotFromSAN`.
    76  This will generate a new lint in the `lints` directory with the necessary
    77  fields filled out.
    78  
    79  **Choosing a Lint Result Level.** When choosing what `lints.LintStatus` your new
    80  lint should return (e.g. `Notice`,`Warn`, `Error`, or `Fatal`) the following
    81  general guidance may help. `Error` should be used for clear violations of RFC/BR
    82  `MUST` or `MUST NOT` requirements and include strong citations. `Warn` should be
    83  used for violations of RFC/BR `SHOULD` or `SHOULD NOT` requirements and again
    84  should include strong citations. `Notice` should be used for more general "FYI"
    85  statements that violate non-codified community standards or for cases where
    86  citations are unclear. Lastly `Fatal` should be used when there is an
    87  unresolvable error in `zlint`, `zcrypto` or some other part of the certificate
    88  processing.
    89  
    90  **Scoping a Lint.** Lints are executed in three steps. First, the ZLint
    91  framework determines whether a certificate falls within the scope of a given
    92  lint by calling `CheckApplies`. This is often used to scope lints to only check
    93  subscriber, intermediate CA, or root CAs. This function commonly calls one of a
    94  select number of helper functions: `IsCA`, `IsSubscriber`, `IsExtInCert`, or
    95  `DNSNamesExist`. Example:
    96  
    97  ```go
    98  func (l *caCRLSignNotSet) CheckApplies(c *x509.Certificate) bool {
    99  	return c.IsCA && util.IsExtInCert(c, util.KeyUsageOID)
   100  }
   101  ```
   102  
   103  Next, the framework determines whether the certificate was issued after the
   104  effective date of a Lint by checking whether the certificate was issued prior
   105  to the lint's `EffectiveDate`. You'll also need to fill out the source and
   106  description of what the lint is checking. We encourage you to copy text
   107  directly from the BR or RFC here. Example:
   108  
   109  ```go
   110  func init() {
   111  	RegisterLint(&Lint{
   112  		Name:          "e_ca_country_name_missing",
   113  		Description:   "Root and Subordinate CA certificates MUST have a countryName present in subject information",
   114  		Citation:      "BRs: 7.1.2.1",
   115  		EffectiveDate: util.CABEffectiveDate,
   116  		Test:          &caCountryNameMissing{},
   117  	})
   118  }
   119  ```
   120  
   121  The meat of the lint is contained within the `RunTest` function, which is
   122  passed `x509.Certificate`. **Note:** This is an X.509 object from
   123  [ZCrypto](https://github.com/zmap/zcrypto) not the Go standard library. Lints
   124  should perform their described test and then return a `ResultStruct` that
   125  contains a Result and optionally a `Details` string, e.g.,
   126  `ResultStruct{Result: Pass}`. If you encounter a situation in which you
   127  typically would return a Go `error` object, instead return
   128  `ResultStruct{Result: Fatal}`.
   129  
   130  Example:
   131  
   132  ```go
   133  func (l *caCRLSignNotSet) RunTest(c *x509.Certificate) *ResultStruct {
   134  	if c.KeyUsage&x509.KeyUsageCRLSign != 0 {
   135  		return &ResultStruct{Result: Pass}
   136  	}
   137  	return &ResultStruct{Result: Error}
   138  }
   139  ```
   140  
   141  **Creating Unit Tests.** Every lint should also have two corresponding unit
   142  tests for a success and failure condition. We have typically generated test
   143  certificates using Go (see https://golang.org/pkg/crypto/x509/#CreateCertificate
   144  for details), but OpenSSL could also be used. Test certificates should be placed
   145  in `testlint/testCerts` and called from the test file created by `newLint.sh`.
   146  Prepend the PEM with the output of `openssl x509 -text`.
   147  
   148  Example:
   149  
   150  ```go
   151  func TestBasicConstNotCritical(t *testing.T) {
   152  	// Only need to change these two values and the lint name
   153  	inputPath := "../testlint/testCerts/caBasicConstNotCrit.pem"
   154  	expected := Error
   155  	out, _ := Lints["e_basic_constraints_not_critical"].ExecuteTest(ReadCertificate(inputPath))
   156  	if out.Result != expected {
   157  		t.Errorf("%s: expected %s, got %s", inputPath, expected, out.Status)
   158  	}
   159  }
   160  
   161  ```
   162  
   163  **Integration Tests.** ZLint's [continuous
   164  integration](https://travis-ci.org/zmap/zlint) includes an integration test
   165  phase where all lints are run against a large corpus of certificates. The number
   166  of notice, warning, error and fatal results for each lint are captured and
   167  compared to a set of expected values in a configuration file. You may need to
   168  update these expected values when you add/change lints. Please see the
   169  [integration tests
   170  README](https://github.com/zmap/zlint/blob/master/integration/README.md) for
   171  more information.
   172  
   173  Updating the TLD Map
   174  --------------------
   175  
   176  ZLint maintains [a map of
   177  top-level-domains](https://github.com/zmap/zlint/blob/master/util/gtld_map.go)
   178  and their validity periods that is referenced by linters. As ICANN adds and
   179  removes TLDs this map need to be updated. To do so, ensure the
   180  `zlint-gtld-update` command is installed and in your `$PATH` and run `go
   181  generate`:
   182  
   183  	go get github.com/zmap/zlint/cmd/zlint-gtld-update
   184  	go generate github.com/zmap/zlint/...
   185  
   186  Zlint Users/Integrations
   187  -------------------------
   188  
   189  Pre-issuance linting is **strongly recommended** by the [Mozilla root
   190  program](https://wiki.allizom.org/CA/Required_or_Recommended_Practices#Pre-Issuance_Linting).
   191  Here are some projects/CAs known to integrate with ZLint in some fashion:
   192  
   193  * [Camerfirma](https://bugzilla.mozilla.org/show_bug.cgi?id=1556806#c5)
   194  * [CFSSL](https://github.com/cloudflare/cfssl/pull/1015)
   195  * [Sectigo and crt.sh](https://groups.google.com/forum/#!msg/mozilla.dev.security.policy/sjXswrcsvrE/Nl3OLd4PAAAJ)
   196  * [Digicert](https://bugzilla.mozilla.org/show_bug.cgi?id=1550645#c9)
   197  * [EJBCA](https://download.primekey.com/docs/EJBCA-Enterprise/6_11_1/adminguide.html#Post%20Processing%20Validators%20(Pre-Certificate%20or%20Certificate%20Validation))
   198  * [Government of Spain, FNMT](https://bugzilla.mozilla.org/show_bug.cgi?id=1495507#c8)
   199  * [Globalsign](https://cabforum.org/pipermail/public/2018-April/013233.html)
   200  * [GoDaddy](https://bugzilla.mozilla.org/show_bug.cgi?id=1462844#c6)
   201  * [Izenpe](https://bugzilla.mozilla.org/show_bug.cgi?id=1528290#c5)
   202  * [Let's Encrypt](https://letsencrypt.org) and [Boulder](https://github.com/letsencrypt/boulder)
   203  * [Siemens](https://bugzilla.mozilla.org/show_bug.cgi?id=1391063#c32)
   204  * [QuoVadis](https://bugzilla.mozilla.org/show_bug.cgi?id=1521950#c3)
   205  
   206  Please submit a pull request to update the README if you are aware of
   207  another CA/project that uses zlint.
   208  
   209  License and Copyright
   210  ---------------------
   211  
   212  ZMap Copyright 2019 Regents of the University of Michigan
   213  
   214  Licensed under the Apache License, Version 2.0 (the "License"); you may not use
   215  this file except in compliance with the License. You may obtain a copy of the
   216  License at http://www.apache.org/licenses/LICENSE-2.0
   217  
   218  Unless required by applicable law or agreed to in writing, software distributed
   219  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   220  CONDITIONS OF ANY KIND, either express or implied. See LICENSE for the specific
   221  language governing permissions and limitations under the License.