Update to zlint 3.6.6 (#8194)

v3.6.5 and v3.6.6 include several new lints and bugfixes.
Release notes at https://github.com/zmap/zlint/releases
This commit is contained in:
Matthew McPherrin 2025-05-16 14:48:31 -04:00 committed by GitHub
parent bef73f3c8b
commit caa29b2937
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 1291 additions and 125 deletions

4
go.mod
View File

@ -28,8 +28,8 @@ require (
github.com/redis/go-redis/v9 v9.7.3
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399
github.com/weppos/publicsuffix-go v0.40.3-0.20250307081557-c05521c3453a
github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c
github.com/zmap/zlint/v3 v3.6.4
github.com/zmap/zcrypto v0.0.0-20250129210703-03c45d0bae98
github.com/zmap/zlint/v3 v3.6.6
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0
go.opentelemetry.io/otel v1.34.0

62
go.sum
View File

@ -1,10 +1,8 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
github.com/a8m/expect v1.0.0/go.mod h1:4IwSCMumY49ScypDnjNbYEjgVeqy1/U2cEs3Lat96eA=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@ -53,14 +51,12 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@ -111,23 +107,15 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4er
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/certificate-transparency-go v1.3.2-0.20250507091337-0eddb39e94f8 h1:1RSWsOSxq2gk4pD/63bhsPwoOXgz2yXVadxXPbwZ0ec=
github.com/google/certificate-transparency-go v1.3.2-0.20250507091337-0eddb39e94f8/go.mod h1:6Rm5w0Mlv87LyBNOCgfKYjdIBBpF42XpXGsbQvQGomQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-github/v50 v50.2.0/go.mod h1:VBY8FB6yPIjrtKhozXv4FQupxKLS6H4m6xFZlT43q8Q=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
@ -238,7 +226,7 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
@ -249,9 +237,15 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0=
@ -259,7 +253,7 @@ github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHT
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222/go.mod h1:s41lQh6dIsDWIC1OWh7ChWJXLH0zkJ9KHZVqA7vHyuQ=
github.com/weppos/publicsuffix-go v0.40.3-0.20250127173806-e489a31678ca/go.mod h1:43Dfyxu2dpmLg56at26Q4k9gwf3yWSUiwk8kGnwzULk=
github.com/weppos/publicsuffix-go v0.40.3-0.20250307081557-c05521c3453a h1:YTfQ27VVE3PLzEZnGeSrxSKXMOs0JM2lfK0u4qT3/Mk=
github.com/weppos/publicsuffix-go v0.40.3-0.20250307081557-c05521c3453a/go.mod h1:Uao6F2ZmUjG3hDVL4Bn43YHRLuLapqXWKOa9GWk9JC0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
@ -272,11 +266,11 @@ github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54t
github.com/zmap/zcertificate v0.0.1/go.mod h1:q0dlN54Jm4NVSSuzisusQY0hqDWvu92C+TWveAxiVWk=
github.com/zmap/zcrypto v0.0.0-20201128221613-3719af1573cf/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ=
github.com/zmap/zcrypto v0.0.0-20201211161100-e54a5822fb7e/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ=
github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c h1:U1b4THKcgOpJ+kILupuznNwPiURtwVW3e9alJvji9+s=
github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c/go.mod h1:GSDpFDD4TASObxvfZfvpZZ3OWHIUHMlhVWlkOe4ewVk=
github.com/zmap/zcrypto v0.0.0-20250129210703-03c45d0bae98 h1:Qp98bmMm9JHPPOaLi2Nb6oWoZ+1OyOMWI7PPeJrirI0=
github.com/zmap/zcrypto v0.0.0-20250129210703-03c45d0bae98/go.mod h1:YTUyN/U1oJ7RzCEY5hUweYxbVUu7X+11wB7OXZT15oE=
github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8=
github.com/zmap/zlint/v3 v3.6.4 h1:r2kHfRF7mIsxW0IH4Og2iZnrlpCLTZBFjnXy1x/ZnZI=
github.com/zmap/zlint/v3 v3.6.4/go.mod h1:KQLVUquVaO5YJDl5a4k/7RPIbIW2v66+sRoBPNZusI8=
github.com/zmap/zlint/v3 v3.6.6 h1:tH7RJM9bDmh7IonlLEkFIkIn8XDYDYjehhUPgpLVqYA=
github.com/zmap/zlint/v3 v3.6.6/go.mod h1:6yXG+CBOQBRpMCOnpIVPUUL296m5HYksZC9bj5LZkwE=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
@ -312,12 +306,11 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -336,7 +329,6 @@ golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
@ -344,17 +336,16 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -366,6 +357,7 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -381,19 +373,17 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
@ -401,27 +391,24 @@ golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXR
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -443,7 +430,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 h1:GVIKPyP/kLIyVOgOnTwFOrvQaQUzOzGMCxgFUOEmm24=
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw=
@ -453,10 +439,6 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=

View File

@ -15,10 +15,12 @@ package lint
*/
import (
"fmt"
"time"
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/util"
"golang.org/x/crypto/ocsp"
)
// LintInterface is implemented by each certificate linter.
@ -217,7 +219,31 @@ func (l *CertificateLint) CheckEffective(c *x509.Certificate) bool {
// CheckApplies()
// CheckEffective()
// Execute()
func (l *CertificateLint) Execute(cert *x509.Certificate, config Configuration) *LintResult {
func (l *CertificateLint) Execute(cert *x509.Certificate, config Configuration) (result *LintResult) {
defer func() {
if err := recover(); err != nil {
details := fmt.Sprintf("'%s' panicked. Error: %v", l.Name, err)
result = &LintResult{
Status: Fatal,
Details: details,
}
}
}()
result = l.execute(cert, config)
return
}
// Execute runs the lint against a certificate. For lints that are
// sourced from the CA/B Forum Baseline Requirements, we first determine
// if they are within the purview of the BRs. See CertificateLintInterface
// for details about the other methods called.
// The ordering is as follows:
//
// Configure() ----> only if the lint implements Configurable
// CheckApplies()
// CheckEffective()
// Execute()
func (l *CertificateLint) execute(cert *x509.Certificate, config Configuration) *LintResult {
if l.Source == CABFBaselineRequirements && !util.IsServerAuthCert(cert) {
return &LintResult{Status: NA}
}
@ -300,3 +326,60 @@ func checkEffective(effective, ineffective, target time.Time) bool {
strictlyBeforeIneffective := ineffective.IsZero() || target.Before(ineffective)
return onOrAfterEffective && strictlyBeforeIneffective
}
// OcspResponseLintInterface is implemented by each OCSP linter.
type OcspResponseLintInterface interface {
// CheckApplies runs once per OCSP response. It returns true if the Lint
// should run on the given OCSP response. If CheckApplies returns false, the
// Lint result is automatically set to NA without calling CheckEffective()
// or Run().
CheckApplies(o *ocsp.Response) bool
// Execute is the body of the lint. It is called for every OCSP response for
// which CheckApplies returns true.
Execute(o *ocsp.Response) *LintResult
}
// OcspResponseLint represents a single OCSP response linter.
type OcspResponseLint struct {
// Metadata associated with the linter.
LintMetadata
// A constructor which returns the implementation of the linter.
Lint func() OcspResponseLintInterface `json:"-"`
}
// CheckEffective returns true if o was generated on or after the EffectiveDate
// AND before (but not on) the Ineffective date. That is, CheckEffective
// returns true if...
//
// o.NextUpdate in [EffectiveDate, IneffectiveDate)
//
// If EffectiveDate is zero, then only IneffectiveDate is checked. Conversely,
// if IneffectiveDate is zero then only EffectiveDate is checked. If both EffectiveDate
// and IneffectiveDate are zero then CheckEffective always returns true.
func (l *OcspResponseLint) CheckEffective(o *ocsp.Response) bool {
return checkEffective(l.EffectiveDate, l.IneffectiveDate, o.NextUpdate)
}
// Execute runs the lint against an OCSP response.
// The ordering is as follows:
//
// Configure() ----> only if the lint implements Configurable
// CheckApplies()
// CheckEffective()
// Execute()
func (l *OcspResponseLint) Execute(o *ocsp.Response, config Configuration) *LintResult {
lint := l.Lint()
err := config.MaybeConfigure(lint, l.Name)
if err != nil {
return &LintResult{
Status: Fatal,
Details: err.Error()}
}
if !lint.CheckApplies(o) {
return &LintResult{Status: NA}
} else if !l.CheckEffective(o) {
return &LintResult{Status: NE}
}
return lint.Execute(o)
}

View File

@ -24,6 +24,7 @@ var (
_ linterLookup = &linterLookupImpl{}
_ CertificateLinterLookup = &certificateLinterLookupImpl{}
_ RevocationListLinterLookup = &revocationListLinterLookupImpl{}
_ OcspResponseLinterLookup = &ocspResponseLinterLookupImpl{}
)
type linterLookup interface {
@ -215,3 +216,76 @@ func newRevocationListLintLookup() revocationListLinterLookupImpl {
lints: make([]*RevocationListLint, 0),
}
}
// OcspResponseLinterLookup is an interface describing how registered OCSP response lints can be looked up.
type OcspResponseLinterLookup interface {
linterLookup
// ByName returns a pointer to the registered lint with the given name, or nil
// if there is no such lint registered in the registry.
ByName(name string) *OcspResponseLint
// BySource returns a list of registered lints that have the same LintSource as
// provided (or nil if there were no such lints in the registry).
BySource(s LintSource) []*OcspResponseLint
// Lints returns a list of all the lints registered.
Lints() []*OcspResponseLint
}
type ocspResponseLinterLookupImpl struct {
linterLookupImpl
// lintsByName is a map of all registered lints by name.
lintsByName map[string]*OcspResponseLint
lintsBySource map[LintSource][]*OcspResponseLint
lints []*OcspResponseLint
}
// ByName returns the Lint previously registered under the given name with
// Register, or nil if no matching lint name has been registered.
func (lookup *ocspResponseLinterLookupImpl) ByName(name string) *OcspResponseLint {
lookup.RLock()
defer lookup.RUnlock()
return lookup.lintsByName[name]
}
// BySource returns a list of registered lints that have the same LintSource as
// provided (or nil if there were no such lints).
func (lookup *ocspResponseLinterLookupImpl) BySource(s LintSource) []*OcspResponseLint {
lookup.RLock()
defer lookup.RUnlock()
return lookup.lintsBySource[s]
}
// Lints returns a list of registered lints.
func (lookup *ocspResponseLinterLookupImpl) Lints() []*OcspResponseLint {
lookup.RLock()
defer lookup.RUnlock()
return lookup.lints
}
func (lookup *ocspResponseLinterLookupImpl) register(lint *OcspResponseLint, name string, source LintSource) error {
if name == "" {
return errEmptyName
}
lookup.RLock()
defer lookup.RUnlock()
if existing := lookup.lintsByName[name]; existing != nil {
return &errDuplicateName{name}
}
lookup.lints = append(lookup.lints, lint)
lookup.lintNames = append(lookup.lintNames, name)
lookup.lintsByName[name] = lint
lookup.sources[source] = struct{}{}
lookup.lintsBySource[source] = append(lookup.lintsBySource[source], lint)
sort.Strings(lookup.lintNames)
return nil
}
func newOcspResponseLintLookup() ocspResponseLinterLookupImpl {
return ocspResponseLinterLookupImpl{
linterLookupImpl: newLinterLookup(),
lintsByName: make(map[string]*OcspResponseLint),
lintsBySource: make(map[LintSource][]*OcspResponseLint),
lints: make([]*OcspResponseLint, 0),
}
}

View File

@ -35,6 +35,8 @@ import (
//
// Only one of NameFilter or IncludeNames/ExcludeNames can be provided at
// a time.
//
//nolint:recvcheck
type FilterOptions struct {
// NameFilter is a regexp used to filter lints by their name. It is mutually
// exclusive with IncludeNames and ExcludeNames.
@ -110,12 +112,15 @@ type Registry interface { //nolint: interfacebloat // Somewhat unavoidable here.
CertificateLints() CertificateLinterLookup
// RevocationListLitns returns an interface used to lookup RevocationListLints.
RevocationListLints() RevocationListLinterLookup
// OcspResponseLints returns an interface used to lookup OcspResponseLints.
OcspResponseLints() OcspResponseLinterLookup
}
// registryImpl implements the Registry interface to provide a global collection
// of Lints that have been registered.
type registryImpl struct {
certificateLints certificateLinterLookupImpl
ocspResponseLints ocspResponseLinterLookupImpl
revocationListLints revocationListLinterLookupImpl
configuration Configuration
}
@ -171,7 +176,7 @@ func (r *registryImpl) registerCertificateLint(l *CertificateLint) error {
return r.certificateLints.register(l, l.Name, l.Source)
}
// registerCertificateLint registers a CertificateLint to the registry.
// registerRevocationListLint registers a RevocationListLint to the registry.
//
// An error is returned if the lint or lint's Lint pointer is nil, if the Lint
// has an empty Name or if the Name was previously registered.
@ -185,6 +190,23 @@ func (r *registryImpl) registerRevocationListLint(l *RevocationListLint) error {
return r.revocationListLints.register(l, l.Name, l.Source)
}
// register OcspResponseLint registers a OcspResponseLint to the registry.
//
// An error is returned if the lint or lint's Lint pointer is nil, if the Lint
// has an empty Name or if the Name was previously registered.
func (r *registryImpl) registerOcspResponseLint(l *OcspResponseLint) error {
if l == nil {
return errNilLint
}
if l.Lint() == nil {
return errNilLintPtr
}
if l.Name == "" {
return errEmptyName
}
return r.ocspResponseLints.register(l, l.Name, l.Source)
}
// ByName returns the Lint previously registered under the given name with
// Register, or nil if no matching lint name has been registered.
//
@ -203,6 +225,7 @@ func (r *registryImpl) ByName(name string) *Lint {
func (r *registryImpl) Names() []string {
var names []string
names = append(names, r.certificateLints.lintNames...)
names = append(names, r.ocspResponseLints.lintNames...)
names = append(names, r.revocationListLints.lintNames...)
sort.Strings(names)
@ -230,10 +253,20 @@ func (r *registryImpl) BySource(s LintSource) []*Lint {
// Sources returns a SourceList of registered LintSources. The list is not
// sorted but can be sorted by the caller with sort.Sort() if required.
func (r *registryImpl) Sources() SourceList {
set := map[LintSource]struct{}{}
for _, source := range r.certificateLints.Sources() {
set[source] = struct{}{}
}
for _, source := range r.revocationListLints.Sources() {
set[source] = struct{}{}
}
for _, source := range r.ocspResponseLints.Sources() {
set[source] = struct{}{}
}
var sources SourceList
sources = append(sources, r.certificateLints.Sources()...)
sources = append(sources, r.revocationListLints.Sources()...)
for source := range set {
sources = append(sources, source)
}
return sources
}
@ -245,6 +278,10 @@ func (r *registryImpl) RevocationListLints() RevocationListLinterLookup {
return &r.revocationListLints
}
func (r *registryImpl) OcspResponseLints() OcspResponseLinterLookup {
return &r.ocspResponseLints
}
// lintNamesToMap converts a list of lit names into a bool hashmap useful for
// filtering. If any of the lint names are not known by the registry an error is
// returned.
@ -260,6 +297,11 @@ func (r *registryImpl) lintNamesToMap(names []string) (map[string]bool, error) {
namesMap[n] = true
continue
}
if l := r.ocspResponseLints.ByName(n); l != nil {
namesMap[n] = true
continue
}
if l := r.revocationListLints.ByName(n); l != nil {
namesMap[n] = true
continue
@ -324,6 +366,14 @@ func (r *registryImpl) Filter(opts FilterOptions) (Registry, error) {
registerFunc = func() error {
return filteredRegistry.registerCertificateLint(l)
}
} else if l := r.ocspResponseLints.ByName(name); l != nil {
meta = l.LintMetadata
registerFunc = func() error {
if err := filteredRegistry.registerOcspResponseLint(l); err != nil {
return err
}
return nil
}
} else if l := r.revocationListLints.ByName(name); l != nil {
meta = l.LintMetadata
registerFunc = func() error {
@ -364,6 +414,10 @@ func (r *registryImpl) WriteJSON(w io.Writer) {
//nolint:errchkjson
_ = enc.Encode(lint)
}
for _, lint := range r.ocspResponseLints.Lints() {
//nolint:errchkjson
_ = enc.Encode(lint)
}
for _, lint := range r.revocationListLints.Lints() {
//nolint:errchkjson
@ -400,6 +454,15 @@ func (r *registryImpl) defaultConfiguration(globals []GlobalConfiguration) ([]by
}
}
for name, lint := range r.ocspResponseLints.lintsByName {
switch configurable := lint.Lint().(type) {
case Configurable:
configurables[name] = stripGlobalsFromExample(configurable.Configure())
default:
}
}
for name, lint := range r.revocationListLints.lintsByName {
switch configurable := lint.Lint().(type) {
case Configurable:
@ -444,6 +507,7 @@ func (r *registryImpl) defaultConfiguration(globals []GlobalConfiguration) ([]by
func NewRegistry() *registryImpl {
registry := &registryImpl{
certificateLints: newCertificateLintLookup(),
ocspResponseLints: newOcspResponseLintLookup(),
revocationListLints: newRevocationListLintLookup(),
}
registry.SetConfiguration(NewEmptyConfig())
@ -480,6 +544,22 @@ func RegisterCertificateLint(l *CertificateLint) {
}
}
// RegisterOcspResponseLint must be called once for each OcspResponseLint to be executed.
// Normally, RegisterOcspResponseLint is called from the Go init() function of a lint implementation.
//
// IMPORTANT: RegisterOcspResponseLint will panic if given a nil lint, or a lint
// with a nil Lint pointer, or if the lint name matches a previously registered
// lint's name. These conditions all indicate a bug that should be addressed by
// a developer.
func RegisterOcspResponseLint(l *OcspResponseLint) {
// RegisterLint always sets initialize to true. It's assumed this is called by
// the package init() functions and therefore must be doing the first
// initialization of a lint.
if err := globalRegistry.registerOcspResponseLint(l); err != nil {
panic(fmt.Sprintf("RegisterLint error: %v\n", err.Error()))
}
}
// RegisterRevocationListLint must be called once for each RevocationListLint to be executed.
// Normally, RegisterRevocationListLint is called from the Go init() function of a lint implementation.
//

View File

@ -22,7 +22,7 @@ import (
// LintStatus is an enum returned by lints inside of a LintResult.
//
//nolint:revive
//nolint:revive,recvcheck
type LintStatus int
// Known LintStatus values

View File

@ -32,6 +32,7 @@ const (
RFC5280 LintSource = "RFC5280"
RFC5480 LintSource = "RFC5480"
RFC5891 LintSource = "RFC5891"
RFC6960 LintSource = "RFC6960"
RFC6962 LintSource = "RFC6962"
RFC8813 LintSource = "RFC8813"
CABFBaselineRequirements LintSource = "CABF_BR"
@ -53,7 +54,21 @@ func (s *LintSource) UnmarshalJSON(data []byte) error {
}
switch LintSource(throwAway) {
case RFC8813, RFC5280, RFC5480, RFC5891, CABFBaselineRequirements, CABFEVGuidelines, CABFSMIMEBaselineRequirements, MozillaRootStorePolicy, AppleRootStorePolicy, Community, EtsiEsi, RFC6962:
case RFC3279,
RFC5280,
RFC5480,
RFC5891,
RFC6960,
RFC6962,
RFC8813,
CABFBaselineRequirements,
CABFCSBaselineRequirements,
CABFSMIMEBaselineRequirements,
CABFEVGuidelines,
MozillaRootStorePolicy,
AppleRootStorePolicy,
Community,
EtsiEsi:
*s = LintSource(throwAway)
return nil
default:
@ -71,34 +86,40 @@ func (s *LintSource) FromString(src string) {
// Trim space and try to match a known value
src = strings.TrimSpace(src)
switch LintSource(src) {
case RFC3279:
*s = RFC3279
case RFC5280:
*s = RFC5280
case RFC5480:
*s = RFC5480
case RFC5891:
*s = RFC5891
case RFC6962:
*s = RFC6962
case RFC8813:
*s = RFC8813
case CABFBaselineRequirements:
*s = CABFBaselineRequirements
case CABFEVGuidelines:
*s = CABFEVGuidelines
case CABFCSBaselineRequirements:
*s = CABFCSBaselineRequirements
case CABFSMIMEBaselineRequirements:
*s = CABFSMIMEBaselineRequirements
case CABFEVGuidelines:
*s = CABFEVGuidelines
case MozillaRootStorePolicy:
*s = MozillaRootStorePolicy
case AppleRootStorePolicy:
*s = AppleRootStorePolicy
case Community:
*s = Community
case RFC6962:
*s = RFC6962
case EtsiEsi:
*s = EtsiEsi
}
}
// SourceList is a slice of LintSources that can be sorted.
//
//nolint:recvcheck
type SourceList []LintSource
// Len returns the length of the list.

View File

@ -22,8 +22,6 @@ import (
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
"fmt"
)
func init() {
@ -72,7 +70,7 @@ func (l *caInvalidEKU) Execute(c *x509.Certificate) *lint.LintResult {
return &lint.LintResult{
Status: lint.Error,
Details: fmt.Sprintf("%s MUST not be present together with serverAuth in the EKU extension", util.GetEKUString(eku)),
Details: util.GetEKUString(eku) + "%s MUST not be present together with serverAuth in the EKU extension",
}
}
}

View File

@ -0,0 +1,84 @@
/*
* 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.
*/
package cabf_br
import (
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
"fmt"
)
func init() {
lint.RegisterRevocationListLint(&lint.RevocationListLint{
LintMetadata: lint.LintMetadata{
Name: "e_crl_next_update_invalid",
Description: "For CRLs covering (EE|CA) certificates, nextUpdate must be at most (10 days|12 months) beyond thisUpdate",
Citation: "Section 4.9.7 of BRs v1.8.7 (then section 7.2 since BRs v2.0.0)",
Source: lint.CABFBaselineRequirements,
EffectiveDate: util.CABFBRs_1_8_7_Date,
},
Lint: NewCrlNextUpdateInvalid,
})
}
type CrlNextUpdateInvalid struct {
SubscriberCRL bool `comment:"Set this to false if the CRL to be linted covers CA certificates"`
}
func (l *CrlNextUpdateInvalid) Configure() interface{} {
return l
}
func NewCrlNextUpdateInvalid() lint.RevocationListLintInterface {
return &CrlNextUpdateInvalid{
SubscriberCRL: true,
}
}
func (l *CrlNextUpdateInvalid) CheckApplies(c *x509.RevocationList) bool {
// If NextUpdate is absent it's an error but it's not this lint's business
return !c.NextUpdate.IsZero()
}
func (l *CrlNextUpdateInvalid) Execute(c *x509.RevocationList) *lint.LintResult {
// As set out in the CABF BRs
CabfMaxEECRLValidityDays := 10
CabfMaxCACRLValidityMonths := 12
if l.SubscriberCRL {
if c.NextUpdate.After(c.ThisUpdate.AddDate(0, 0, CabfMaxEECRLValidityDays)) {
return &lint.LintResult{
Status: lint.Error,
Details: fmt.Sprintf(
"For CRLs covering Subscriber Certificates, nextUpdate must be at most %d days after thisUpdate",
CabfMaxEECRLValidityDays),
}
}
} else {
if c.NextUpdate.After(c.ThisUpdate.AddDate(0, CabfMaxCACRLValidityMonths, 0)) {
return &lint.LintResult{
Status: lint.Error,
Details: fmt.Sprintf(
"For CRLs covering CA Certificates, nextUpdate must be at most %d months after thisUpdate",
CabfMaxCACRLValidityMonths),
}
}
}
return &lint.LintResult{Status: lint.Pass}
}

View File

@ -0,0 +1,96 @@
/*
* 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 asantoni64@gmail.com
*/
package cabf_br
import (
"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_ca_certificate_policies",
Description: "Checks that the Policy OIDs in the CertificatePolicies extension of a SubCA certificate comply with CABF requirements",
Citation: "CABF BRs §7.1.2.10.5",
Source: lint.CABFBaselineRequirements,
EffectiveDate: util.CABFBRs_2_0_0_Date,
},
Lint: NewInvalidCACertificatePolicies,
})
}
type invalidCACertificatePolicies struct{}
func NewInvalidCACertificatePolicies() lint.LintInterface {
return &invalidCACertificatePolicies{}
}
func (l *invalidCACertificatePolicies) CheckApplies(c *x509.Certificate) bool {
return util.IsCACert(c) && !util.IsRootCA(c)
}
func (l *invalidCACertificatePolicies) Execute(c *x509.Certificate) *lint.LintResult {
// Any type of TLS subordinate CA must have the CP extension,
// as can be seen from the entire chapter 7 of the BR
if !util.IsExtInCert(c, util.CertPolicyOID) {
return &lint.LintResult{
Status: lint.Error,
Details: "In a TLS subordinate CA certificate, the CertificatePolicies extension is mandatory",
}
}
anyPolicyOIDFound := false
reservedOIDFound := false
for _, oid := range c.PolicyIdentifiers {
if oid.Equal(util.AnyPolicyOID) {
anyPolicyOIDFound = true
}
if oid.Equal(util.BROrganizationValidatedOID) ||
oid.Equal(util.BRExtendedValidatedOID) ||
oid.Equal(util.BRDomainValidatedOID) ||
oid.Equal(util.BRIndividualValidatedOID) {
reservedOIDFound = true
}
}
if anyPolicyOIDFound {
if len(c.PolicyIdentifiers) > 1 {
// See the BR, Table 69: No Policy Restrictions
return &lint.LintResult{
Status: lint.Error,
Details: "The AnyPolicy OID must not be accompanied by any other policy OIDs",
}
} else {
return &lint.LintResult{Status: lint.Pass}
}
}
if !reservedOIDFound {
// See the BR, Table 70: Policy Restricted
return &lint.LintResult{
Status: lint.Error,
Details: "At least one CABF reserved policy OIDs MUST be present in a policy-restricted CA cert",
}
}
return &lint.LintResult{Status: lint.Pass}
}

View File

@ -15,8 +15,6 @@ package cabf_br
*/
import (
"fmt"
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
@ -59,7 +57,7 @@ func (l *subExtKeyUsageCheck) Execute(c *x509.Certificate) *lint.LintResult {
case x509.ExtKeyUsageAny, x509.ExtKeyUsageCodeSigning, x509.ExtKeyUsageTimeStamping,
x509.ExtKeyUsageOcspSigning, x509.ExtKeyUsageEmailProtection:
return &lint.LintResult{Status: lint.Error, Details: fmt.Sprintf("%s MUST NOT be present", util.GetEKUString(eku))}
return &lint.LintResult{Status: lint.Error, Details: util.GetEKUString(eku) + " MUST NOT be present"}
}
}

View File

@ -0,0 +1,101 @@
/*
* 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 <asantoni64@gmail.com>
*/
package cabf_ev
import (
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
"crypto/x509/pkix"
"encoding/asn1"
"fmt"
)
func init() {
lint.RegisterCertificateLint(&lint.CertificateLint{
LintMetadata: lint.LintMetadata{
Name: "e_ev_extra_subject_attribs",
Description: "CAs SHALL NOT include any Subject Distinguished Name attributes except as specified...",
Citation: "EVGs §7.1.4.2.9",
Source: lint.CABFEVGuidelines,
EffectiveDate: util.SC16EffectiveDate,
},
Lint: NewExtraSubjectAttribs,
})
}
type extraSubjectAttribs struct{}
func NewExtraSubjectAttribs() lint.LintInterface {
return &extraSubjectAttribs{}
}
func (l *extraSubjectAttribs) CheckApplies(c *x509.Certificate) bool {
return util.IsEV(c.PolicyIdentifiers) && util.IsSubscriberCert(c)
}
var allowedAttribs = map[string]bool{
"1.3.6.1.4.1.311.60.2.1.1": true, // joiLocalityName
"1.3.6.1.4.1.311.60.2.1.2": true, // joiStateOrProvinceName
"1.3.6.1.4.1.311.60.2.1.3": true, // joiCountryName
"2.5.4.3": true, // commonName
"2.5.4.5": true, // serialNumber
"2.5.4.6": true, // countryName
"2.5.4.7": true, // localityName
"2.5.4.8": true, // stateOrProvinceName
"2.5.4.9": true, // streetAddress
"2.5.4.10": true, // organizationName
/*
* We also include the OU attribute here, even though it is now banned, because this lint
* deals with a more general requirement that came into force long before the OU ban,
* and there is already another lint that deals with the OU attribute specifically.
*/
"2.5.4.11": true, // organizationUnitName
"2.5.4.15": true, // businessCategory
"2.5.4.17": true, // postalCode
/*
* The organizationIdentifier attribute is only permitted starting from 21-may-2019 (EVGL 1.7.0),
* which is slightly after SC16 came into force, however any certificates that contain this
* attribute and were issued before that date have long since expired, so it makes no difference.
*/
"2.5.4.97": true, // organizationIdentifier
}
func (l *extraSubjectAttribs) Execute(c *x509.Certificate) *lint.LintResult {
var rdnSequence pkix.RDNSequence
_, err := asn1.Unmarshal(c.RawSubject, &rdnSequence)
if err != nil {
return &lint.LintResult{Status: lint.Fatal}
}
for _, rdn := range rdnSequence {
for _, atv := range rdn {
if !allowedAttribs[atv.Type.String()] {
return &lint.LintResult{
Status: lint.Error,
Details: fmt.Sprintf("Subject attribute %s is not allowed in EV certificates", atv.Type.String()),
}
}
}
}
return &lint.LintResult{Status: lint.Pass}
}

View File

@ -0,0 +1,80 @@
/*
* 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 <asantoni64@gmail.com>
package cabf_ev
import (
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
"fmt"
)
func init() {
lint.RegisterCertificateLint(&lint.CertificateLint{
LintMetadata: lint.LintMetadata{
Name: "e_ev_invalid_orgid_reg_scheme",
Description: "The Registration Schemes allowed in organizationIdentifier are those listed in Appendix H",
Citation: "CABF EV Guidelines §9.2.8",
Source: lint.CABFEVGuidelines,
EffectiveDate: util.CABV170Date,
},
Lint: NewInvalidOrgIDRegistrationScheme,
})
}
type invalidOrgIDRegistrationScheme struct{}
func NewInvalidOrgIDRegistrationScheme() lint.LintInterface {
return &invalidOrgIDRegistrationScheme{}
}
func (l *invalidOrgIDRegistrationScheme) CheckApplies(c *x509.Certificate) bool {
return util.IsEV(c.PolicyIdentifiers) && util.IsSubscriberCert(c) && c.Subject.OrganizationIDs != nil
}
func (l *invalidOrgIDRegistrationScheme) Execute(c *x509.Certificate) *lint.LintResult {
if len(c.Subject.OrganizationIDs) == 0 {
return &lint.LintResult{Status: lint.Pass}
}
// Let's assume there is just one OrganizationID; if not so, it's not this lint's business to raise an alarm
orgId := c.Subject.OrganizationIDs[0]
runes := []rune(orgId)
if len(runes) < 3 {
return &lint.LintResult{
Status: lint.Error,
Details: "Invalid registration scheme in Subject.organizationIdentifier",
}
}
firstThreeRunes := runes[:3]
registrationScheme := string(firstThreeRunes)
if (registrationScheme != "NTR") && (registrationScheme != "VAT") && (registrationScheme != "PSD") {
return &lint.LintResult{
Status: lint.Error,
Details: fmt.Sprintf("Registration scheme '%s' in Subject.organizationIdentifier "+
"is not allowed in EV certificates", registrationScheme),
}
}
return &lint.LintResult{Status: lint.Pass}
}

View File

@ -15,7 +15,7 @@
package cabf_smime_br
import (
"fmt"
"errors"
"regexp"
"github.com/zmap/zcrypto/x509"
@ -99,7 +99,7 @@ func verifySMIMEOrganizationIdentifierContainsSubjectNameCountry(id string, coun
identifierCountry := submatches[2]
if identifierCountry != country {
return fmt.Errorf("the country code used in the Registration Scheme identifier SHALL match that of the subject:countryName")
return errors.New("the country code used in the Registration Scheme identifier SHALL match that of the subject:countryName")
}
return nil

View File

@ -91,7 +91,7 @@ func (l *mailboxValidatedEnforceSubjectFieldRestrictions) Execute(c *x509.Certif
if fieldName, knownField := l.forbiddenSubjectFields[oidStr]; knownField {
return &lint.LintResult{Status: lint.Error, Details: fmt.Sprintf("subject DN contains forbidden field: %s (%s)", fieldName, oidStr)}
}
return &lint.LintResult{Status: lint.Error, Details: fmt.Sprintf("subject DN contains forbidden field: %s", oidStr)}
return &lint.LintResult{Status: lint.Error, Details: "subject DN contains forbidden field: " + oidStr}
}
}
}

View File

@ -0,0 +1,59 @@
/*
* 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.
*/
package community
import (
"fmt"
"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_unique_revoked_certificate",
Description: "The CRL must not include duplicate serial numbers in its revoked certificates list.",
Source: lint.Community,
EffectiveDate: util.ZeroDate,
},
Lint: NewUniqueRevokedCertificate,
})
}
type uniqueRevokedCertificate struct{}
func NewUniqueRevokedCertificate() lint.RevocationListLintInterface {
return &uniqueRevokedCertificate{}
}
func (l *uniqueRevokedCertificate) CheckApplies(c *x509.RevocationList) bool {
return true
}
func (l *uniqueRevokedCertificate) Execute(c *x509.RevocationList) *lint.LintResult {
serials := make(map[string]bool)
for _, rc := range c.RevokedCertificates {
if serials[rc.SerialNumber.String()] {
return &lint.LintResult{
Status: lint.Warn,
Details: fmt.Sprintf("Revoked certificates list contains duplicate serial number: %x", rc.SerialNumber),
}
}
serials[rc.SerialNumber.String()] = true
}
return &lint.LintResult{Status: lint.Pass}
}

View File

@ -61,7 +61,7 @@ func (l *fermatFactorization) Execute(c *x509.Certificate) *lint.LintResult {
if err != nil {
return &lint.LintResult{
Status: lint.Error,
Details: fmt.Sprintf("this certificate's RSA key pair is susceptible to Fermat factorization, %s", err.Error())}
Details: "this certificate's RSA key pair is susceptible to Fermat factorization, " + err.Error()}
} else {
return &lint.LintResult{Status: lint.Pass}
}

View File

@ -0,0 +1,101 @@
/*
* 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.
*/
package community
import (
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
"fmt"
"reflect"
"regexp"
)
func init() {
lint.RegisterCertificateLint(&lint.CertificateLint{
LintMetadata: lint.LintMetadata{
Name: "e_subj_contains_html_entities",
Description: "Detects the presence of HTML entities (e.g. '&amp;') in the Subject, which probably shouldn't be there",
Source: lint.Community,
EffectiveDate: util.ZeroDate,
},
Lint: NewSubjectContainsHTMLEntities,
})
}
type subjectContainsHTMLEntities struct {
Skip bool `comment:"Set this to true to skip this lint"`
}
func NewSubjectContainsHTMLEntities() lint.LintInterface {
return &subjectContainsHTMLEntities{
Skip: false,
}
}
func (l *subjectContainsHTMLEntities) Configure() interface{} {
return l
}
func (l *subjectContainsHTMLEntities) CheckApplies(c *x509.Certificate) bool {
return true
}
var htmlEntitiesRegExp = regexp.MustCompile("&#?[a-zA-Z0-9]+;")
func containsHTMLEntities(s string) bool {
return htmlEntitiesRegExp.MatchString(s)
}
func (l *subjectContainsHTMLEntities) Execute(c *x509.Certificate) *lint.LintResult {
if l.Skip {
return &lint.LintResult{Status: lint.Pass}
}
targetFields := []string{
"GivenName",
"Surname",
"CommonNames",
"OrganizationalUnit",
"Organization",
"Locality",
"Province",
"StreetAddress",
"PostalCode",
"OrganizationIDs",
"JurisdictionLocality",
"JurisdictionProvince",
}
value := reflect.ValueOf(c.Subject)
for _, fieldName := range targetFields {
field := value.FieldByName(fieldName)
strSlice := field.Interface().([]string)
if len(strSlice) > 0 {
if containsHTMLEntities(strSlice[0]) {
return &lint.LintResult{
Status: lint.Error,
Details: fmt.Sprintf("Subject.%s contains an HTML entity", fieldName),
}
}
}
}
return &lint.LintResult{Status: lint.Pass}
}

View File

@ -0,0 +1,159 @@
/*
* 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.
*/
package community
import (
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
"fmt"
"reflect"
"strings"
)
func init() {
lint.RegisterCertificateLint(&lint.CertificateLint{
LintMetadata: lint.LintMetadata{
Name: "e_utf8_latin1_mixup",
Description: "Checks for wrongly encoded diacritics due to UTF-8 mistaken for Latin-1",
Citation: "See https://en.wikipedia.org/wiki/ISO/IEC_8859-1",
Source: lint.Community,
EffectiveDate: util.ZeroDate,
},
Lint: NewUTF8Latin1Mixup,
})
}
type UTF8Latin1Mixup struct{}
func NewUTF8Latin1Mixup() lint.LintInterface {
return &UTF8Latin1Mixup{}
}
func (l *UTF8Latin1Mixup) CheckApplies(c *x509.Certificate) bool {
return true
}
// Checks if the supplied string contains any wrongly encoded diacritics
// due to mistaking their correct UTF-8 encoding for Latin-1 code points
func containsUtf8Latin1Mixup(s string) bool {
// This table does not cover 100% of all possible miscodings, but it avoids false positives.
// The correct diacritic that each entry relates to is shown in the entry's trailing comment.
miscodedDiacritics := []string{
"À", // "Â", // Â
"Ã", // Ã
"Ä", // Ä
"Ã…", // Å
"Æ", // Æ
"Ç", // Ç
"È", // È
"É", // É
"Ê", // Ê
"Ë", // Ë
"ÃŒ", // Ì
"ÃŽ", // Î
"Ñ", // Ñ
"Ã’", // Ò
"Ó", // Ó
"Ô", // Ô
"Õ", // Õ
"Ö", // Ö
"×", // ×
"Ø", // Ø
"Ù", // Ù
"Ú", // Ú
"Û", // Û
"Ü", // Ü
"Þ", // Þ
"ß", // ß
"á", // á
"â", // â
"ã", // ã
"ä", // ä
"Ã¥", // å
"æ", // æ
"ç", // ç
"è", // è
"é", // é
"ê", // ê
"ë", // ë
"ì", // ì
"î", // î
"ï", // ï
"ð", // ð
"ñ", // ñ
"ò", // ò
"ó", // ó
"ô", // ô
"õ", // õ
"ö", // ö
"÷", // ÷
"ø", // ø
"ù", // ù
"ú", // ú
"û", // û
"ü", // ü
"ý", // ý
"þ", // þ
"ÿ", // ÿ
}
for _, mixup := range miscodedDiacritics {
if strings.Contains(s, mixup) {
return true
}
}
return false
}
func (l *UTF8Latin1Mixup) Execute(c *x509.Certificate) *lint.LintResult {
targetFields := []string{
"GivenName",
"Surname",
"CommonNames",
"OrganizationalUnit",
"Organization",
"Locality",
"Province",
"StreetAddress",
"PostalCode",
"OrganizationIDs",
"JurisdictionLocality",
"JurisdictionProvince",
}
value := reflect.ValueOf(c.Subject)
for _, fieldName := range targetFields {
field := value.FieldByName(fieldName)
strSlice := field.Interface().([]string)
if len(strSlice) > 0 {
if containsUtf8Latin1Mixup(strSlice[0]) {
return &lint.LintResult{
Status: lint.Error,
Details: fmt.Sprintf("Subject.%s contains wrongly encoded diacritics (UTF-8 mistaken for Latin-1)",
fieldName),
}
}
}
}
return &lint.LintResult{Status: lint.Pass}
}

View File

@ -0,0 +1,89 @@
/*
* ZLint Copyright 2025 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 etsi
import (
"github.com/zmap/zcrypto/encoding/asn1"
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
)
type qcStatemQctypeSmime struct{}
func init() {
lint.RegisterCertificateLint(&lint.CertificateLint{
LintMetadata: lint.LintMetadata{
Name: "e_qcstatem_qctype_smime",
Description: "Checks that a QC Statement of the type Id-etsi-qcs-QcType features at least one of the types IdEtsiQcsQctEsign or IdEtsiQcsQctEseal, in case of an S/MIME certificate.",
Citation: "ETSI EN 319 412 - 5 V2.2.1 (2017 - 11) / Section 4.2.3",
Source: lint.EtsiEsi,
EffectiveDate: util.EtsiEn319_412_5_V2_2_1_Date,
},
Lint: NewQcStatemQctypeSmime,
})
}
func NewQcStatemQctypeSmime() lint.LintInterface {
return &qcStatemQctypeSmime{}
}
func (this *qcStatemQctypeSmime) getStatementOid() *asn1.ObjectIdentifier {
return &util.IdEtsiQcsQcType
}
func (l *qcStatemQctypeSmime) CheckApplies(c *x509.Certificate) bool {
if !util.IsExtInCert(c, util.QcStateOid) {
return false
}
if util.ParseQcStatem(util.GetExtFromCert(c, util.QcStateOid).Value, *l.getStatementOid()).IsPresent() {
return util.IsSMIMEBRCertificate(c)
}
return false
}
func (l *qcStatemQctypeSmime) Execute(c *x509.Certificate) *lint.LintResult {
errString := ""
ext := util.GetExtFromCert(c, util.QcStateOid)
s := util.ParseQcStatem(ext.Value, *l.getStatementOid())
errString += s.GetErrorInfo()
if len(errString) != 0 {
return &lint.LintResult{Status: lint.Error, Details: errString}
}
qcType := s.(util.Etsi423QcType)
if len(qcType.TypeOids) == 0 {
errString += "no QcType present, sequence of OIDs is empty"
}
found := false
for _, t := range qcType.TypeOids {
if t.Equal(util.IdEtsiQcsQctEseal) || t.Equal(util.IdEtsiQcsQctEsign) {
found = true
}
}
if !found {
errString += "etsi Type does not indicate certificate as a 'eSeal' or 'eSign' certificate"
}
if len(errString) == 0 {
return &lint.LintResult{Status: lint.Pass}
} else {
return &lint.LintResult{Status: lint.Error, Details: errString}
}
}

View File

@ -1,5 +1,5 @@
/*
* ZLint Copyright 2024 Regents of the University of Michigan
* ZLint Copyright 2025 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
@ -15,8 +15,6 @@
package etsi
import (
"fmt"
"github.com/zmap/zcrypto/encoding/asn1"
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
@ -28,7 +26,7 @@ type qcStatemQctypeWeb struct{}
func init() {
lint.RegisterCertificateLint(&lint.CertificateLint{
LintMetadata: lint.LintMetadata{
Name: "w_qcstatem_qctype_web",
Name: "e_qcstatem_qctype_web",
Description: "Checks that a QC Statement of the type Id-etsi-qcs-QcType features at least the type IdEtsiQcsQctWeb",
Citation: "ETSI EN 319 412 - 5 V2.2.1 (2017 - 11) / Section 4.2.3",
Source: lint.EtsiEsi,
@ -51,7 +49,7 @@ func (l *qcStatemQctypeWeb) CheckApplies(c *x509.Certificate) bool {
return false
}
if util.ParseQcStatem(util.GetExtFromCert(c, util.QcStateOid).Value, *l.getStatementOid()).IsPresent() {
return true
return util.IsServerAuthCert(c)
}
return false
}
@ -59,33 +57,31 @@ func (l *qcStatemQctypeWeb) CheckApplies(c *x509.Certificate) bool {
func (l *qcStatemQctypeWeb) Execute(c *x509.Certificate) *lint.LintResult {
errString := ""
wrnString := ""
ext := util.GetExtFromCert(c, util.QcStateOid)
s := util.ParseQcStatem(ext.Value, *l.getStatementOid())
errString += s.GetErrorInfo()
if len(errString) == 0 {
qcType := s.(util.Etsi423QcType)
if len(qcType.TypeOids) == 0 {
errString += "no QcType present, sequence of OIDs is empty"
}
found := false
for _, t := range qcType.TypeOids {
if t.Equal(util.IdEtsiQcsQctWeb) {
found = true
}
}
if !found {
wrnString += fmt.Sprintf("etsi Type does not indicate certificate as a 'web' certificate")
if len(errString) != 0 {
return &lint.LintResult{Status: lint.Error, Details: errString}
}
qcType := s.(util.Etsi423QcType)
if len(qcType.TypeOids) == 0 {
errString += "no QcType present, sequence of OIDs is empty"
}
found := false
for _, t := range qcType.TypeOids {
if t.Equal(util.IdEtsiQcsQctWeb) {
found = true
}
}
if !found {
errString += "etsi Type does not indicate certificate as a 'web' certificate"
}
if len(errString) == 0 {
if len(wrnString) == 0 {
return &lint.LintResult{Status: lint.Pass}
} else {
return &lint.LintResult{Status: lint.Warn, Details: wrnString}
}
return &lint.LintResult{Status: lint.Pass}
} else {
return &lint.LintResult{Status: lint.Error, Details: errString}
}

View File

@ -86,5 +86,5 @@ func (l *ecdsaPubKeyAidEncoding) Execute(c *x509.Certificate) *lint.LintResult {
}
}
return &lint.LintResult{Status: lint.Error, Details: fmt.Sprintf("Wrong encoding of ECC public key. Got the unsupported %s", hex.EncodeToString(encodedPublicKeyAid))}
return &lint.LintResult{Status: lint.Error, Details: "Wrong encoding of ECC public key. Got the unsupported " + hex.EncodeToString(encodedPublicKeyAid)}
}

View File

@ -103,7 +103,7 @@ func (l *ecdsaSignatureAidEncoding) Execute(c *x509.Certificate) *lint.LintResul
}
return &lint.LintResult{
Status: lint.Error,
Details: fmt.Sprintf("Encoding of signature algorithm does not match signing key on P-256 curve. Got the unsupported %s", hex.EncodeToString(encoded)),
Details: "Encoding of signature algorithm does not match signing key on P-256 curve. Got the unsupported " + hex.EncodeToString(encoded),
}
} else if signatureSize <= maxP384SigByteLen {
expectedEncoding := []byte{0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03}
@ -113,7 +113,7 @@ func (l *ecdsaSignatureAidEncoding) Execute(c *x509.Certificate) *lint.LintResul
}
return &lint.LintResult{
Status: lint.Error,
Details: fmt.Sprintf("Encoding of signature algorithm does not match signing key on P-384 curve. Got the unsupported %s", hex.EncodeToString(encoded)),
Details: "Encoding of signature algorithm does not match signing key on P-384 curve. Got the unsupported " + hex.EncodeToString(encoded),
}
}
return &lint.LintResult{

View File

@ -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 <adriano.santoni@staff.aruba.it>
* 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."}
}

View File

@ -15,7 +15,6 @@
package rfc
import (
"fmt"
"sort"
"strings"
@ -89,7 +88,7 @@ func (l *ecdsaAllowedKU) Execute(c *x509.Certificate) *lint.LintResult {
sort.Strings(invalidKUs)
return &lint.LintResult{
Status: lint.Error,
Details: fmt.Sprintf("Certificate contains invalid key usage(s): %s", strings.Join(invalidKUs, ", ")),
Details: "Certificate contains invalid key usage(s): " + strings.Join(invalidKUs, ", "),
}
}

View File

@ -15,7 +15,6 @@
package rfc
import (
"fmt"
"sort"
"strings"
@ -90,9 +89,8 @@ func (l *ecdsaInvalidKU) Execute(c *x509.Certificate) *lint.LintResult {
sort.Strings(invalidKUs)
return &lint.LintResult{
Status: lint.Notice,
Details: fmt.Sprintf(
"Certificate had unexpected key usage(s): %s",
strings.Join(invalidKUs, ", ")),
Details: "Certificate had unexpected key usage(s): " +
strings.Join(invalidKUs, ", "),
}
}

View File

@ -15,7 +15,6 @@ package rfc
*/
import (
"fmt"
"strings"
"github.com/zmap/zcrypto/x509"
@ -82,9 +81,7 @@ func (l *extDuplicateExtension) Execute(cert *x509.Certificate) *lint.LintResult
}
return &lint.LintResult{
Status: lint.Error,
Details: fmt.Sprintf(
"The following extensions are duplicated: %s",
strings.Join(duplicateOIDsList, ", ")),
Status: lint.Error,
Details: "The following extensions are duplicated: " + strings.Join(duplicateOIDsList, ", "),
}
}

View File

@ -0,0 +1,60 @@
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 (
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
"golang.org/x/crypto/ocsp"
)
type OCSPThisUpdateNotAfterProducedAt struct{}
/*
RFC 6960: 2.4
thisUpdate The most recent time at which the status being
indicated is known by the responder to have been
correct.
producedAt The time at which the OCSP responder signed this
response.
*/
func init() {
lint.RegisterOcspResponseLint(&lint.OcspResponseLint{
LintMetadata: lint.LintMetadata{
Name: "e_this_update_not_after_produced_at",
Description: "The value of thisUpdate MUST be prior to the time at which the response is produced, i.e., the value of producedAt",
Source: lint.RFC6960,
Citation: "RFC 6960: 2.4",
EffectiveDate: util.RFC6960Date,
},
Lint: NewOCSPThisUpdateNotAfterProducedAt,
})
}
func NewOCSPThisUpdateNotAfterProducedAt() lint.OcspResponseLintInterface {
return OCSPThisUpdateNotAfterProducedAt{}
}
func (l OCSPThisUpdateNotAfterProducedAt) CheckApplies(c *ocsp.Response) bool {
return true
}
func (l OCSPThisUpdateNotAfterProducedAt) Execute(c *ocsp.Response) *lint.LintResult {
if c.ThisUpdate.After(c.ProducedAt) {
return &lint.LintResult{Status: lint.Error}
}
return &lint.LintResult{Status: lint.Pass}
}

View File

@ -15,7 +15,6 @@
package rfc
import (
"fmt"
"sort"
"strings"
@ -88,7 +87,7 @@ func (l *rsaAllowedKUCa) Execute(c *x509.Certificate) *lint.LintResult {
sort.Strings(invalidKUs)
return &lint.LintResult{
Status: lint.Error,
Details: fmt.Sprintf("CA certificate with an RSA key contains invalid key usage(s): %s", strings.Join(invalidKUs, ", ")),
Details: "CA certificate with an RSA key contains invalid key usage(s): " + strings.Join(invalidKUs, ", "),
}
}

View File

@ -15,7 +15,6 @@
package rfc
import (
"fmt"
"sort"
"strings"
@ -86,7 +85,7 @@ func (l *rsaAllowedKUEe) Execute(c *x509.Certificate) *lint.LintResult {
sort.Strings(invalidKUs)
return &lint.LintResult{
Status: lint.Error,
Details: fmt.Sprintf("Subscriber certificate with an RSA key contains invalid key usage(s): %s", strings.Join(invalidKUs, ", ")),
Details: "Subscriber certificate with an RSA key contains invalid key usage(s): " + strings.Join(invalidKUs, ", "),
}
}

View File

@ -61,7 +61,7 @@ func (l *rsaSPKIEncryptionParamNotNULL) Execute(c *x509.Certificate) *lint.LintR
}
if err := util.CheckAlgorithmIDParamNotNULL(encodedPublicKeyAid, util.OidRSAEncryption); err != nil {
return &lint.LintResult{Status: lint.Error, Details: fmt.Sprintf("certificate pkixPublicKey %s", err.Error())}
return &lint.LintResult{Status: lint.Error, Details: "certificate pkixPublicKey " + err.Error()}
}
return &lint.LintResult{Status: lint.Pass}

View File

@ -15,8 +15,6 @@ package rfc
*/
import (
"fmt"
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
@ -77,7 +75,7 @@ func (l *rsaTBSSignatureEncryptionParamNotNULL) Execute(c *x509.Certificate) *li
}
if err := util.CheckAlgorithmIDParamNotNULL(signatureAlgoID, c.SignatureAlgorithmOID); err != nil {
return &lint.LintResult{Status: lint.Error, Details: fmt.Sprintf("certificate tbsCertificate.signature %s", err.Error())}
return &lint.LintResult{Status: lint.Error, Details: "certificate tbsCertificate.signature " + err.Error()}
}
return &lint.LintResult{Status: lint.Pass}

View File

@ -1,12 +1,12 @@
#!/usr/bin/env bash
function usage() {
echo "./newLint.sh [-h|--help] -r|--req <REQUIREMENT> -f|--file <FILENAME> -s|--struct <STRUCTNAME>"
echo "./newLint.sh [-h|--help] -r|--req <REQUIREMENT> -n|--name <LINTNAME> -s|--struct <STRUCTNAME>"
echo ""
echo "Options:"
echo " -h|--help Prints this help text."
echo " -r|--req The name of the requirements body governing this lint. Valid options are $(valid_requirement_names)."
echo " -f|--file The target filename for the given lint (no file extension is required)."
echo " -n|--name The lintname for the given lints."
echo " -s|--struct The name of the Golang struct to create."
echo ""
echo "Example:"
@ -45,10 +45,8 @@ while [[ $# -gt 0 ]]; do
REQUIREMENT="${2}"
shift 2
;;
-f | --file)
-n| --name)
LINTNAME="${2}"
FILENAME="lint_${LINTNAME}.go"
TEST_FILENAME="lint_${LINTNAME}_test.go"
shift 2
;;
-s | --struct)
@ -67,6 +65,15 @@ while [[ $# -gt 0 ]]; do
esac
done
if [[ $LINTNAME =~ ^[enw]_ ]]; then
FILENAME="lint_${LINTNAME:2}.go"
TEST_FILENAME="lint_${LINTNAME:2}_test.go"
else
echo "The lintname should start with e_, w_, n_"
usage
exit 1
fi
if [ -z "${REQUIREMENT}" ]; then
echo "The -r|--req flag is required. Valid options are $(valid_requirement_names)"
usage
@ -74,13 +81,13 @@ if [ -z "${REQUIREMENT}" ]; then
fi
if [ -z "${LINTNAME}" ]; then
echo "The -f|--file flag is required."
echo "The -n|--name flag is required."
usage
exit 1
fi
if [ -z "${STRUCTNAME}" ]; then
echo "The -s|--strut flag is required."
echo "The -s|--struct flag is required."
usage
exit 1
fi
@ -89,12 +96,12 @@ PATHNAME="$(git_root)/v3/lints/${REQUIREMENT}/${FILENAME}"
TEST_PATHNAME="$(git_root)/v3/lints/${REQUIREMENT}/${TEST_FILENAME}"
sed -e "s/PACKAGE/${REQUIREMENT}/" \
-e "s/PASCAL_CASE_SUBST/${STRUCTNAME^}/g" \
-e "s/PASCAL_CASE_SUBST/${STRUCTNAME}/g" \
-e "s/SUBST/${STRUCTNAME}/g" \
-e "s/SUBTEST/${LINTNAME}/g" "$(git_root)/v3/template" > "${PATHNAME}"
sed -e "s/PACKAGE/${REQUIREMENT}/" \
-e "s/PASCAL_CASE_SUBST/${STRUCTNAME^}/g" \
-e "s/PASCAL_CASE_SUBST/${STRUCTNAME}/g" \
-e "s/SUBST/${STRUCTNAME}/g" \
-e "s/SUBTEST/${LINTNAME}/g" "$(git_root)/v3/test_template" > "${TEST_PATHNAME}"

View File

@ -17,6 +17,7 @@ package zlint
import (
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"golang.org/x/crypto/ocsp"
)
// ResultSet contains the output of running all lints in a registry against
@ -59,6 +60,20 @@ func (z *ResultSet) executeRevocationList(o *x509.RevocationList, registry lint.
}
}
// Execute lints on the given OCSP response with all of the lints in the provided
// registry. The ResultSet is mutated to trace the lint results obtained from
// linting the OCSP response.
func (z *ResultSet) executeOcspResponse(o *ocsp.Response, registry lint.Registry) {
z.Results = make(map[string]*lint.LintResult, len(registry.Names()))
// Run each lints from the registry.
for _, lint := range registry.OcspResponseLints().Lints() {
res := lint.Execute(o, registry.GetConfiguration())
res.LintMetadata = lint.LintMetadata
z.Results[lint.Name] = res
z.updateErrorStatePresent(res)
}
}
func (z *ResultSet) updateErrorStatePresent(result *lint.LintResult) {
switch result.Status {
case lint.Notice:

View File

@ -3426,7 +3426,7 @@ var tldMap = map[string]GTLDPeriod{
"kerrylogistics": {
GTLD: "kerrylogistics",
DelegationDate: "2016-03-05",
RemovalDate: "",
RemovalDate: "2025-02-27",
},
"kerryproperties": {
GTLD: "kerryproperties",
@ -3776,7 +3776,7 @@ var tldMap = map[string]GTLDPeriod{
"lipsy": {
GTLD: "lipsy",
DelegationDate: "2016-05-03",
RemovalDate: "",
RemovalDate: "2025-02-27",
},
"live": {
GTLD: "live",

View File

@ -17,7 +17,6 @@
package util
import (
"fmt"
"net"
)
@ -120,7 +119,7 @@ func init() {
var err error
if _, ipNet, err = net.ParseCIDR(network); err != nil {
panic(fmt.Sprintf("unexpected internal network value provided: %s", err.Error()))
panic("unexpected internal network value provided: " + err.Error())
}
reservedNetworks = append(reservedNetworks, ipNet)
}

View File

@ -32,6 +32,7 @@ var (
CertPolicyOID = asn1.ObjectIdentifier{2, 5, 29, 32} // Certificate Policies
CrlDistOID = asn1.ObjectIdentifier{2, 5, 29, 31} // CRL Distribution Points
CtPoisonOID = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 3} // CT Poison
DeltaCRLIndicatorOID = asn1.ObjectIdentifier{2, 5, 29, 27} // Delta CRL Indicator
EkuSynOid = asn1.ObjectIdentifier{2, 5, 29, 37} // Extended Key Usage Syntax
FreshCRLOID = asn1.ObjectIdentifier{2, 5, 29, 46} // Freshest CRL
InhibitAnyPolicyOID = asn1.ObjectIdentifier{2, 5, 29, 54} // Inhibit Any Policy

View File

@ -37,6 +37,7 @@ var (
RFC4630Date = time.Date(2006, time.August, 1, 0, 0, 0, 0, time.UTC)
RFC5280Date = time.Date(2008, time.May, 1, 0, 0, 0, 0, time.UTC)
RFC6818Date = time.Date(2013, time.January, 1, 0, 0, 0, 0, time.UTC)
RFC6960Date = time.Date(2013, time.June, 1, 0, 0, 0, 0, time.UTC)
RFC6962Date = time.Date(2013, time.June, 1, 0, 0, 0, 0, time.UTC)
RFC8813Date = time.Date(2020, time.August, 1, 0, 0, 0, 0, time.UTC)
CABEffectiveDate = time.Date(2012, time.July, 1, 0, 0, 0, 0, time.UTC)
@ -76,8 +77,17 @@ var (
CABFBRs_1_7_9_Date = time.Date(2021, time.August, 16, 0, 0, 0, 0, time.UTC)
CABFBRs_1_8_0_Date = time.Date(2021, time.August, 25, 0, 0, 0, 0, time.UTC)
CABFBRs_2_0_0_Date = time.Date(2023, time.September, 15, 0, 0, 0, 0, time.UTC)
CABFBRs_2_0_1_Date = time.Date(2024, time.March, 15, 0, 0, 0, 0, time.UTC)
CABFBRs_2_0_2_Date = time.Date(2024, time.January, 8, 0, 0, 0, 0, time.UTC)
CABFBRs_2_0_3_Date = time.Date(2024, time.April, 15, 0, 0, 0, 0, time.UTC)
CABFBRs_2_0_4_Date = time.Date(2024, time.May, 15, 0, 0, 0, 0, time.UTC)
CABFBRs_2_0_5_Date = time.Date(2024, time.July, 1, 0, 0, 0, 0, time.UTC)
CABFBRs_2_0_6_Date = time.Date(2024, time.August, 6, 0, 0, 0, 0, time.UTC)
CABFBRs_2_0_7_Date = time.Date(2024, time.September, 6, 0, 0, 0, 0, time.UTC)
CABFBRs_2_0_8_Date = time.Date(2024, time.October, 2, 0, 0, 0, 0, time.UTC)
NoReservedDomainLabelsDate = time.Date(2021, time.October, 1, 0, 0, 0, 0, time.UTC)
CABFBRs_OU_Prohibited_Date = time.Date(2022, time.September, 1, 0, 0, 0, 0, time.UTC)
SC16EffectiveDate = time.Date(2019, time.April, 16, 0, 0, 0, 0, time.UTC)
SC17EffectiveDate = time.Date(2019, time.June, 21, 0, 0, 0, 0, time.UTC)
CABF_SMIME_BRs_1_0_0_Date = time.Date(2023, time.September, 1, 0, 0, 0, 0, time.UTC)
// Enforcement date of CRL reason codes from Ballot SC 061

View File

@ -30,6 +30,7 @@ import (
_ "github.com/zmap/zlint/v3/lints/etsi"
_ "github.com/zmap/zlint/v3/lints/mozilla"
_ "github.com/zmap/zlint/v3/lints/rfc"
"golang.org/x/crypto/ocsp"
)
const Version int64 = 3
@ -90,3 +91,31 @@ func LintRevocationListEx(r *x509.RevocationList, registry lint.Registry) *Resul
res.Timestamp = time.Now().Unix()
return res
}
// LintOcspResponse runs all registered lints on o using default options,
// producing a ResultSet.
//
// Using LintOcspResponse(o) is equivalent to calling LintOcspResponseEx(o, nil).
func LintOcspResponse(o *ocsp.Response) *ResultSet {
return LintOcspResponseEx(o, nil)
}
// LintOcspResponseEx runs lints from the provided registry on o producing
// a ResultSet. Providing an explicit registry allows the caller to filter the
// lints that will be run. (See lint.Registry.Filter())
//
// If registry is nil then the global registry of all lints is used and this
// function is equivalent to calling LintOcspResponse(o).
func LintOcspResponseEx(o *ocsp.Response, registry lint.Registry) *ResultSet {
if o == nil {
return nil
}
if registry == nil {
registry = lint.GlobalRegistry()
}
res := new(ResultSet)
res.executeOcspResponse(o, registry)
res.Version = Version
res.Timestamp = time.Now().Unix()
return res
}

6
vendor/modules.txt vendored
View File

@ -281,7 +281,7 @@ github.com/titanous/rocacheck
# github.com/weppos/publicsuffix-go v0.40.3-0.20250307081557-c05521c3453a
## explicit; go 1.16
github.com/weppos/publicsuffix-go/publicsuffix
# github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c
# github.com/zmap/zcrypto v0.0.0-20250129210703-03c45d0bae98
## explicit; go 1.16
github.com/zmap/zcrypto/cryptobyte
github.com/zmap/zcrypto/cryptobyte/asn1
@ -293,8 +293,8 @@ github.com/zmap/zcrypto/util
github.com/zmap/zcrypto/x509
github.com/zmap/zcrypto/x509/ct
github.com/zmap/zcrypto/x509/pkix
# github.com/zmap/zlint/v3 v3.6.4
## explicit; go 1.18
# github.com/zmap/zlint/v3 v3.6.6
## explicit; go 1.23.0
github.com/zmap/zlint/v3
github.com/zmap/zlint/v3/lint
github.com/zmap/zlint/v3/lints/apple