-
Notifications
You must be signed in to change notification settings - Fork 172
Description
Is it possible to use a primary key's ctx file (created with tpm2-tools) to sign some data using the "github.com/google/go-tpm/tpm2" package. Im using tpm2 and am on an ubuntu linux VM.
I'm using these commands to create the key in the terminal. Im creating the key as a transient object, rather than saving it to a persistent handle.
echo -n -e "\x00\x01\x49\x44\x45\x56\x49\x44" > idevid.dat
tpm2_createprimary --hierarchy e --key-algorithm rsa2048 --attributes "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|sign|noda" --key-context idevid.ctx --unique-data idevid.dat --output idevid.pub
I am able to sign data with idevid.ctx key created above with the following tpm2 tools commands
echo "my message" > message.dat
tpm2_sign --key-context idevid.ctx --hash-algorithm sha256 --signature sig.rssa message.dat
tpm2_verifysignature --key-context idevid.ctx --hash-algorithm sha256 --signature sig.rssa --message message.dat
Im making a connection to the TPM using the "github.com/google/go-tpm/tpm2/transport" package
tpmDevice := "/dev/tpmrm0"
tpm, err := transport.OpenTPM(tpmDevice)
if err != nil {
fmt.Printf("Could not connect to TPM: %v", err)
}Im currently having an issue trying to load the key handle of the idevid.ctx file into the KeyHandle field in the Sign struct. The examples I have seen in the go-tpm repo seem to make the keys using go-tpm with functions like CreatePrimary and then pass the key handle returned by CreatePrimary into other functions like Sign. In my case I need to get the key handle object by loading an external idevid.ctx file. Below an example of code that im building off of to sign data.
sign := Sign{
KeyHandle: NamedHandle{
Handle: handle,
Name: name,
},
Digest: TPM2BDigest{
Buffer: digest[:],
},
InScheme: TPMTSigScheme{
Scheme: TPMAlgRSASSA,
Details: NewTPMUSigScheme(
TPMAlgRSASSA,
&TPMSSchemeHash{
HashAlg: TPMAlgSHA256,
},
),
},
Validation: TPMTTKHashCheck{
Tag: TPMSTHashCheck,
},
}
rspSign, err := sign.Execute(tpm)
if err != nil {
fmt.Printf("Failed to Sign Digest: %v", err)
}
fmt.Println(rspSign)I wrote the following code to decode the ctx file and load its contents into a TPMSContext object. Using the tpm2-tools tpm2_print command, Ive been able to confirm that the value of the savehandle, hierarchy, sequence and contextblob size are correct and that they are the correct type. I have not been able to verify if the value of contextblob is correct.
var ctx TPMSContext
reader := bytes.NewReader(primaryCtx)
var extra uint64
if err := binary.Read(reader, binary.BigEndian, &extra); err != nil {
fmt.Printf("Failed to parse SavedHandle: %v", err)
}
if err := binary.Read(reader, binary.BigEndian, &ctx.Hierarchy); err != nil {
fmt.Printf("Failed to parse SavedHandle: %v", err)
}
if err := binary.Read(reader, binary.BigEndian, &ctx.SavedHandle); err != nil {
fmt.Printf("Failed to parse Hierarchy: %v", err)
}
if err := binary.Read(reader, binary.BigEndian, &ctx.Sequence); err != nil {
fmt.Printf("Failed to parse size: %v", err)
}
var size uint16
if err := binary.Read(reader, binary.BigEndian, &size); err != nil {
fmt.Printf("Failed to parse size: %v", err)
}
contextData := make([]byte, size)
if err := binary.Read(reader, binary.BigEndian, &contextData); err != nil {
fmt.Printf("Failed to read context data buffer: %v", err)
return
}
ctx.ContextBlob = TPM2BContextData{
Buffer: contextData,
}I have tried directly loading the ctx.SavedHandle variable (which is type TPMHandle) and I tried using the KnownName function on it to get the name and then pass the handle and name value into the NamedHandle object.
name := ctx.SavedHandle.KnownName()
digest := sha256.Sum256([]byte("migrationpains"))
sign := Sign{
KeyHandle: NamedHandle{
Handle: ctx.SavedHandle,
Name: *name,
},
Digest: TPM2BDigest{
Buffer: digest[:],
},
InScheme: TPMTSigScheme{
Scheme: TPMAlgRSASSA,
Details: NewTPMUSigScheme(
TPMAlgRSASSA,
&TPMSSchemeHash{
HashAlg: TPMAlgSHA256,
},
),
},
Validation: TPMTTKHashCheck{
Tag: TPMSTHashCheck,
},
}
rspSign, err := sign.Execute(tpm)
if err != nil {
fmt.Printf("Failed to Sign Digest: %v", err)
}
}It seems that the value returned by ctx.SaveHandle.KnownName() is nil. So when I run the code above I get the following error
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x525ac8]
I have also tried to use the ContextLoad function to get the key handle from the idevid.ctx file to pass into the Sign struct
var ctx TPMSContext
reader := bytes.NewReader(primaryCtx)
var extra uint64
if err := binary.Read(reader, binary.BigEndian, &extra); err != nil {
fmt.Printf("Failed to parse SavedHandle: %v", err)
}
if err := binary.Read(reader, binary.BigEndian, &ctx.Hierarchy); err != nil {
fmt.Printf("Failed to parse SavedHandle: %v", err)
}
if err := binary.Read(reader, binary.BigEndian, &ctx.SavedHandle); err != nil {
fmt.Printf("Failed to parse Hierarchy: %v", err)
}
if err := binary.Read(reader, binary.BigEndian, &ctx.Sequence); err != nil {
fmt.Printf("Failed to parse size: %v", err)
}
var size uint16
if err := binary.Read(reader, binary.BigEndian, &size); err != nil {
fmt.Printf("Failed to parse size: %v", err)
}
contextData := make([]byte, size)
if err := binary.Read(reader, binary.BigEndian, &contextData); err != nil {
fmt.Printf("Failed to read context data buffer: %v", err)
return
}
ctx.ContextBlob = TPM2BContextData{
Buffer: contextData,
}
contextLoad := ContextLoad{
Context: ctx,
}
rspCL, err := contextLoad.Execute(tpm)
if err != nil {
fmt.Printf("ContextLoad failed: %v", err)
}
fmt.Println(rspCL)
}When I run the code above to load the context I get the following error.
ContextLoad failed: TPM_RC_SIZE (parameter 1): structure is the wrong size<nil>
Is there a way that I can load the idevid.ctx file and use go-tpm to sign data?