-
crate prmiary
-
create key
-
evict primary to persistent handle
0x81000000
-
save key with go-tpm-keyfiles
-
load key using go-tpm-keyfile
module main
go 1.22.2
require (
github.com/foxboron/go-tpm-keyfiles v0.0.0-20240607201534-c7a43ea1908b
github.com/google/go-tpm v0.9.1
github.com/google/go-tpm-tools v0.4.4
)
require (
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-configfs-tsm v0.2.2 // indirect
github.com/google/go-sev-guest v0.9.3 // indirect
github.com/google/go-tdx-guest v0.3.1 // indirect
github.com/google/logger v1.1.1 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/pborman/uuid v1.2.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/sys v0.21.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
)
- create.go
package main
import (
"bytes"
"encoding/base64"
"flag"
"log"
"os"
keyfile "github.com/foxboron/go-tpm-keyfiles"
"github.com/google/go-tpm/tpm2"
"github.com/google/go-tpm/tpm2/transport"
)
const ()
var (
tpmPath = flag.String("tpm-path", "/dev/tpmrm0", "Path to the TPM device (character device or a Unix socket).")
keyFile = flag.String("keyfile", "private.pem", "privateKey File")
)
func main() {
flag.Parse()
log.Println("======= Init ========")
rwc, err := transport.OpenTPM(*tpmPath)
if err != nil {
log.Fatalf("can't open TPM %q: %v", *tpmPath, err)
}
defer func() {
rwc.Close()
}()
log.Printf("======= createPrimary ========")
primaryKey, err := tpm2.CreatePrimary{
PrimaryHandle: tpm2.TPMRHOwner,
InPublic: tpm2.New2B(tpm2.RSASRKTemplate),
}.Execute(rwc)
if err != nil {
log.Fatalf("can't create primary %v", err)
}
defer func() {
flushContextCmd := tpm2.FlushContext{
FlushHandle: primaryKey.ObjectHandle,
}
_, _ = flushContextCmd.Execute(rwc)
}()
log.Printf("primaryKey Name %s\n", base64.StdEncoding.EncodeToString(primaryKey.Name.Buffer))
// *************** evict
// tpm2_evictcontrol -C o -c 0x81000000
// https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html#section-3.1.8
_, err = tpm2.EvictControl{
Auth: tpm2.TPMRHOwner,
ObjectHandle: &tpm2.NamedHandle{
Handle: primaryKey.ObjectHandle,
Name: primaryKey.Name,
},
PersistentHandle: tpm2.TPMHandle(0x81000000),
}.Execute(rwc)
if err != nil {
log.Fatalf("can't create rsa %v", err)
}
// rsa
log.Printf("======= create key ========")
rsaTemplate := tpm2.TPMTPublic{
Type: tpm2.TPMAlgRSA,
NameAlg: tpm2.TPMAlgSHA256,
ObjectAttributes: tpm2.TPMAObject{
SignEncrypt: true,
FixedTPM: true,
FixedParent: true,
SensitiveDataOrigin: true,
UserWithAuth: true,
},
AuthPolicy: tpm2.TPM2BDigest{},
Parameters: tpm2.NewTPMUPublicParms(
tpm2.TPMAlgRSA,
&tpm2.TPMSRSAParms{
Scheme: tpm2.TPMTRSAScheme{
Scheme: tpm2.TPMAlgRSASSA,
Details: tpm2.NewTPMUAsymScheme(
tpm2.TPMAlgRSASSA,
&tpm2.TPMSSigSchemeRSASSA{
HashAlg: tpm2.TPMAlgSHA256,
},
),
},
KeyBits: 2048,
},
),
Unique: tpm2.NewTPMUPublicID(
tpm2.TPMAlgRSA,
&tpm2.TPM2BPublicKeyRSA{
Buffer: make([]byte, 256),
},
),
}
rsaKeyResponse, err := tpm2.CreateLoaded{
ParentHandle: tpm2.AuthHandle{
Handle: primaryKey.ObjectHandle,
Name: primaryKey.Name,
Auth: tpm2.PasswordAuth([]byte("")),
},
InPublic: tpm2.New2BTemplate(&rsaTemplate),
}.Execute(rwc)
if err != nil {
log.Fatalf("can't create rsa %v", err)
}
defer func() {
flushContextCmd := tpm2.FlushContext{
FlushHandle: rsaKeyResponse.ObjectHandle,
}
_, _ = flushContextCmd.Execute(rwc)
}()
// write the key to file
log.Printf("======= writing key to file ========")
kf := &keyfile.TPMKey{
Keytype: keyfile.OIDLoadableKey,
AuthPolicy: []*keyfile.TPMAuthPolicy{},
Parent: 0x81000000,
Pubkey: rsaKeyResponse.OutPublic,
Privkey: rsaKeyResponse.OutPrivate,
Description: "key1",
}
if err != nil {
log.Fatalf("failed to create KeyFile: %v", err)
}
b := new(bytes.Buffer)
err = keyfile.Encode(b, kf)
if err != nil {
log.Fatalf("failed to encode Key: %v", err)
}
log.Printf("rsa Key PEM: \n%s\n", b)
err = os.WriteFile(*keyFile, b.Bytes(), 0644)
if err != nil {
log.Fatalf("failed to write private key to file %v", err)
}
}
- load.go
package main
import (
"crypto/sha256"
"encoding/base64"
"flag"
"log"
"os"
keyfile "github.com/foxboron/go-tpm-keyfiles"
"github.com/google/go-tpm/tpm2"
"github.com/google/go-tpm/tpm2/transport"
)
const ()
var (
tpmPath = flag.String("tpm-path", "/dev/tpmrm0", "Path to the TPM device (character device or a Unix socket).")
keyFile = flag.String("keyfile", "private.pem", "privateKey File")
dataToSign = flag.String("datatosign", "foo", "data to sign")
)
func main() {
flag.Parse()
log.Println("======= Init ========")
rwc, err := transport.OpenTPM(*tpmPath)
if err != nil {
log.Fatalf("can't open TPM %q: %v", *tpmPath, err)
}
defer func() {
rwc.Close()
}()
// load the rsa key from disk
log.Printf("======= reading key from file ========")
c, err := os.ReadFile(*keyFile)
if err != nil {
log.Fatalf("error reading private keyfile: %v", err)
}
key, err := keyfile.Decode(c)
if err != nil {
log.Fatalf("failed decoding key: %v", err)
}
sess := keyfile.NewTPMSession(rwc)
// pub, err := tpm2.ReadPublic{
// ObjectHandle: key.Parent,
// }.Execute(rwc)
// if err != nil {
// log.Fatalf("failed loading key with parent: %v", err)
// }
// parentAuthHandle := tpm2.AuthHandle{
// Handle: key.Parent,
// Name: pub.Name,
// Auth: tpm2.PasswordAuth(nil),
// }
parentAuthHandle := tpm2.AuthHandle{
Handle: key.Parent,
Name: tpm2.HandleName(key.Parent),
Auth: tpm2.PasswordAuth(nil),
}
ah, err := keyfile.LoadKeyWithParent(sess, parentAuthHandle, key)
if err != nil {
log.Fatalf("failed loading key with parent: %v", err)
}
defer func() {
flushContextCmd := tpm2.FlushContext{
FlushHandle: ah.Handle,
}
_, _ = flushContextCmd.Execute(rwc)
}()
data := []byte(*dataToSign)
digest := sha256.Sum256(data)
rspSign, err := tpm2.Sign{
KeyHandle: ah,
Digest: tpm2.TPM2BDigest{
Buffer: digest[:],
},
InScheme: tpm2.TPMTSigScheme{
Scheme: tpm2.TPMAlgRSASSA,
Details: tpm2.NewTPMUSigScheme(
tpm2.TPMAlgRSASSA,
&tpm2.TPMSSchemeHash{
HashAlg: tpm2.TPMAlgSHA256,
},
),
},
Validation: tpm2.TPMTTKHashCheck{
Tag: tpm2.TPMSTHashCheck,
},
}.Execute(rwc)
if err != nil {
log.Fatalf("Failed to Sign: %v", err)
}
rsassa, err := rspSign.Signature.Signature.RSASSA()
if err != nil {
log.Fatalf("Failed to get signature part: %v", err)
}
log.Printf("signature : %s\n", base64.StdEncoding.EncodeToString(rsassa.Sig.Buffer))
}
if you want to use a softwaretpm instead,
rm -rf /tmp/myvtpm && mkdir /tmp/myvtpm && sudo swtpm socket --tpmstate dir=/tmp/myvtpm --tpm2 --server type=tcp,port=2321 --ctrl type=tcp,port=2322 --flags not-need-init,startup-clear
export TPM2TOOLS_TCTI="swtpm:port=2321"
## or with socat pipe /tmp/vtpm to swtpm tpc listner
sudo socat pty,link=/tmp/vtpm,raw,echo=0 tcp:localhost:2321
sudo chmod go+rw /tmp/vtpm
export TPM2TOOLS_TCTI="device:/tmp/vtpm"