func chainValidation(addr, hostname string) (grade Grade, output Output, err error) { chain, err := getChain(addr, defaultTLSConfig(hostname)) if err != nil { return } var warnings []string for i := 0; i < len(chain)-1; i++ { cert, parent := chain[i], chain[i+1] valid := helpers.ValidExpiry(cert) if !valid { warnings = append(warnings, fmt.Sprintf("Certificate for %s is valid for too long", cert.Subject.CommonName)) } revoked, ok := revoke.VerifyCertificate(cert) if !ok { warnings = append(warnings, fmt.Sprintf("couldn't check if %s is revoked", cert.Subject.CommonName)) } if revoked { err = fmt.Errorf("%s is revoked", cert.Subject.CommonName) return } if !parent.IsCA { err = fmt.Errorf("%s is not a CA", parent.Subject.CommonName) return } if !bytes.Equal(cert.AuthorityKeyId, parent.SubjectKeyId) { err = fmt.Errorf("%s AuthorityKeyId differs from %s SubjectKeyId", cert.Subject.CommonName, parent.Subject.CommonName) return } if err = cert.CheckSignatureFrom(parent); err != nil { return } switch cert.SignatureAlgorithm { case x509.ECDSAWithSHA1: warnings = append(warnings, fmt.Sprintf("%s is signed by ECDSAWithSHA1", cert.Subject.CommonName)) case x509.SHA1WithRSA: warnings = append(warnings, fmt.Sprintf("%s is signed by RSAWithSHA1", cert.Subject.CommonName)) } } if len(warnings) == 0 { grade = Good } else { grade = Warning output = warnings } return }
// worker does all the parsing and validation of the certificate(s) // contained in a single file. It first reads all the data in the // file, then begins parsing certificates in the file. Those // certificates are then checked for revocation. func worker(paths chan string, bundler chan *x509.Certificate, pool *sync.WaitGroup) { defer (*pool).Done() for { path, ok := <-paths if !ok { return } log.Infof("Loading %s", path) fileData, err := ioutil.ReadFile(path) if err != nil { log.Warningf("%v", err) continue } for { var block *pem.Block if len(fileData) == 0 { break } block, fileData = pem.Decode(fileData) if block == nil { log.Warningf("%s: no PEM data found", path) break } else if block.Type != "CERTIFICATE" { log.Info("Skipping non-certificate") continue } cert, err := x509.ParseCertificate(block.Bytes) if err != nil { log.Warningf("Invalid certificate: %v", err) continue } log.Infof("Validating %+v", cert.Subject) revoked, ok := revoke.VerifyCertificate(cert) if !ok { log.Warning("Failed to verify certificate.") } else if !revoked { bundler <- cert } else { log.Info("Skipping revoked certificate") } } } }