Git Product home page Git Product logo

Comments (8)

arianvp avatar arianvp commented on May 3, 2024

You'd have to load the Activation Key from go-attestation from the same template into go-tpm-tools. You're now generating two distinct AKs.

I don't know how easy it is to get the go-attestation AK into go-tpm-tools. IDK if they store them in the same hierarchy for example. but it's probably possible with some masssaging.

Perhaps easier would be to try this PR which adds credential activation to this library
#98

from go-tpm-tools.

arianvp avatar arianvp commented on May 3, 2024

Main problem is that that this library only creates Primary keys and no child keys . So basically we'd have to wait for #98 to be merged; but at that point we don't need go-attestation libary in the firstp lace

from go-tpm-tools.

GastonMeghi avatar GastonMeghi commented on May 3, 2024

@arianvp
Thank you for your answer!

I was able to get around to it by using go-attestation's functions for boot measurement. But that makes me wonder. What's the relation between go-tpm-tools and go-attestation? At first I thought they did different things but now it seems that they have overlapping functionality. Is one of them going to be deprecated or I'm missing something important here?

I'll leave my solution here just for reference, but I still have to do some checks and add some policies to it:

//***client code***
	config := &attest.OpenConfig{}
	tpm, err := attest.OpenTPM(config)
	if err != nil {
		//handle error
		return nil,err
	}
	defer tpm.Close()

	ak, err := GetAK(tpm)
	if err != nil {
		//handle error
	    return nil,err
	}

	PlatformParameters, err := tpm.AttestPlatform(ak,nonce,nil)
	if err != nil {
		//handle error
		return nil,err
	}
//***server code***
	AKPublic, err := attest.ParseAKPublic(attest.TPMVersion20, PlatformParameters.Public)
	if err != nil {
		//handle error
	    return false,err
	}

	if verified :=CompareAKs(TrustedAK,AKPublic.Public); verified != true {
		//handle error
		return false,err
	}

	err = AKPublic.VerifyAll(PlatformParameters.Quotes, PlatformParameters.PCRs, nonce)
	if err != nil {
		//handle error
	    return false,err
	}

	Eventlog,err := ParseEventLog(PlatformParameters.EventLog)
	if err != nil {
		//handle error
	    return false,err
	}
	Events, err := Eventlog.Verify(PlatformParameters.PCRs)
	if err != nil {
		//handle error
	    return false,err
	}

from go-tpm-tools.

arianvp avatar arianvp commented on May 3, 2024

from go-tpm-tools.

GastonMeghi avatar GastonMeghi commented on May 3, 2024

Thank you for the link and your help! I'll be checking that for the answer!

from go-tpm-tools.

arianvp avatar arianvp commented on May 3, 2024

Here is an (untested). Activation + Attestation flow using just this library:

package main

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/subtle"
	"crypto/x509"
	"log"

	"github.com/google/go-tpm-tools/client"
	"github.com/google/go-tpm-tools/server"
	"github.com/google/go-tpm/tpm2"
	"github.com/google/go-tpm/tpm2/credactivation"
)

func main() {

	// BEGIN SERVER
	attestationRootKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		log.Fatal(err)

	}
	attestationRootTemplate := &x509.Certificate{
		IsCA: true,
	}
	attestationRoot, err := x509.CreateCertificate(rand.Reader, attestationRootTemplate, attestationRootTemplate, attestationRootKey.Public(), attestationRootKey)
	if err != nil {
		log.Fatal(err)
	}
	attestationRootCert, err := x509.ParseCertificate(attestationRoot)
	if err != nil {
		log.Fatal(err)
	}
	// END SERVER

	// BEGIN CLIENT
	tpm, err := tpm2.OpenTPM()
	if err != nil {
		log.Fatal(err)
	}
	defer tpm.Close()

	ek, err := client.EndorsementKeyRSA(tpm)
	if err != nil {
		log.Fatal(err)
	}
	defer ek.Close()

	ekCert := ek.Cert()

	ak, err := client.AttestationKeyECC(tpm)
	if err != nil {
		log.Fatal(err)
	}
	defer ak.Close()

	akCSRTemplate := &x509.CertificateRequest{}
	akPrivateKey, err := ak.GetSigner()
	if err != nil {
		log.Fatal(err)
	}
	akCSRBytes, err := x509.CreateCertificateRequest(rand.Reader, akCSRTemplate, akPrivateKey)
	if err != nil {
		log.Fatal(err)
	}
	// END CLIENT

	// BEGIN SERVER

	// Check that th EK cert is trusted
	_, err = ekCert.Verify(x509.VerifyOptions{})
	if err != nil {
		log.Fatal(err)
	}

	secret := make([]byte, 32)
	if _, err := rand.Read(secret); err != nil {
		log.Fatal(err)
	}

	// generate a challenge for the the client
	credBlob, encryptedSecret, err := credactivation.Generate(ak.Name().Digest, ek.PublicKey(), 16, secret)
	if err != nil {
		log.Fatal(err)
	}

	// END SERVER

	// BEGIN CLIENT
	decryptedSecret, err := tpm2.ActivateCredential(tpm, ek.Handle(), ak.Handle(), "", "", credBlob, encryptedSecret)
	if err != nil {
		log.Fatal(err)
	}
	// END CLIENT

	// BEGIN SERVER

	// Check if the challenge is solved
	if subtle.ConstantTimeCompare(secret, decryptedSecret) != 0 {
		log.Fatal("Secrets did not match")
	}
	// decode the CSR
	akCSR, err := x509.ParseCertificateRequest(akCSRBytes)
	if err != nil {
		log.Fatal(err)
	}
	if err := akCSR.CheckSignature(); err != nil {
		log.Fatal(err)
	}

	// We know that the AK is backed by the EK and that the EK is trusted at
	// this point! Lets issue a certificate for the AK

	// NOTE: should be populated with the same fields as set on the CSR template In
	// our case it's empty...
	akCertTemplate := &x509.Certificate{}

	akCertBytes, err := x509.CreateCertificate(rand.Reader, akCertTemplate, attestationRootCert, akCSR.PublicKey, attestationRootKey)
	if err != nil {
		log.Fatal(err)
	}
	// END SERVER

	// BEGIN CLIENT
	akCert, err := x509.ParseCertificate(akCertBytes)
	if err != nil {
		log.Fatal(err)
	}
	ak.SetCert(akCert)

	// we can now generate an attestation

	nonce := make([]byte, 32)
	if _, err := rand.Read(nonce); err != nil {
		log.Fatal(err)
	}
	attestation, err := ak.Attest(client.AttestOpts{
		Nonce: nonce,
	})
	if err != nil {
		log.Fatal(err)
	}
	// END CLIENT

	// BEGIN SERVER
	machineState, err := server.VerifyAttestation(attestation, server.VerifyOpts{
		Nonce:            nonce,
		TrustedRootCerts: []*x509.Certificate{attestationRootCert},
	})
	if err != nil {
		log.Fatal(err)
	}
	log.Print(machineState.String())
	// END SERVER
}

from go-tpm-tools.

arianvp avatar arianvp commented on May 3, 2024

Two things about the above code dont work:

ActivateCredential needs to use ActivateCredentialUsingAuth.

and The CSR part needs to be skipped

I'll see if I can send a patch

from go-tpm-tools.

arianvp avatar arianvp commented on May 3, 2024

This one actually works:

package main

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/subtle"
	"crypto/x509"
	"log"
	"math/big"
	"os"
	"os/exec"
	"time"

	"github.com/google/go-tpm-tools/client"
	"github.com/google/go-tpm-tools/server"
	"github.com/google/go-tpm/tpm2"
	"github.com/google/go-tpm/tpm2/credactivation"
)

func main() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	// BEGIN SERVER
	attestationRootKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		log.Fatal(err)

	}
	attestationRootTemplate := &x509.Certificate{
		SerialNumber:          big.NewInt(1),
		NotBefore:             time.Now(),
		NotAfter:              time.Now().Add(24 * time.Hour),
		IsCA:                  true,
		KeyUsage:              x509.KeyUsageCertSign,
		BasicConstraintsValid: true,
	}
	attestationRoot, err := x509.CreateCertificate(rand.Reader, attestationRootTemplate, attestationRootTemplate, attestationRootKey.Public(), attestationRootKey)
	if err != nil {
		log.Fatal(err)
	}
	attestationRootCert, err := x509.ParseCertificate(attestationRoot)
	if err != nil {
		log.Fatal(err)
	}
	rootCertPool := x509.NewCertPool()
	rootCertPool.AddCert(attestationRootCert)

	// END SERVER

	// BEGIN CLIENT
	if os.Getenv("CLOUD_SHELL") == "true" {
		cmd := exec.Command("sudo", "chmod", "777", "/dev/tpmrm0")
		if b, err := cmd.CombinedOutput(); err != nil {
			log.Fatal(string(b))
		}
	}

	tpm, err := tpm2.OpenTPM()
	if err != nil {
		log.Fatal(err)
	}
	defer tpm.Close()

	ek, err := client.EndorsementKeyRSA(tpm)
	if err != nil {
		log.Fatal(err)
	}
	defer ek.Close()

	ekCert := ek.Cert()

	ak, err := client.AttestationKeyRSA(tpm)
	if err != nil {
		log.Fatal(err)
	}
	defer ak.Close()
	// END CLIENT

	// BEGIN SERVER

	if ekCert != nil {
		_, err = ekCert.Verify(x509.VerifyOptions{})
		if err != nil {
			log.Fatal(err)
		}
	}

	secret := make([]byte, 32)
	if _, err := rand.Read(secret); err != nil {
		log.Fatal(err)
	}

	// generate a challenge for the the client
	credBlob, encryptedSecret, err := credactivation.Generate(ak.Name().Digest, ek.PublicKey(), 16, secret)
	if err != nil {
		log.Fatal(err)
	}

	// END SERVER

	// BEGIN CLIENT

	// Had to hack this session in as.  ek.Session is not exposed publicly
	session, _, err := tpm2.StartAuthSession(
		tpm,
		/*tpmKey=*/ tpm2.HandleNull,
		/*bindKey=*/ tpm2.HandleNull,
		/*nonceCaller=*/ make([]byte, 16),
		/*encryptedSalt=*/ nil,
		/*sessionType=*/ tpm2.SessionPolicy,
		/*symmetric=*/ tpm2.AlgNull,
		/*authHash=*/ client.SessionHashAlgTpm)
	if err != nil {
		log.Fatal(err)
	}
	defer tpm2.FlushContext(tpm, session)
	nullAuth := tpm2.AuthCommand{Session: tpm2.HandlePasswordSession, Attributes: tpm2.AttrContinueSession}
	if _, _, err = tpm2.PolicySecret(tpm, tpm2.HandleEndorsement, nullAuth, session, nil, nil, nil, 0); err != nil {
		log.Fatal(err)
	}
	ekAuth := tpm2.AuthCommand{Session: session, Attributes: tpm2.AttrContinueSession}
	auth := []tpm2.AuthCommand{nullAuth, ekAuth}
	decryptedSecret, err := tpm2.ActivateCredentialUsingAuth(tpm, auth, ak.Handle(), ek.Handle(), credBlob[2:], encryptedSecret[2:])
	if err != nil {
		log.Fatal(err)
	}

	// END CLIENT

	// BEGIN SERVER

	// Check if the challenge is solved
	if subtle.ConstantTimeCompare(secret, decryptedSecret) != 1 {
		log.Fatal("Secrets did not match")
	}

	// We know that the AK is backed by the EK and that the EK is trusted at
	// this point! Lets issue a certificate for the AK

	// NOTE: should be populated with the same fields as set on the CSR template In
	// our case it's empty...
	akCertTemplate := &x509.Certificate{
		SerialNumber: big.NewInt(3),
		NotBefore:    time.Now(),
		NotAfter:     time.Now().Add(24 * time.Hour),
		ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
	}

	akCertBytes, err := x509.CreateCertificate(rand.Reader, akCertTemplate, attestationRootCert, ak.PublicKey(), attestationRootKey)
	if err != nil {
		log.Fatal(err)
	}
	// END SERVER

	// BEGIN CLIENT
	akCert, err := x509.ParseCertificate(akCertBytes)
	if err != nil {
		log.Fatal(err)
	}

	if _, err := akCert.Verify(x509.VerifyOptions{
		Roots:     rootCertPool,
		KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsage(x509.ExtKeyUsageAny)},
	}); err != nil {
		log.Fatal(err)
	}

	ak.SetCert(akCert)

	// we can now generate an attestation

	nonce := make([]byte, 32)
	if _, err := rand.Read(nonce); err != nil {
		log.Fatal(err)
	}
	attestation, err := ak.Attest(client.AttestOpts{
		Nonce: nonce,
	})
	if err != nil {
		log.Fatal(err)
	}
	// END CLIENT

	// BEGIN SERVER
	machineState, err := server.VerifyAttestation(attestation, server.VerifyOpts{
		Nonce:            nonce,
		TrustedRootCerts: []*x509.Certificate{attestationRootCert},
	})
	if err != nil {
		log.Fatal(err)
	}
	log.Print(machineState.String())
	// END SERVER
}

from go-tpm-tools.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.