mirror of
https://github.com/google/go-attestation.git
synced 2024-12-22 14:22:28 +00:00
145 lines
3.7 KiB
Go
145 lines
3.7 KiB
Go
package verifier
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/google/certificate-transparency-go/x509"
|
|
|
|
pb "github.com/google/go-attestation/verifier/proto"
|
|
)
|
|
|
|
// EKVerifier verifies x509 EK certificates based on a pool of allowed
|
|
// parent certificates.
|
|
type EKVerifier struct {
|
|
roots, intermediates *x509.CertPool
|
|
}
|
|
|
|
// VerifyEKCert verifies the properties and provenance of a given EK certificate.
|
|
func (v *EKVerifier) VerifyEKCert(certBytes []byte) (*pb.EkcertVerificationResults, error) {
|
|
c, err := x509.ParseCertificate(certBytes)
|
|
c.UnhandledCriticalExtensions = nil
|
|
if err != nil && x509.IsFatal(err) {
|
|
return nil, err
|
|
}
|
|
|
|
chains, verificationErr := c.Verify(x509.VerifyOptions{
|
|
Roots: v.roots,
|
|
Intermediates: v.intermediates,
|
|
|
|
// Disable checking extensions & key usages, as their application
|
|
// appears to be inconsistent, and we only use the certificate
|
|
// chains as a means to determine provenance.
|
|
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
|
})
|
|
|
|
out := &pb.EkcertVerificationResults{
|
|
Succeeded: verificationErr == nil,
|
|
ChainVerified: verificationErr == nil,
|
|
}
|
|
if verificationErr != nil {
|
|
out.VerificationError = verificationErr.Error()
|
|
} else {
|
|
for _, cert := range chains[0] {
|
|
out.Chain = append(out.Chain, &pb.EkcertVerificationResults_CertSummary{
|
|
IssuerCn: cert.Issuer.CommonName,
|
|
IssuerOrg: strings.Join(cert.Issuer.Organization, " "),
|
|
Serial: cert.SerialNumber.String(),
|
|
})
|
|
}
|
|
}
|
|
|
|
return out, nil
|
|
}
|
|
|
|
// NewEKVerifier returns an EKVerifier initialized using the certificates in the specified
|
|
// directories. Directories are resolved recursively.
|
|
// The specified directory should be structured in the forms:
|
|
// <XXXX>/RootCA/<cert>.{der,cer,crt)
|
|
// <XXXX>/IntermediateCA/<cert>.{der,cer,crt)
|
|
func NewEKVerifier(certsPath []string) (*EKVerifier, error) {
|
|
roots := x509.NewCertPool()
|
|
intermediates := x509.NewCertPool()
|
|
|
|
for _, dir := range certsPath {
|
|
root, err := ioutil.ReadDir(dir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, f := range root {
|
|
if !f.IsDir() {
|
|
continue
|
|
}
|
|
if err := readCertificates(filepath.Join(dir, f.Name()), roots, intermediates); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
|
|
return &EKVerifier{
|
|
roots: roots,
|
|
intermediates: intermediates,
|
|
}, nil
|
|
}
|
|
|
|
func readCertificates(dir string, roots, intermediates *x509.CertPool) error {
|
|
rootFiles, err := ioutil.ReadDir(filepath.Join(dir, "RootCA"))
|
|
if err != nil && !os.IsNotExist(err) {
|
|
return err
|
|
}
|
|
if err == nil {
|
|
if err := parseCertsToPool(filepath.Join(dir, "RootCA"), rootFiles, roots); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
intermediateFiles, err := ioutil.ReadDir(filepath.Join(dir, "IntermediateCA"))
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
// Not all manufacturers use intermediates certificates.
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
return parseCertsToPool(filepath.Join(dir, "IntermediateCA"), intermediateFiles, intermediates)
|
|
}
|
|
|
|
func parseCertsToPool(path string, files []os.FileInfo, pool *x509.CertPool) error {
|
|
for _, info := range files {
|
|
if info.IsDir() {
|
|
continue
|
|
}
|
|
|
|
path := filepath.Join(path, info.Name())
|
|
switch filepath.Ext(info.Name()) {
|
|
case ".der":
|
|
d, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c, err := x509.ParseCertificate(d)
|
|
if err != nil && x509.IsFatal(err) {
|
|
return fmt.Errorf("%s parse failed: %v", info.Name(), err)
|
|
}
|
|
pool.AddCert(c)
|
|
|
|
case ".crt", ".cer":
|
|
// Either DER or PEM.
|
|
d, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c, err := x509.ParseCertificate(d)
|
|
if err != nil && x509.IsFatal(err) && !pool.AppendCertsFromPEM(d) {
|
|
return fmt.Errorf("%s parse failed: %v", info.Name(), err)
|
|
}
|
|
if err == nil {
|
|
pool.AddCert(c)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|