Utility function you can use to securely copy an RSA or ECC or AES or HMAC KEY from your laptop to a remote Trusted Platform MOdule (TPM)
Basically, you can transfer a key from your laptop (local) to TPM-B such that the key cannot get decrypted or exposed outside of TPM-B.
The key you transfer will not get exposed into user space but can be used to sign/encrypt/decrypt/hmac while always existing inside the destination TPM.
Furthermore, you can place TPM based conditions on the transfer and the use of that key on the destination TPM
For examples, you can specify a passphrase or certain PCR values must be present on use for the destination key.
Alternativley, if you just want some secret to get transferred securely only to get decrypted in userspace (eg securely transfer raw data as opposed to a TPM-embedded key), see
- Overview
- Options
- References
- Build
- Usage CLI
- Usage Library
- Key Policies
- Key Parent
- TPM2_TOOLS Compatibility
- Parent Persistent Handle
- Key persistent handle
- Openssl Compatibility
- Session Encryption
- Key Formats
- TPMPolicy Syntax PEM Encoding
- Setup Software TPM
- tpmcopy using tpm2_tools
At a high level, this utility basically performs tpm2_duplicate and involves several steps:
If you want to transfer an external RSA|ECC|AES|HMAC key from a local system to TPM-B, you will need to
-
On
TPM-B, extract the Endorsement Public Key, the H2 ECC SRK or the RSA|ECC Storage Root Key (SRK) Copy the public key to the system from which you want to transfer the secret key (eg, local) -
On
local, create the secretRSA|ECC|AES|HMAC -
On
localuseTPM-Bpublic key to duplicate the secret key such that it can only get loaded -inside-TPM-BThe duplicate step will encrypt the external key such that onlyTPM-Bcan import it. The encrypted key is saved as a file which you will need to copy toTPM-B -
On
TPM-Bimport the duplicated key you copied fromlocalThe imported key is saved in TPM encoded PEM format for later use -
On
TPM-B, use the imported key to sign,encrypt,decrypt,hmac
It is critical to note the key that is transferred carries specific TPM policies which must be fulfilled upon use.
These policies ensure the key cannot get duplicated beyond the target TPM. Specifically, the keys carry:
- PCR:
tpm2_policyor(tpm2_policypcr | tpm2_policyduplicateselect) - Password:
tpm2_policyor(tpm2_policyauthvalue | tpm2_policyduplicateselct).
For more details, see the section below on Bound Key Policy
You can skip binding to the policies using the --skipPolicy flag
| Option | Description |
|---|---|
-tpm-path |
Path to the TPM device (default: /dev/tpmrm0) |
-mode |
Operation mode: publickey duplicate import (default: ``) |
-help |
print usage |
| Option | Description |
|---|---|
-parentKeyType |
type of the parent Key (rsa ecc) (default: "rsa") |
| Option | Description |
|---|---|
-keyType |
type of key to import/export (rsa ecc aes hmac keyedhash) (default: "rsa") |
-rsaScheme |
rsa Key Scheme (rsassa rsapss) (default: "rsassa") |
-hashScheme |
hash Scheme (sha256 sha384 sha512) (default: "sha256") |
-eccScheme |
ecc Key Alg (ecc256 ecc384 ecc521) (default: "ecc256") |
-keySize |
AES key size (128 256) (default: "128") |
-secret |
File with secret to duplicate (rsa |
-out |
Output file (default: "") |
-in |
Import file (default: "") |
-pubout |
Save the imported key as TPM2B_PUBLIC (default: ") |
-privout |
Save the imported private as , TPM2B_PRIVATE (default: ") |
-parent |
parent to to encode the key parent against or load. |
-keyName |
description of the key to annotate (default: "") |
-tpmPublicKeyFile |
File to write the public key to (default: /tmp/public.pem) |
| Option | Description |
|---|---|
-pcrValues |
comma separated list of current pcr values to bind the key to (default: "") |
-persistentHandle |
persistentHandle to save the key to (default 0x81008001 owner) |
-password |
passphrase for the TPM key (default: "") |
-skipPolicy |
skip binding the key to any policy |
-ownerpw |
passphrase for the TPM owner (default: "") |
-tpm-session-encrypt-with-name |
"hex encoded TPM object 'name' to use with an encrypted session" |
This repo is not supported by Google
- tpm2 key utility
- Sign, Verify and decode using Google Cloud vTPM Attestation Key and Certificate
- TPM based Google Cloud Credential Access Token
- golang-jwt for Trusted Platform Module (TPM)
- TPM Credential Source for Google Cloud SDK
- go-tpm-tools: Transferring RSA and Symmetric keys with GCP vTPMs
You can use the binary in the Releases page as a standalone cli or load as a library or just build:
go build -o tpmcopy cmd/main.goTo tranfer an RSA key from local to TPM-B
You'll first need the endorsement public key or the H2 parent from TPM-B. You can get that either from TPM-B directly using tpmcopy or with a utility like tpm2_tools:
For the Endorsement Public:
tpm2_createek -c primaryB.ctx -G rsa -u ekB.pub -Q
tpm2_readpublic -c primaryB.ctx -o ekpubB.pem -f PEM -QNote, if you have the EKCertificate, you can easily extract the ekPub
tpm2_getekcertificate -X -o ECcert.bin
openssl x509 -in ECcert.bin -inform DER -noout -text
openssl x509 -pubkey -noout -in ECcert.bin -inform DER If you wanted to use the H2 Parent instead of the EK, you need to do that on TPM-B itself:
printf '\x00\x00' > unique.dat
tpm2_createprimary -C o -G ecc -g sha256 \
-c primary.ctx \
-a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda|restricted|decrypt" -u unique.dat
tpm2_readpublic -c primary.ctx -o h2Public.pem -f PEM -n primary.name If you want the RSA or ECC Storage Root Key (SRK)
## RSASRK
printf '\x00\x01' > ud.1
dd if=/dev/zero bs=256 count=1 of=ud.2
cat ud.1 ud.2 > unique.dat
tpm2_createprimary -C o -u unique.dat \
-G rsa2048 -g sha256 -c primary.ctx --attributes="fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda|restricted|decrypt" -Q
tpm2_readpublic -c primary.ctx -o rsa_srk.pem -f PEM
tpm2_flushcontext -tTo transfer an RSASSA key
### Local
openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:65537 -out /tmp/key_rsa.pem
### TPM-B
export TPMB="/dev/tpmrm0" # TPMB="127.0.0.1:2321"
tpmcopy --mode publickey --parentKeyType=rsa_ek -tpmPublicKeyFile=/tmp/public.pem --tpm-path=$TPMB
### copy public.pem to Local
### local
tpmcopy --mode duplicate --keyType=rsa --secret=/tmp/key_rsa.pem --rsaScheme=rsassa \
--hashScheme=sha256 --password=bar -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
### copy /tmp/out.json to TPM-B
### TPM-B
tpmcopy --mode import --parentKeyType=rsa_ek --in=/tmp/out.json --out=/tmp/tpmkey.pem --tpm-path=$TPMB
### test
cd example/
go run rsa/password/main.go --pemFile=/tmp/tpmkey.pem --password=bar --tpm-path=$TPMBTo transfer an ECC-P256 key
### Local
openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 -out /tmp/key_ecc.pem
### TPM-B
export TPMB="/dev/tpmrm0"
tpmcopy --mode publickey --parentKeyType=rsa_ek -tpmPublicKeyFile=/tmp/public.pem --tpm-path=$TPMB
### copy public.pem to Local
## Password
tpmcopy --mode duplicate --keyType=ecc --secret=/tmp/key_ecc.pem --eccScheme=ecc256 --hashScheme=sha256 \
--password=bar -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
### copy /tmp/out.json to TPM-B
### TPM-B
tpmcopy --mode import --parentKeyType=rsa_ek --in=/tmp/out.json --out=/tmp/tpmkey.pem --tpm-path=$TPMB
### test
cd example/
go run ecc/password/main.go --pemFile=/tmp/tpmkey.pem --password=bar --tpm-path=$TPMBTo transfer AES-128 CFB
### Local
echo -n "46be0927a4f86577f17ce6d10bc6aa61" > /tmp/aes.key
### TPM-B
export TPMB="/dev/tpmrm0"
tpmcopy --mode publickey --parentKeyType=rsa_ek -tpmPublicKeyFile=/tmp/public.pem --tpm-path=$TPMB
### copy public.pem to local
### Local
tpmcopy --mode duplicate --keyType=aes --aesScheme=cfb --keySize=128 --secret=/tmp/aes.key \
--password=bar -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
### copy /tmp/out.json to TPM-B
### TPM-B
tpmcopy --mode import --parentKeyType=rsa_ek --in=/tmp/out.json --out=/tmp/tpmkey.pem --tpm-path=$TPMB
### test
cd example/
go run aes/password/main.go --pemFile=/tmp/tpmkey.pem --password=bar --tpm-path=$TPMBTo transfer an HMAC 256 key,
### Local
echo -n "change this password to a secret" > /tmp/hmac_256.key
### TPM-B
export TPMB="/dev/tpmrm0"
tpmcopy --mode publickey --parentKeyType=rsa_ek -tpmPublicKeyFile=/tmp/public.pem --tpm-path=$TPMB
### copy public.pem to Local
### loal
tpmcopy --mode duplicate --keyType=hmac --hashScheme=sha256 --secret=/tmp/hmac_256.key \
--password=bar -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
### copy /tmp/out.json to TPM-B
### TPM-B
tpmcopy --mode import --parentKeyType=rsa_ek --in=/tmp/out.json --out=/tmp/tpmkey.pem --tpm-path=$TPMB
### test
cd example/
go run hmac/password/main.go --pemFile=/tmp/tpmkey.pem --password=bar --tpm-path=$TPMBTo transfer an arbitrary secret to unseal remotely (eg aKeyedHash) run the following.
In other words, The secret you seal is unsealed into userspace on the remote system.
Note that if all you want to do is to transfer a secret, you can also use the standalone tool here which specificly only coverst this:
anyway,
### Local
echo -n "mysecretdata" > /tmp/keyed_hash.key
### TPM-B
export TPMB="/dev/tpmrm0"
tpmcopy --mode publickey --parentKeyType=rsa_ek -tpmPublicKeyFile=/tmp/public.pem --tpm-path=$TPMB
### copy public.pem to Local
### loal
tpmcopy --mode duplicate --keyType=keyedhash --secret=/tmp/keyed_hash.key \
--password=bar -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
### copy /tmp/out.json to TPM-B
### TPM-B
tpmcopy --mode import --parentKeyType=rsa_ek --in=/tmp/out.json --out=/tmp/tpmkey.pem --tpm-path=$TPMB
### test
cd example/
go run keyedhash/main.go --pemFile=/tmp/tpmkey.pem --password=bar --tpm-path=$TPMB
# prints "mysecretdata"You can also use this utility in go directly. For an example of using as a library, see the testcases or the example/direct folder which creates a public key, then duplicates an HMAC key and finally import it into a destination TPM
By default the example uses a software TPM:
### get public key
$ go run direct/public/main.go -tpmPublicKeyFile /tmp/public.pem -tpm-path "127.0.0.1:2321"
$ cat /tmp/public.pem
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAne5iFdkj4QETbjUnWcOl
+wQl6s9tBR2bSOp3gRUCn1noG7E62U5T3jCP9k0883rWeUh6fTICTzxhoPRIlm/R
z0vFnKOm51VYAgT/XwhirLTqaskvS76B9OXGRt+9BVo0RkbzV8fhYzd2kGQPGdj5
ncRSqF/wzLEnfdv5tZziPmdtHQXvlGdVOEIP3Zz2VPi36DP3IW5wnxohrTIB9R/o
m+1jdG2CRn7rkv2ZRvBKP9umNttG3wFM4qn2Pn+mBZ9rfxPCeZULC/EMu2lvG/+q
lBSUzXVDECes2SdamtwvA2o0Wnfw4SunIY2ehT+J8jq7c/4mMHus8amCBs1tgcDA
bwIDAQAB
-----END PUBLIC KEY-----
echo -n "change this password to a secret" > /tmp/hmac_256.key
### duplicate
$ go run direct/duplicate/main.go -parentKeyType rsa_ek \
-secret /tmp/hmac_256.key -tpmPublicKeyFile /tmp/public.pem
$ cat /tmp/out.json | jq '.'
{
"version": 1,
"type": "HMAC",
"parentKeyType": "EndorsementRSA",
"key": "-----BEGIN TSS2 PRIVATE KEY-----\nMIIB4QYGZ4EFCgEEoAMBAf+iggEGBIIBAgEAlXOL+W9RnYQFb3zoatVISsgZnMJS\nwBKtSKwHMh9vBCvIGl69puX9Od4JGBZyi4uUf48Cjci+CRBEKX3ijjC5RWVnPpLt\nCndMK3jNxoGQK3hoIzDvfHitVzEHcOa151Wg8WKq2uAOJoDVSEgPf7OqPYWnCiQE\nbMdogZhZWPM6BYbUOF0dsC96kEd1Bj6AXUNKa5sD8AgPWJAPhujQyaiuhybCwAjN\nzVOi04VA5bGcPr4DOpsQ7dWFPcRYtpkQQ7tMllJaMDouAeibVOE2zDd30aklolsc\nb5/hroxpSTQk317DakuqmAAinb6+QGcStNqhUl1i2xL9kJQpEulM7HBMoQIEQAAB\nQARSAFAACAALAAQAAAAgOY9wqZE2tqP3VTLztEEjQI8CmVJpp/aP2wFpaT1zA2AA\nBQALACAL1ozkZPJRncVrwrLS3XqEQsHUR4Nw/ujnWE0HbfPrrwRuAGwAIDlUgijx\nH4z+Kh1XWChiuswtgZkpdGZPbdAAVy2g7bsiokFY/CDMyzawCGyR6THxsn6FH/Aj\nXiGwMuOm/jJsnC2vEwAb6pZ8bU/M+4lhQteR4ZfaCMlZvKS7Ka0tMyurlPjvG9CH\nV8yP6/E=\n-----END TSS2 PRIVATE KEY-----\n",
"parentName": "000b8b6e4856595f2a27e663f7b727cfd9ae6f4ab085d8548f785b7ae8f11a107c06"
}
### import
$ go run direct/import/main.go -in /tmp/out.json \
-out /tmp/key.pem -tpm-path "127.0.0.1:2321"
$ cat /tmp/key.pem
-----BEGIN TSS2 PRIVATE KEY-----
MIIBCwYGZ4EFCgEDoAMBAf8CBQCAAAABBFIAUAAIAAsABAAAACA5j3CpkTa2o/dV
MvO0QSNAjwKZUmmn9o/bAWlpPXMDYAAFAAsAIE1UrKKNAGtyjMUXvFb4/xdC8CaE
/tlocqTCOiSjORZ6BIGgAJ4AIIH39gnyjK0B/SM8WzscKpgzvWXD92h+wBoM7ha1
YrWVABChCu4bQTtNOSPmYD4uX3CjNFc5BCr2vgRngTUdz74dCY3CZNCvRU9/VYAq
++q8lVZP1nHBZxK0m2vllJJHO56HnFUCcJ5hZKCaNbyUbWZ4LJi/9WoaaRtFONIE
5APNOKtWvcb/s9rqXkfStVNTXF56/AE0/HoFegzHbA==
-----END TSS2 PRIVATE KEY-----
### use the key to run hmac
$ go run hmac/password/main.go --pemFile=/tmp/key.pem -tpm-path "127.0.0.1:2321"
2025/11/24 22:27:38 Hmac: 7c50506d993b4a10e5ae6b33ca951bf2b8c8ac399e0a34026bb0ac469bea3de2To transfer an key which is NOT bound by a policy, set --skipPolicy parameter on duplicate
### Local
openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:65537 -out /tmp/key_rsa.pem
### TPM-B
export TPMB="/dev/tpmrm0" # TPMB="127.0.0.1:2321"
tpmcopy --mode publickey --parentKeyType=rsa_ek -tpmPublicKeyFile=/tmp/public.pem --tpm-path=$TPMB
### copy public.pem to Local
### local
tpmcopy --mode duplicate --keyType=rsa --secret=/tmp/key_rsa.pem --rsaScheme=rsassa --skipPolicy \
--hashScheme=sha256 -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
### copy /tmp/out.json to TPM-B
### TPM-B
tpmcopy --mode import --parentKeyType=rsa_ek \
--in=/tmp/out.json --out=/tmp/tpmkey.pem \
--pubout=/tmp/pub.dat --privout=/tmp/priv.dat --tpm-path=$TPMB
### test
cd example/
go run rsa/skipPolicy/main.go --pemFile=/tmp/tpmkey.pem --tpm-path=$TPMB
### with tpm2_tools
tpm2_createek -c ek.ctx -G rsa -u ek.pub
tpm2 startauthsession --session session.ctx --policy-session
tpm2 policysecret --session session.ctx --object-context endorsement
tpm2_load -C ek.ctx -c key.ctx -u /tmp/pub.dat -r /tmp/priv.dat --auth session:session.ctx
echo -n "foo" > /tmp/file.txt
tpm2_sign -c key.ctx -g sha256 -f plain -o sig.rss /tmp/file.txtEach key that is exported to TPM-B is bound using TPM Policies which ensure the key cannot be duplicated further.
The specific base policy applied is PolicyDuplicateSelect which ensures the key can only exist on the target TPM and cannot get exported further. For more information, see Transfer TPM based key using PCR policy
Furthermore, they key will be bound using tpm2_policyauthvalue for password and tpm2_policypcr for PCR.
Since the key is always bound via policy, the UserWithAuth flag is always CLEAR (false)
"UserWithAuth: this attribute refers to key use policy and indicates that the object's authValue may be used to provide the USER role authorizations for the object. If this attribute is CLEAR, then USER role authorizations may only be provided by satisfying the object's authPolicy in a policy session. Refer to section 3.10 for more details."
Essentially, when you use the duplicated key on the destination, you need to replay
-
Password:
tpm2_policyor(tpm2_policyauthvalue, tpm2_policyduplicateselect)and specify the finalPolicySessionwith the passphrase -
PCR:
tpm2_policyor(tpm2_policypcr, tpm2_policyduplicateselect)
and when the parent is loaded, since by default its the RSA or ECC Endorsement, you need to use tpm2_policysecret
To help with construction of the policy session in go, you can use the utility functions here:
Password
import (
tpmcopy "github.com/salrashid123/tpmcopy"
)
// for password and with the parent name as primaryKey.Name:
tc, err := tpmcopy.NewPolicyAuthValueAndDuplicateSelectSession(rwr, []byte(*password), primaryKey.Name, primaryKey.ObjectHandle)
or_sess, or_cleanup, err := tc.GetSession()
defer or_cleanup()PCR
import (
tpmcopy "github.com/salrashid123/tpmcopy"
)
// for pcr's bound to bank 23 and with the parent name as primaryKey.Name:
se, err := tpmcopy.NewPCRAndDuplicateSelectSession(rwr, []tpm2.TPMSPCRSelection{
{
Hash: tpm2.TPMAlgSHA256,
PCRSelect: tpm2.PCClientCompatible.PCRs(uint(23)),
},
}, nil, primaryKey.Name, primaryKey.ObjectHandle)
or_sess, or_cleanup, err := se.GetSession()
defer or_cleanup()For python, you will need to implement both policies as shown here
If you want to bind the key to a passphrase
### local, generate RSA-SSA key
openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:65537 -out /tmp/key_rsa.pem
### TPM-B
export TPMB="/dev/tpmrm0"
tpmcopy --mode publickey --parentKeyType=rsa_ek -tpmPublicKeyFile=/tmp/public.pem --tpm-path=$TPMB
# Alternatively, you can use `tpm2_tools`:
# tpm2_createek -c /tmp/ek.ctx -G rsa -u /tmp/ek.pub
# tpm2_readpublic -c /tmp/ek.ctx -o /tmp/public.pem -f PEM -n /tmp/ek.name
# ## or extract the ekcert x509
# tpm2_getekcertificate -X -o EKCert.bin
# openssl x509 -in EKCert.bin -inform DER -noout -text
# copy `public.pem` to `local`
### local
tpmcopy --mode duplicate --secret=/tmp/key_rsa.pem --keyType=rsa \
--password=bar -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
# copy `/tmp/out.json` to `TPM-B`
## TPM-B
tpmcopy --mode import --parentKeyType=rsa_ek --in=/tmp/out.json --out=/tmp/tpmkey.pem --tpm-path=$TPMB
cd example/
go run rsa/password/main.go --pemFile=/tmp/tpmkey.pem --password=bar --tpm-path=$TPMBIf you wanted to use a PCR policy like one that enforces that to use the key TPM-B must have pcr 23=f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b
## TPM-B
tpmcopy --mode publickey --parentKeyType=rsa_ek -tpmPublicKeyFile=/tmp/public.pem --tpm-path=$TPMB
### copy `public.pem` to `Local`
$ tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
$ tpm2_pcrread sha256:23
sha256:
23: 0x0000000000000000000000000000000000000000000000000000000000000000
$ tpm2_pcrextend 23:sha256=0x0000000000000000000000000000000000000000000000000000000000000000
$ tpm2_pcrread sha256:23
sha256:
23: 0xF5A5FD42D16A20302798EF6ED309979B43003D2320D9F0E8EA9831A92759FB4B
### local
tpmcopy --mode duplicate --keyType=rsa \
--secret=/tmp/key_rsa.pem --pcrValues=23:f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b \
-tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
# copy `/tmp/out.json` to `TPM-B`
tpmcopy --mode import --in=/tmp/out.json --out=/tmp/tpmkey.pem --tpm-path=$TPMB
### test
cd example
### sign directly
go run rsa/pcr/main.go --pemFile=/tmp/tpmkey.pem --tpm-path=$TPMB
### using crypto.Signer
go run rsa/signer_pcr/main.go --pemFile=/tmp/tpmkey.pem --tpm-path=$TPMBThe examples above all use RSAEK parent, if you want to generate and use an EK ECC parent
tpmcopy --mode publickey --parentKeyType=ecc_ek \
-tpmPublicKeyFile=/tmp/public.pem --tpm-path=$TPMB
tpmcopy --mode duplicate --secret=/tmp/key_rsa.pem \
--keyType=rsa --password=bar -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
tpmcopy --mode import --parentKeyType=ecc_ek \
--in=/tmp/out.json --out=/tmp/tpmkey.pem --tpm-path=$TPMB
cd example/
go run rsa/password/main.go --pemFile=/tmp/tpmkey.pem \
--password=bar --parentKeyType=ecc_ek --tpm-path=$TPMBThe examples above all use EK RSA/ECC parent, if you want to use the H2 profile
tpmcopy --mode publickey --parentKeyType=h2 \
-tpmPublicKeyFile=/tmp/public.pem --tpm-path=$TPMB
tpmcopy --mode duplicate --parentKeyType=h2 --secret=/tmp/key_rsa.pem \
--keyType=rsa --password=bar -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
tpmcopy --mode import --parentKeyType=h2 \
--in=/tmp/out.json --out=/tmp/tpmkey.pem --pubout=/tmp/pub.dat --privout=/tmp/priv.dat \
--tpm-path=$TPMB
cd example/
go run rsa/persistent_h2_parent/main.go --pemFile=/tmp/tpmkey.pem \
--password=bar --tpm-path=$TPMBIf you want to use the storage root key as the parent, see
### RSA_SRK
#### see go-tpm.tpm2.RSASRKTemplate https://github.com/google/go-tpm/blob/main/tpm2/templates.go#L6
#### pg 26: https://trustedcomputinggroup.org/wp-content/uploads/TCG-TPM-v2.0-Provisioning-Guidance-Published-v1r1.pdf
#### pg 43: B.3.3 Template L-1: RSA 2048 (Storage) https://trustedcomputinggroup.org/wp-content/uploads/TCG-EK-Credential-Profile-for-TPM-Family-2.0-Level-0-Version-2.6_pub.pdf
printf '\x00\x01' > ud.1
dd if=/dev/zero bs=256 count=1 of=ud.2
cat ud.1 ud.2 > unique.dat
tpm2_createprimary -C o -u unique.dat \
-G rsa2048 -g sha256 -c primary.ctx --attributes="fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda|restricted|decrypt" -Q
tpm2_readpublic -c primary.ctx -o rsa_srk.pem -f PEM
tpm2_flushcontext -t
### for ECC_SRK
# printf '\x20\x00' > ud.1
# dd if=/dev/zero bs=128 count=1 of=ud.2
# cat ud.1 ud.2 ud.1 ud.2 > unique.dat
# tpm2_createprimary -C o -G ecc256 -g sha256 -c primary.ctx -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda|restricted|decrypt" -u unique.dat
# tpm2_readpublic -c primary.ctx -o ecc_srk.pem -f PEM -Q
# tpm2_flushcontext -t
# cat ecc_srk.pem
## or
go run cmd/main.go --mode publickey --parentKeyType=rsa_srk -tpmPublicKeyFile=/tmp/rsa_srk.pem --tpm-path=$TPMB
# echo -n "46be0927a4f86577f17ce6d10bc6aa61" > /tmp/aes.key
go run cmd/main.go --mode duplicate --parentKeyType=rsa_srk --keyType=aes --aesScheme=cfb --keySize=128 --secret=/tmp/aes.key \
--password=bar -tpmPublicKeyFile=/tmp/rsa_srk.pem -out=/tmp/out.json
### copy /tmp/out.json to TPM-B
### TPM-B
go run cmd/main.go --mode import --parentKeyType=rsa_srk --in=/tmp/out.json --out=/tmp/tpmkey.pem --tpm-path=$TPMB
### test
cd example/
go run aes/srk/main.go --pemFile=/tmp/tpmkey.pem --password=bar --tpm-path=$TPMBAlternatively, if you want to SkipPolicy
go run cmd/main.go --mode duplicate --parentKeyType=rsa_srk --skipPolicy --keyType=aes --aesScheme=cfb --keySize=128 --secret=/tmp/aes.key \
--password=bar -tpmPublicKeyFile=/tmp/rsa_srk.pem -out=/tmp/out.json
### copy /tmp/out.json to TPM-B
### TPM-B
go run cmd/main.go --mode import --parentKeyType=rsa_srk --in=/tmp/out.json --out=/tmp/tpmkey.pem --tpm-path=$TPMB
### test
cd example/
go run aes/skipPolicy/main.go --pemFile=/tmp/tpmkey.pem --password=bar --tpm-path=$TPMBIf you wanted to use tpm2_tools on the key imported to TPM-B, then use the --pubout= and --privout= parameters when importing.
What that'll do is save the key as [TPM2B_PUBLIC, TPM2B_PRIVATE]
For example, the follwoing will import the password or pcr policy encoded files and use tpm2_tools to perform further operations.
on TPM-B, save the ek (and optionallhy as a persistent handle)
cd /tmp/
tpm2_createek -c ek.ctx -G rsa -u ek.pub
tpm2_readpublic -c ek.ctx -o ek.pem -f PEM -n ek.nametransfer the key using ek.pem from local then when running import on TPM-B, specify the output pub/private part
tpmcopy --mode import --parentKeyType=rsa_ek \
--pubout=/tmp/pub.dat --privout=/tmp/priv.dat --in=/tmp/out.json \
--out=/tmp/tpmkey.pem --tpm-path=$TPMBIf the key had a policy password:
### load
cd /tmp/
tpm2 flushcontext -t
tpm2 startauthsession --session session.ctx --policy-session
tpm2 policysecret --session session.ctx --object-context endorsement
tpm2_load -C ek.ctx -c key.ctx -u pub.dat -r priv.dat --auth session:session.ctx
## regenerate the full policy
tpm2_startauthsession -S sessionA.dat --policy-session
tpm2_policyduplicationselect -S sessionA.dat -N ek.name -L policyA_dupselect.dat
tpm2_flushcontext sessionA.dat
rm sessionA.dat
tpm2_startauthsession -S sessionA.dat --policy-session
tpm2_policyauthvalue -S sessionA.dat -L policyA_auth.dat
echo -n foo > /tmp/file.txt
tpm2_policyor -S sessionA.dat -L policyA_or.dat sha256:policyA_auth.dat,policyA_dupselect.dat
tpm2_sign -c key.ctx -g sha256 -f plain -p"session:sessionA.dat+bar" -o sig.rss /tmp/file.txtIf the key had a pcr policy
### load
cd /tmp/
tpm2 flushcontext -t
tpm2 startauthsession --session session.ctx --policy-session
tpm2 policysecret --session session.ctx --object-context endorsement
tpm2_load -C ek.ctx -c key.ctx -u pub.dat -r priv.dat --auth session:session.ctx
## regenerate the full policy
tpm2_startauthsession -S sessionA.dat --policy-session
tpm2_policyduplicationselect -S sessionA.dat -N ek.name -L policyA_dupselect.dat
tpm2_flushcontext sessionA.dat
rm sessionA.dat
tpm2_startauthsession -S sessionA.dat --policy-session
tpm2_policypcr -S sessionA.dat -l "sha256:23" -f pcr23_valA.bin -L policyA_pcr.dat
tpm2_policyor -S sessionA.dat -L policyA_or.dat sha256:policyA_pcr.dat,policyA_dupselect.dat
### test sign
echo -n foo >/tmp/file.txt
tpm2_sign -c key.ctx -g sha256 -f plain -o signB.raw /tmp/file.txt -p "session:sessionA.dat"
rm sessionA.datFor an H2 primary, the steps to sign with password would be
# ## create H2 Template
printf '\x00\x00' > /tmp/unique.dat
tpm2_createprimary -C o -G ecc -g sha256 \
-c primary.ctx \
-a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda|restricted|decrypt" -u /tmp/unique.dat
tpm2_readpublic -c /tmp/primary.ctx -o /tmp/public.pem -f PEM -n /tmp/primary.name
tpm2 flushcontext -t
tpm2_load -C /tmp/primary.ctx -c /tmp/key.ctx -u /tmp/pub.dat -r /tmp/priv.dat
## regenerate the full policy
tpm2_startauthsession -S sessionA.dat --policy-session
tpm2_policyduplicationselect -S sessionA.dat -N/tmp/primary.name -L policyA_dupselect.dat
tpm2_flushcontext sessionA.dat
rm sessionA.dat
tpm2_startauthsession -S sessionA.dat --policy-session
tpm2_policyauthvalue -S sessionA.dat -L policyA_auth.dat
echo -n "foo" > /tmp/file.txt
tpm2_policyor -S sessionA.dat -L policyA_or.dat sha256:policyA_auth.dat,policyA_dupselect.dat
tpm2_sign -c key.ctx -g sha256 -f plain -p"session:sessionA.dat+bar" -o sig.rss /tmp/file.txtIf you want to encode the PEM key with a preset persistent handle parent, then during import specify the -parentpersistentHandle= flag:
For example, the following will create a key on TPM-B and persist it to 0x81008001.
From there, you can import the key and and encode the parent into the PEM file directly
## TPM-B
tpm2_getcap handles-persistent
tpm2_evictcontrol -C o -c 0x81008001
tpm2_createek -c /tmp/ek.ctx -G rsa -u /tmp/ek.pub
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
tpm2_evictcontrol -c /tmp/ek.ctx 0x81008001
tpm2_readpublic -c /tmp/ek.ctx -o /tmp/public.pem -f PEM -n ek.name -Q
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
## Local
tpmcopy --mode duplicate --secret=/tmp/key_rsa.pem --keyType=rsa \
--password=bar -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
## TPM-B
tpmcopy --mode import --parentKeyType=rsa_ek --password=bar \
--in=/tmp/out.json --pubout=/tmp/pub.dat --privout=/tmp/priv.dat \
--out=/tmp/tpmkey.pem --parentpersistentHandle=0x81008001 --tpm-path=$TPMB
$ openssl asn1parse -in /tmp/tpmkey.pem
0:d=0 hl=4 l= 565 cons: SEQUENCE
4:d=1 hl=2 l= 6 prim: OBJECT :2.23.133.10.1.3
12:d=1 hl=2 l= 3 cons: cont [ 0 ]
14:d=2 hl=2 l= 1 prim: BOOLEAN :255
17:d=1 hl=2 l= 5 prim: INTEGER :81008001 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
24:d=1 hl=4 l= 314 prim: OCTET STRING [HEX DUMP]:01380001000B0004000000207487CF644F9B7D548C7CEF7D...
342:d=1 hl=3 l= 224 prim: OCTET STRING [HEX DUMP]:00DE0020742AC11B...then run the following sample: note that the "parent" is read in from the PEM file and initialized automatically
cd example/
go run rsa/persistent_parent/main.go --pemFile=/tmp/tpmkey.pem --password=bar --tpm-path=$TPMBIf you want to persist the actual key into NV:
# tpm-b
tpmcopy --mode publickey --parentKeyType=rsa_ek -tpmPublicKeyFile=/tmp/public.pem --tpm-path=$TPMB
# local
tpmcopy --mode duplicate \
--secret=/tmp/key_rsa.pem --keyType=rsa \
--password=bar -tpmPublicKeyFile=/tmp/public.pem \
-out=/tmp/out.json
# tpm-b
tpmcopy --mode import \
--pubout=/tmp/pub.dat --privout=/tmp/priv.dat --in=/tmp/out.json \
--out=/tmp/tpmkey.pem --tpm-path=$TPMB
### then load
tpmcopy --mode evict \
--persistentHandle=0x81008001 \
--in=/tmp/tpmkey.pem --tpm-path=$TPMB
## or using tpm2_tools:
# tpm2_createek -c ek.ctx -G rsa -u ek.pub
# tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
# tpm2 startauthsession --session session.ctx --policy-session
# tpm2 policysecret --session session.ctx --object-context endorsement
# tpm2_load -C ek.ctx -c key.ctx -u pub.dat -r priv.dat --auth session:session.ctx
# tpm2_evictcontrol -c key.ctx 0x81008001
go run rsa/persistent_key/main.go --persistentHandle=0x81008001 --password=bar --tpm-path=$TPMBNote that while openssl does have a tpm2 provider, the default CLI does not support complex policy statements bound to keys.
For example, with openssl is limited to basic auth constructors as described [here]](https://github.com/tpm2-software/tpm2-openssl/blob/master/docs/keys.md)
Since default keys transferred by this utility uses more complex policies, you can't easily really use openssl (but you can use tpm2_tools).
If you did not use the default policies by setting the --skipPolicy and the h2 template, then some basic openssl operations are possible
export TPM2TOOLS_TCTI="swtpm:port=2321"
export TPM2OPENSSL_TCTI="swtpm:port=2321"
openssl list --providers -provider tpm2
Providers:
tpm2
name: TPM 2.0 Provider
version: 1.3.0
status: active
tpmcopy --mode publickey --parentKeyType=h2 \
-tpmPublicKeyFile=/tmp/public.pem --tpm-path=$TPMB
tpmcopy --mode duplicate --parentKeyType=h2 --secret=/tmp/key_rsa.pem --skipPolicy \
--keyType=rsa -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
tpmcopy --mode import --parentKeyType=h2 \
--in=/tmp/out.json --out=/tmp/tpmkey.pem --pubout=/tmp/pub.dat --privout=/tmp/priv.dat \
--tpm-path=$TPMB
### assume tpmkey.pem is an rsa key with password using the H2 primary
openssl asn1parse -in /tmp/tpmkey.pem
openssl rsa -provider tpm2 -provider default -in /tmp/tpmkey.pem -text
## test signature
cd example/
go run rsa/skipPolicy/main.go --pemFile=/tmp/tpmkey.pem --tpm-path=$TPMB --parentKeyType=h2
echo -n "foo" >/tmp/data.txt
openssl dgst -sha256 -binary -out /tmp/data.hash /tmp/data.txt
openssl pkeyutl -provider tpm2 -provider default \
-sign -inkey /tmp/tpmkey.pem -in /tmp/data.hash -out /tmp/signature.sigEach operation uses encrypted sessions by default and interrogates the TPM for the current EK directly.
If for whatever reason you want to specify the "name" of the EK to to use, set the --tpm-session-encrypt-with-name= parameter shown below
# for tpmB
tpm2_createek -c /tmp/primaryB.ctx -G rsa -Q
tpm2_readpublic -c /tmp/primaryB.ctx -o /tmp/ekpubB.pem -n /tmp/ekpubBname.bin -f PEM -Q
xxd -p -c 100 /tmp/ekpubBname.bin
000b47ab97fdda365cbb86a37548e38468f72e8baccc633cffc42402183679956608
# Then use the hex value returned in the --tpm-session-encrypt-with-name= argument.
--tpm-session-encrypt-with-name=000b47ab97fdda365cbb86a37548e38468f72e8baccc633cffc42402183679956608This utility encodes the key to transfer as protobuf during the Duplicate() step
syntax = "proto3";
package duplicatepb;
option go_package = "github.com/salrashid123/go-tpm-wrapping/tpmwrappb";
message Secret {
string name = 1;
int32 version = 2;
KeyType type = 3;
enum KeyType {
ECC = 0;
RSA = 1;
HMAC = 2;
AES = 3;
KEYEDHASH = 4;
}
ParentKeyType parentKeyType = 4;
enum ParentKeyType {
EndoresementECC = 0;
EndorsementRSA = 1;
H2 = 2;
OwnerECC = 3;
OwnerRSA = 4;
}
repeated PCRS pcrs = 5;
string key = 6;
string parentName = 7;
}
message PCRS {
int32 pcr = 1;
bytes value = 2;
}So an output file may look like:
{
"version": 1,
"type": "RSA",
"parentKeyType": "EndorsementRSA",
"key": "-----BEGIN TSS2 PRIVATE KEY-----\nMIIDowYGZ4EFCgEEoYGWMIGTMAqgBAICAWuhAgQAMDGgBAICAYihKQQnAAAAIgAL\nTTWiK01Z+KGkuImOvdG/WUm/oz/Lcb2Z4Jhmyw1YOEsAMFKgBAICAXGhSgRIAAAA\nAgAgj80haauSaU4MYz8at3KEK4JBu8ICiJgfx6we3cH92w4AIG4KC9eaWaph5FAK\nm5HsPBnfHpV1KLWu/ngsdFGgGmuyooIBBgSCAQIBAMOl4GvDGXWAz2Z3W/NNwjd9\n1dFnqKD4FMtm1TlVsptk1hVSdzZ6C0cut3u15LiekeJZwWmFpOyiuJr/lV3cIjKv\naUlq+a3DjcvBPhcYC8Y20J+JFsLujekDOnrDzc6OrTvM8qoXMLJenYmwCAHtdN+0\nH/5s5SeZpDsVCOZZWDfRJLh/F3oM5f5R1VRElyHrx7rbrduLgkqh5j7kCAnC+fet\n1IpSSW55CiwecyHq7ewqqjH9pXLwrMu5DTxUr4OLiuQQD+JISFyLWZI8E06HqzMh\nXT1vyU9J6aQ+hIUQdbFvh639+QyCj/SL3tdqW59/nHbwfxm8MeQxG9Sx0/fPiLkC\nBEAAAUAEggE6ATgAAQALAAQAAAAgtzGhqUcZ8m14fqMMDjocDbzpInzeMioNYjn1\nVKVXqI0AEAAUAAsIAAABAAEBAOopWu7BnpqZMH04VfA6o2SXtlrGHSMPUBducP26\n+eTTPXy0Y4fHOw/qWyYsnzLCcySiZ1sM/vx1mUcQLeyf/u6y1FRPAdv1RX+Bzzvm\nAwnSqyttFqOwfUnu1AFLh7MR/wwqgGL2iBTHuDbXPtzK2IrjqevTwnfLJke9dW4K\nSWdxcEPxMz1mUdV0N4wgIw7NeDp3R8vRS+6MY9IgRiepuZjgOWkjRG50wCw60By1\nujsOrvG6JIFxb2yXHFJ7XyY7r/cgkA0pWUeTKemNMSTPNyEpHlusKi166RwuFI9O\nVI2aS/ME5dsNPJGGuuzwcTK59AZzgwYuNK2lMU2w4fLXGqcEgbEArwAgm/YdhGaF\nigcO0yJEqphb9bitPf8ZJ7DbicHeOt6shx4hTyDG6hgT/RVwMjPN5wRgRZuZfcKR\n0V67QDN9elXn0grU4vk3uDulNP+bePVPHmDE3dJ8kZUp4VYn167PFStPu7+r+okl\nuOAKCjfy71yu6OG73epxdzIXvuTAjuY/zc1AKZqeSonTWHZq4R2whynIpSDFZ6Jh\nehLs1g4RBZpyUQ1PItng8mHJl1Q10OY=\n-----END TSS2 PRIVATE KEY-----\n",
"parentName": "000b4d35a22b4d59f8a1a4b8898ebdd1bf5949bfa33fcb71bd99e09866cb0d58384b"
}where the parentName is actually the duplicating parents 'name' on TPM-B:
$ xxd -p -c 100 /tmp/ek.name
000bbc0c7f8b565f09e4614624fa6f46ece235c9904d47050e8a8dd466ac9b96d49bAs mentioned, the Import() function saves the imported using in two ways:
-
--out=parameter saves the imported key as ASN.1 Specification for TPM 2.0 Key Files which is the format openssl (mostly) follows. However, to use this you need to specify the parent as the endorsement RSA key and not the H2 tepmplate. -
--pubout=and--privout=parameters saves they key in raw formats which can be used withtpm2_tools
If you want to encode the policies into the PEM file based on the draft ASN.1 Specification for TPM 2.0 Key Files, then set ENABLE_POLICY_SYNTAX environment variable to any value during the duplicate and import steps.
Please note that it the specs are still draft and is incompatible with the PEM format used by openssl
Anyway, the big advantage of this encoding is the PEM file describes the steps to generate the policy itself and execute them.
For example, see the link here on how to manually generate the policies and use policySyntax utility.
In the following note that the same codebase will execute the both types of policies in keyfile_policy/main.go:
- PolicyAuthValue
For auth value, the following will generate a key with the syntax variables already baked in
export ENABLE_POLICY_SYNTAX=1
tpmcopy --mode publickey --parentKeyType=rsa_ek \
-tpmPublicKeyFile=/tmp/public.pem --tpm-path=$TPMB
tpmcopy --mode duplicate \
--keyType=aes --secret=/tmp/aes.key \
--password=bar -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
tpm2_evictcontrol -c 0x81008000
tpmcopy --mode import \
--parentKeyType=rsa_ek --in=/tmp/out.json --out=/tmp/tpmkey_auth.pem --tpm-path=$TPMB
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
cd example/
go run keyfile_policy/main.go --pemFile=/tmp/tpmkey_auth.pem --tpm-path=$TPMB --password=bar- PolicyPCR
export ENABLE_POLICY_SYNTAX=1
tpmcopy --mode publickey --parentKeyType=rsa_ek \
-tpmPublicKeyFile=/tmp/public.pem --tpm-path=$TPMB
tpmcopy --mode duplicate --keyType=aes --secret=/tmp/aes.key \
--pcrValues=23:f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b \
-tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
tpmcopy --mode import --parentKeyType=rsa_ek --in=/tmp/out.json --out=/tmp/tpmkey_pcr.pem --tpm-path=$TPMB
cd example/
go run keyfile_policy/main.go --pemFile=/tmp/tpmkey_pcr.pem --tpm-path=$TPMBthe specific PEM files generated has the polices encode into it itself.
Note that the command code for PolicyDuplicateSelect=0x00000188, TPMCCPolicyOR=0x00000171, TPMCCPolicyPCR=0x0000017F
for authvalue
$ openssl asn1parse -in /tmp/tpmkey_auth.pem
0:d=0 hl=4 l= 406 cons: SEQUENCE
4:d=1 hl=2 l= 6 prim: OBJECT :2.23.133.10.1.3
12:d=1 hl=2 l= 3 cons: cont [ 0 ]
14:d=2 hl=2 l= 1 prim: BOOLEAN :255
17:d=1 hl=3 l= 150 cons: cont [ 1 ]
20:d=2 hl=3 l= 147 cons: SEQUENCE
23:d=3 hl=2 l= 10 cons: SEQUENCE
25:d=4 hl=2 l= 4 cons: cont [ 0 ]
27:d=5 hl=2 l= 2 prim: INTEGER :016B
31:d=4 hl=2 l= 2 cons: cont [ 1 ]
33:d=5 hl=2 l= 0 prim: OCTET STRING
35:d=3 hl=2 l= 49 cons: SEQUENCE
37:d=4 hl=2 l= 4 cons: cont [ 0 ]
39:d=5 hl=2 l= 2 prim: INTEGER :0188
43:d=4 hl=2 l= 41 cons: cont [ 1 ]
45:d=5 hl=2 l= 39 prim: OCTET STRING [HEX DUMP]:00000022000B75CE518FE809BFF11C7C3575FB50B943F9EFC3E4C3E0FA4AC3AD796D7DF66DE700
86:d=3 hl=2 l= 82 cons: SEQUENCE
88:d=4 hl=2 l= 4 cons: cont [ 0 ]
90:d=5 hl=2 l= 2 prim: INTEGER :0171
94:d=4 hl=2 l= 74 cons: cont [ 1 ]
96:d=5 hl=2 l= 72 prim: OCTET STRING [HEX DUMP]:0000000200208FCD2169AB92694E0C633F1AB772842B8241BBC20288981FC7AC1EDDC1FDDB0E0020E6613C6F3F14B6A9C8613FA7D2766BAB170C6E477BB047C5E10928DA897FCB1D
170:d=1 hl=2 l= 5 prim: INTEGER :81008000
177:d=1 hl=2 l= 84 prim: OCTET STRING [HEX DUMP]:00520025000B000600000020B27A9BE905FD3C543969DF3965EA3B62F554DCB20681BC484E90FAF03FA6E04300060080004300206D1078F0CF8B17C99CD183C71D3E0F29F62FB655B97EC1135832EAFDDB795FF7
263:d=1 hl=3 l= 144 prim: OCTET STRING [HEX DUMP]:008E0020F99928C2177F50253A7F8568EC7B14CB1A39C538B3CF4AC83A031257857355EE0010E7A442207E6488A97D046687B925135F5A4F579FA4E4120A2BC274B568DA75EAF2D24299EA17EF2B3132EF39BB64FB9CFF83E772B1FEF2916D0BB3283322B7A4EC809DB0F5229232C5D8EA4A858AADC17D8889A7327A589DFE9560C335D843C725CD21ACD441ED8ACA17for PCR:
$ openssl asn1parse -in /tmp/tpmkey_pcr.pem
0:d=0 hl=4 l= 450 cons: SEQUENCE
4:d=1 hl=2 l= 6 prim: OBJECT :2.23.133.10.1.3
12:d=1 hl=2 l= 3 cons: cont [ 0 ]
14:d=2 hl=2 l= 1 prim: BOOLEAN :255
17:d=1 hl=3 l= 194 cons: cont [ 1 ]
20:d=2 hl=3 l= 191 cons: SEQUENCE
23:d=3 hl=2 l= 54 cons: SEQUENCE
25:d=4 hl=2 l= 4 cons: cont [ 0 ]
27:d=5 hl=2 l= 2 prim: INTEGER :017F
31:d=4 hl=2 l= 46 cons: cont [ 1 ]
33:d=5 hl=2 l= 44 prim: OCTET STRING [HEX DUMP]:0020E2F61C3F71D1DEFD3FA999DFA36953755C690689799962B48BEBD836974E8CF900000001000B03000080
79:d=3 hl=2 l= 49 cons: SEQUENCE
81:d=4 hl=2 l= 4 cons: cont [ 0 ]
83:d=5 hl=2 l= 2 prim: INTEGER :0188
87:d=4 hl=2 l= 41 cons: cont [ 1 ]
89:d=5 hl=2 l= 39 prim: OCTET STRING [HEX DUMP]:00000022000B75CE518FE809BFF11C7C3575FB50B943F9EFC3E4C3E0FA4AC3AD796D7DF66DE700
130:d=3 hl=2 l= 82 cons: SEQUENCE
132:d=4 hl=2 l= 4 cons: cont [ 0 ]
134:d=5 hl=2 l= 2 prim: INTEGER :0171
138:d=4 hl=2 l= 74 cons: cont [ 1 ]
140:d=5 hl=2 l= 72 prim: OCTET STRING [HEX DUMP]:0000000200202094289099C2CB180F28F99C71C8D681123935F7330BDAE5AA1AE1E09F0FE5320020E6613C6F3F14B6A9C8613FA7D2766BAB170C6E477BB047C5E10928DA897FCB1D
214:d=1 hl=2 l= 5 prim: INTEGER :81008000
221:d=1 hl=2 l= 84 prim: OCTET STRING [HEX DUMP]:00520025000B000600000020114DE1F5BD4B2EC1AA51DE81CA4CEE5EB7B34FD338DCFB0D635F7F65DB56DBF80006008000430020237668CD3AF2827B9A590B32EAA8056226DB1C0D89000E403845AE13C4E35240
307:d=1 hl=3 l= 144 prim: OCTET STRING [HEX DUMP]:008E002034CC17FD41CE5414923D8C75624E746276809068E34EF06A2DBBC933004A2E900010EEDBD95BE8D7746EF004BC0DA7CE289B3EEC0FCDC969ADD1D3DC4122FC79BF72F02D2DD9DE11171767FF3979ABA236BC8BF27914B682AFDA920802CD10297594E1A5094A9936AE6CAFE16DDCE1170E65F7A819B1310F8378641DCEF141E3592701D3D80CB35FDC16FB12If you want to test locally with a software TPM
- Start
TPM-B
## TPMB
rm -rf /tmp/myvtpm && mkdir /tmp/myvtpm
/usr/share/swtpm/swtpm-create-user-config-files
swtpm_setup --tpmstate /tmp/myvtpm --tpm2 --create-ek-cert
swtpm socket --tpmstate dir=/tmp/myvtpm --tpm2 --server type=tcp,port=2321 --ctrl type=tcp,port=2322 --flags not-need-init,startup-clear --log level=2
## in new window
export TPM2TOOLS_TCTI="swtpm:port=2321"
export TPMB="127.0.0.1:2321"
$ tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
$ tpm2_pcrread sha256:23
sha256:
23: 0x0000000000000000000000000000000000000000000000000000000000000000
$ tpm2_pcrextend 23:sha256=0x0000000000000000000000000000000000000000000000000000000000000000
$ tpm2_pcrread sha256:23
sha256:
23: 0xF5A5FD42D16A20302798EF6ED309979B43003D2320D9F0E8EA9831A92759FB4B
## export the ekPub
### derive the RSA EK
tpm2_createek -c /tmp/ek.ctx -G rsa -u /tmp/ek.pub
tpm2_readpublic -c /tmp/ek.ctx -o /tmp/ek.pem -f PEM -n ek.name -Q
tpm2_getekcertificate -X -o EKCert.bin
openssl x509 -in EKCert.bin -inform DER -noout -textTo run all the examples:
export TPMB="127.0.0.1:2321"
export TPM2TOOLS_TCTI="swtpm:port=2321"
### TPM-B make sure the pcr value is 0xF5A5FD42D16A20302798EF6ED309979B43003D2320D9F0E8EA9831A92759FB4B
### tpm2_pcrextend 23:sha256=0x0000000000000000000000000000000000000000000000000000000000000000
tpm2_pcrread sha256:23
### RSA
tpmcopy --mode publickey --parentKeyType=rsa_ek -tpmPublicKeyFile=/tmp/public.pem --tpm-path=$TPMB
# openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:65537 -out /tmp/key_rsa.pem
tpmcopy --mode duplicate --secret=/tmp/key_rsa.pem --keyType=rsa \
--password=bar -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
tpmcopy --mode import --parentKeyType=rsa_ek --in=/tmp/out.json --out=/tmp/tpmkey.pem --tpm-path=$TPMB
cd example/
go run rsa/password/main.go --pemFile=/tmp/tpmkey.pem --password=bar --tpm-path=$TPMB
cd ..
### pcr
tpmcopy --mode duplicate --keyType=rsa --secret=/tmp/key_rsa.pem \
--pcrValues=23:f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b \
-tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
tpmcopy --mode import --parentKeyType=rsa_ek --in=/tmp/out.json --out=/tmp/tpmkey.pem --tpm-path=$TPMB
cd example/
go run rsa/pcr/main.go --pemFile=/tmp/tpmkey.pem --tpm-path=$TPMB
go run rsa/signer_pcr/main.go --pemFile=/tmp/tpmkey.pem --tpm-path=$TPMB
cd ..
### ECC
# openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 -out /tmp/key_ecc.pem
tpmcopy --mode duplicate --keyType=ecc --secret=/tmp/key_ecc.pem \
--password=bar -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
tpmcopy --mode import --parentKeyType=rsa_ek --in=/tmp/out.json --out=/tmp/tpmkey.pem --tpm-path=$TPMB
cd example/
go run ecc/password/main.go --pemFile=/tmp/tpmkey.pem --password=bar --tpm-path=$TPMB
cd ..
### AES
# echo -n "46be0927a4f86577f17ce6d10bc6aa61" > /tmp/aes.key
tpmcopy --mode duplicate --keyType=aes --aesScheme=cfb --keySize=128 --secret=/tmp/aes.key \
--password=bar -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
tpmcopy --mode import --parentKeyType=rsa_ek --in=/tmp/out.json --out=/tmp/tpmkey.pem --password=bar --tpm-path=$TPMB
cd example/
go run aes/password/main.go --pemFile=/tmp/tpmkey.pem --password=bar --tpm-path=$TPMB
cd ..
### HMAC
# echo -n "change this password to a secret" > /tmp/hmac.key
tpmcopy --mode duplicate --keyType=hmac --hashScheme=sha256 --secret=/tmp/hmac.key \
--password=bar -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
tpmcopy --mode import --parentKeyType=rsa_ek --in=/tmp/out.json --out=/tmp/tpmkey.pem --tpm-path=$TPMB
cd example/
go run hmac/password/main.go --pemFile=/tmp/tpmkey.pem --password=bar --tpm-path=$TPMB
cd ..
### KeyedHash
# echo -n "change this password to a secret" > /tmp/seal.key
tpmcopy --mode duplicate --keyType=keyedhash --secret=/tmp/seal.key \
--password=bar -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
tpmcopy --mode import --parentKeyType=rsa_ek --in=/tmp/out.json --out=/tmp/tpmkey.pem --tpm-path=$TPMB
cd example/
go run keyedhash/main.go --pemFile=/tmp/tpmkey.pem --password=bar --tpm-path=$TPMB
cd ..
### Python RSA
tpmcopy --mode publickey --parentKeyType=rsa_ek -tpmPublicKeyFile=/tmp/public.pem --tpm-path=$TPMB
tpmcopy --mode duplicate --secret=/tmp/key_rsa.pem --keyType=rsa \
--password=bar -tpmPublicKeyFile=/tmp/public.pem -out=/tmp/out.json
tpmcopy --mode import --parentKeyType=rsa_ek --in=/tmp/out.json --out=/tmp/tpmkey.pem --tpm-path=$TPMB
cd example/python
virtualenv env
apt-get install libtss2-dev
python3 -m pip install git+https://github.com/tpm2-software/tpm2-pytss.git
python3 esapi_keyfile_policy_duplicateselect_password.pyIf you want to see how this flow works with pure tpm2_tools, see PolicyDuplicateSelect and PolicyAuthValue bound PolicyDuplicate
Specifically, the following will transfer an rsa key from one TPM to another. We're using two tpms although tpmcopy does not require a a TPM at the source. We're doing that because tpm2_tools does not allow for an easy way to synthetically duplicate without an actual local TPM.
start two TPMs
rm -rf /tmp/myvtpm && mkdir /tmp/myvtpm
swtpm_setup --tpmstate /tmp/myvtpm --tpm2 --create-ek-cert
rm -rf /tmp/myvtpm2 && mkdir /tmp/myvtpm2
swtpm_setup --tpmstate /tmp/myvtpm2 --tpm2 --create-ek-cert
swtpm socket --tpmstate dir=/tmp/myvtpm --tpm2 --server type=tcp,port=2321 --ctrl type=tcp,port=2322 --flags not-need-init,startup-clear --log level=2
swtpm socket --tpmstate dir=/tmp/myvtpm2 --tpm2 --server type=tcp,port=2341 --ctrl type=tcp,port=2342 --flags not-need-init,startup-clear --log level=2To transfer from TPM-A to TPM-B
TPM-B
Create an endorsement public key and extract the ECC PEM public key:
export TPM2TOOLS_TCTI="swtpm:port=2341"
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
tpm2_createek -c ek.ctx -G ecc -u ek.pub
tpm2_readpublic -c ek.ctx -o ek.pem -f PEM -n ek.name
tpm2_print -t TPM2B_PUBLIC ek.pubcopy ek.pem to TPM-A
TPM-A
export TPM2TOOLS_TCTI="swtpm:port=2321"
## generate an rsa key
openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:65537 -out /tmp/key_rsa.pem
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
# create any primary
tpm2_createprimary -C o -g sha256 -G rsa -c primaryA.ctx
tpm2_loadexternal -C o -g sha256 -G ecc:null:aes128cfb -u ek.pem -c newparent.ctx \
--attributes="fixedtpm|fixedparent|sensitivedataorigin|adminwithpolicy|restricted|decrypt"
tpm2_readpublic -c newparent.ctx -o new_parent.pub -n new_parent.name
## create a policy_or(policyAuthValue|policyDuplicateSelect)
tpm2_startauthsession -S sessionA.dat
tpm2_policyauthvalue -S sessionA.dat -L policyA_auth.dat
tpm2_flushcontext sessionA.dat
rm sessionA.dat
tpm2_startauthsession -S sessionA.dat
tpm2_policyduplicationselect -S sessionA.dat -N new_parent.name -L policyA_dupselect.dat
tpm2_flushcontext sessionA.dat
rm sessionA.dat
tpm2_startauthsession -S sessionA.ctx
tpm2_policyor -S sessionA.ctx -L policyA_or.dat sha256:policyA_auth.dat,policyA_dupselect.dat
tpm2_flushcontext sessionA.ctx
tpm2_flushcontext -t
### now import the external rsa key
tpm2_import -C primaryA.ctx -G rsa2048:rsassa:null -i /tmp/key_rsa.pem -u key.pub -r key.prv -p bar -a "sign" -L policyA_or.dat
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
tpm2_load -C primaryA.ctx -r key.prv -u key.pub -c key.ctx -n key.name
tpm2_readpublic -c key.ctx -o dup.pub
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
### create a binding policy
tpm2_startauthsession -S sessionA.dat --policy-session
tpm2_policyduplicationselect -S sessionA.dat -N new_parent.name -n key.name -L policyA_dupselect.dat
tpm2_policyor -S sessionA.dat -L policyA_or.dat sha256:policyA_auth.dat,policyA_dupselect.dat
## now duplicate
tpm2_flushcontext -t
tpm2_duplicate -C newparent.ctx -c key.ctx -G null -p "session:sessionA.dat" -r dup.dpriv -s dup.seed
tpm2_flushcontext -tTPM-B
on TPM B, import the duplicated keys, seed:
export TPM2TOOLS_TCTI="swtpm:port=2341"
tpm2 flushcontext -t
tpm2 startauthsession --session session.ctx --policy-session
tpm2 policysecret --session session.ctx --object-context endorsement
tpm2_import -C ek.ctx -u dup.pub -i dup.dpriv -r dup.prv -s dup.seed --parent-auth session:session.ctx
tpm2_flushcontext -t
tpm2_flushcontext session.ctx
tpm2_flushcontext -t
tpm2 flushcontext -t
tpm2 startauthsession --session session.ctx --policy-session
tpm2 policysecret --session session.ctx --object-context endorsement
tpm2_load -C ek.ctx -u dup.pub -r dup.prv -c dup.ctx --auth session:session.ctx
tpm2_readpublic -c dup.ctx -o dup.pub
tpm2_flushcontext session.ctx
tpm2_flushcontext -t
### now create a real policy which will full the conditions set earlier
tpm2_startauthsession -S sessionB.dat --policy-session
tpm2_policyauthvalue -S sessionB.dat -L policyB_auth.dat
tpm2_flushcontext sessionB.dat
rm sessionB.dat
tpm2_startauthsession -S sessionB.dat --policy-session
tpm2_policyduplicationselect -S sessionB.dat -N new_parent.name -L policyB_dupselect.dat
tpm2_flushcontext sessionB.dat
rm sessionB.dat
tpm2_startauthsession -S sessionB.dat --policy-session
tpm2_policyauthvalue -S sessionB.dat -L policyB_auth.dat
tpm2_policyor -S sessionB.dat -L policyB_or.dat sha256:policyB_auth.dat,policyB_dupselect.dat
echo "meet me at.." >file.txt
openssl dgst -sha256 -keyform PEM - -sign /tmp/key_rsa.pem -out sig.dat file.txt
tpm2_flushcontext -t
tpm2_sign -c dup.ctx -g sha256 -f plain -p"session:sessionB.dat+bar" -o sig.rss file.txt
tpm2_flushcontext -t