in cmd/gke-exec-auth-plugin/tpm.go [82:160]
func tpmAttest(dev tpmDevice, privateKey crypto.PrivateKey) ([]byte, error) {
aikh, aikPub, err := loadPrimaryKey(dev)
if err != nil {
return nil, fmt.Errorf("loadPrimaryKey: %v", err)
}
defer dev.flush(aikh)
klog.Info("loaded AIK")
kh, err := loadTLSKey(dev, privateKey)
if err != nil {
return nil, fmt.Errorf("loadTLSKey: %v", err)
}
defer dev.flush(kh)
klog.Info("loaded TLS key")
attest, sig, err := dev.certify(kh, aikh)
if err != nil {
return nil, fmt.Errorf("certify failed: %v", err)
}
klog.Info("TLS key certified by AIK")
// Sanity-check the signature.
attestHash := sha256.Sum256(attest)
if err := rsa.VerifyPKCS1v15(aikPub.(*rsa.PublicKey), crypto.SHA256, attestHash[:], sig); err != nil {
return nil, fmt.Errorf("signature verification failed: %v", err)
}
klog.Info("certification signature verified with AIK public key")
// Try loading AIK cert, but don't fail if it wasn't provisioned.
//
// TODO(awly): make missing AIK cert an error eventually provisioning is
// reliable enough.
aikCertRaw, aikCert, err := readAIKCert(dev, aikh, aikPub)
if err != nil {
klog.Warningf("proceeding without AIK cert in CSR: failed reading AIK cert: %v", err)
} else {
klog.Info("AIK cert loaded")
// Sanity-check that AIK cert matches AIK.
aikCertPub := aikCert.PublicKey.(*rsa.PublicKey)
if !reflect.DeepEqual(aikPub, aikCertPub) {
return nil, fmt.Errorf("AIK public key doesn't match certificate public key")
}
if err := rsa.VerifyPKCS1v15(aikCertPub, crypto.SHA256, attestHash[:], sig); err != nil {
return nil, fmt.Errorf("verifying certification signature with AIK cert: %v", err)
}
}
id, err := newNodeIdentity()
if err != nil {
return nil, fmt.Errorf("fetching VM identity from GCE metadata: %v", err)
}
idRaw, err := json.Marshal(id)
if err != nil {
return nil, fmt.Errorf("marshaling VM identity: %v", err)
}
buf := new(bytes.Buffer)
// OK to ignore errors from pem.Encode below because buf.Write never fails.
pem.Encode(buf, &pem.Block{
Type: "ATTESTATION DATA",
Bytes: attest,
})
pem.Encode(buf, &pem.Block{
Type: "ATTESTATION SIGNATURE",
Bytes: sig,
})
pem.Encode(buf, &pem.Block{
Type: "VM IDENTITY",
Bytes: idRaw,
})
if len(aikCertRaw) > 0 {
pem.Encode(buf, &pem.Block{
Type: "ATTESTATION CERTIFICATE",
Bytes: aikCertRaw,
})
}
return buf.Bytes(), nil
}