@@ -13,6 +13,7 @@ import (
1313 "github.com/zmap/zlint/v3"
1414 "github.com/zmap/zlint/v3/lint"
1515
16+ "github.com/letsencrypt/boulder/core"
1617 "github.com/letsencrypt/boulder/crl/crl_x509"
1718
1819 _ "github.com/letsencrypt/boulder/linter/lints/cabf_br"
@@ -25,15 +26,18 @@ var ErrLinting = fmt.Errorf("failed lint(s)")
2526
2627// Check accomplishes the entire process of linting: it generates a throwaway
2728// signing key, uses that to create a throwaway cert, and runs a default set
28- // of lints (everything except for the ETSI and EV lints) against it. This is
29+ // of lints (everything except for the ETSI and EV lints) against it. If the
30+ // subjectPubKey and realSigner indicate that this is a self-signed cert, the
31+ // throwaway cert will have its pubkey replaced to also be self-signed. This is
2932// the primary public interface of this package, but it can be inefficient;
3033// creating a new signer and a new lint registry are expensive operations which
31- // performance-sensitive clients may want to cache.
34+ // performance-sensitive clients may want to cache via linter.New() .
3235func Check (tbs * x509.Certificate , subjectPubKey crypto.PublicKey , realIssuer * x509.Certificate , realSigner crypto.Signer , skipLints []string ) error {
3336 linter , err := New (realIssuer , realSigner , skipLints )
3437 if err != nil {
3538 return err
3639 }
40+
3741 _ , err = linter .Check (tbs , subjectPubKey )
3842 return err
3943}
@@ -52,9 +56,10 @@ func CheckCRL(tbs *crl_x509.RevocationList, realIssuer *x509.Certificate, realSi
5256// public key matches the throwaway private key, and then running the resulting
5357// throwaway certificate through a registry of zlint lints.
5458type Linter struct {
55- issuer * x509.Certificate
56- signer crypto.Signer
57- registry lint.Registry
59+ issuer * x509.Certificate
60+ signer crypto.Signer
61+ registry lint.Registry
62+ realPubKey crypto.PublicKey
5863}
5964
6065// New constructs a Linter. It uses the provided real certificate and signer
@@ -75,23 +80,37 @@ func New(realIssuer *x509.Certificate, realSigner crypto.Signer, skipLints []str
7580 if err != nil {
7681 return nil , err
7782 }
78- return & Linter {lintIssuer , lintSigner , reg }, nil
83+ return & Linter {lintIssuer , lintSigner , reg , realSigner . Public () }, nil
7984}
8085
8186// Check signs the given TBS certificate using the Linter's fake issuer cert and
8287// private key, then runs the resulting certificate through all non-filtered
83- // lints. It returns an error if any lint fails. On success it also returns the
84- // DER bytes of the linting certificate.
88+ // lints. If the subjectPubKey is identical to the public key of the real signer
89+ // used to create this linter, then the throwaway cert will have its pubkey
90+ // replaced with the linter's pubkey so that it appears self-signed. It returns
91+ // an error if any lint fails. On success it also returns the DER bytes of the
92+ // linting certificate.
8593func (l Linter ) Check (tbs * x509.Certificate , subjectPubKey crypto.PublicKey ) ([]byte , error ) {
86- lintCertBytes , cert , err := makeLintCert (tbs , subjectPubKey , l .issuer , l .signer )
94+ lintPubKey := subjectPubKey
95+ selfSigned , err := core .PublicKeysEqual (subjectPubKey , l .realPubKey )
96+ if err != nil {
97+ return nil , err
98+ }
99+ if selfSigned {
100+ lintPubKey = l .signer .Public ()
101+ }
102+
103+ lintCertBytes , cert , err := makeLintCert (tbs , lintPubKey , l .issuer , l .signer )
87104 if err != nil {
88105 return nil , err
89106 }
107+
90108 lintRes := zlint .LintCertificateEx (cert , l .registry )
91109 err = ProcessResultSet (lintRes )
92110 if err != nil {
93111 return nil , err
94112 }
113+
95114 return lintCertBytes , nil
96115}
97116
0 commit comments