Skip to content

Commit cfdee22

Browse files
committed
certcheck: check self-signature on roots
1 parent 8de9966 commit cfdee22

File tree

1 file changed

+32
-5
lines changed

1 file changed

+32
-5
lines changed

x509util/certcheck/certcheck.go

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ var (
3636
useSystemRoots = flag.Bool("system_roots", false, "Use system roots")
3737
verbose = flag.Bool("verbose", false, "Verbose output")
3838
strict = flag.Bool("strict", true, "Set non-zero exit code for non-fatal errors in parsing")
39-
validate = flag.Bool("validate", false, "Validate certificate signatures")
39+
validate = flag.Bool("validate", false, "Validate certificate signatures (leaf to root)")
4040
checkTime = flag.Bool("check_time", false, "Check current validity of certificate")
4141
checkName = flag.Bool("check_name", true, "Check certificate name validity")
4242
checkEKU = flag.Bool("check_eku", true, "Check EKU nesting validity")
@@ -46,7 +46,7 @@ var (
4646
checkRevoked = flag.Bool("check_revocation", false, "Check revocation status of certificate")
4747
)
4848

49-
func addCerts(filename string, pool *x509.CertPool) {
49+
func addCerts(filename string, pool *x509.CertPool, validateSelfSigned bool) {
5050
if filename != "" {
5151
dataList, err := x509util.ReadPossiblePEMFile(filename, "CERTIFICATE")
5252
if err != nil {
@@ -58,6 +58,12 @@ func addCerts(filename string, pool *x509.CertPool) {
5858
glog.Exitf("Failed to parse certificate from %s: %v", filename, err)
5959
}
6060
for _, cert := range certs {
61+
if validateSelfSigned {
62+
err := cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature)
63+
if err != nil {
64+
glog.Exitf("Failed to verify self-signature on root cert from %s: %v", filename, err)
65+
}
66+
}
6167
pool.AddCert(cert)
6268
}
6369
}
@@ -105,6 +111,7 @@ func main() {
105111
}
106112
if *validate && len(chain) > 0 {
107113
opts := x509.VerifyOptions{
114+
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
108115
DisableTimeChecks: !*checkTime,
109116
DisableCriticalExtensionChecks: !*checkUnknownCriticalExts,
110117
DisableNameChecks: !*checkName,
@@ -220,11 +227,10 @@ func validateChain(chain []*x509.Certificate, opts x509.VerifyOptions, rootsFile
220227
}
221228
roots = systemRoots
222229
}
223-
opts.KeyUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageAny}
224230
opts.Roots = roots
225231
opts.Intermediates = x509.NewCertPool()
226-
addCerts(rootsFile, opts.Roots)
227-
addCerts(intermediatesFile, opts.Intermediates)
232+
addCerts(rootsFile, opts.Roots /* validate_self_signed= */, true)
233+
addCerts(intermediatesFile, opts.Intermediates /* validate_self_signed= */, false)
228234

229235
if !useSystemRoots && len(rootsFile) == 0 {
230236
// No root CA certs provided, so assume the chain is self-contained.
@@ -241,6 +247,27 @@ func validateChain(chain []*x509.Certificate, opts x509.VerifyOptions, rootsFile
241247
opts.Intermediates.AddCert(chain[i])
242248
}
243249
}
250+
251+
for i, cert := range chain {
252+
var msg string
253+
var signer *x509.Certificate
254+
if i == len(chain)-1 {
255+
signer = cert
256+
msg = "self-signature"
257+
} else {
258+
signer = chain[i+1]
259+
msg = fmt.Sprintf("signature from cert [%d]", i+1)
260+
}
261+
262+
err := signer.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature)
263+
if err != nil {
264+
glog.Exitf("Failed to verify %s on certificate [%d]: %v", msg, i, err)
265+
} else if *verbose {
266+
fmt.Printf("Certificate [%d] with subject %q has valid %s\n", i, cert.Subject, msg)
267+
}
268+
}
269+
270+
// Also do full x509 verification according to the options.
244271
_, err := chain[0].Verify(opts)
245272
return err
246273
}

0 commit comments

Comments
 (0)