func tpmAttest()

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
}