Skip to content

Commit

Permalink
set session encryption in-out for import; update docs
Browse files Browse the repository at this point in the history
Signed-off-by: sal rashid <salrashid123@gmail.com>
  • Loading branch information
salrashid123 committed Aug 28, 2024
1 parent 610939f commit 812cf3a
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 120 deletions.
196 changes: 99 additions & 97 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ There are two modes to using this library:

* `Remote encryption`

This mode utilizes a TPM `Endorsement Public Key (EKPub)` to wrap the encryption key which can ONLY get decrypted by the TPM that owns the EKPub
This mode utilizes a TPM `Endorsement Public Key (EKPub)` to wrap the some data which can ONLY get decrypted by the TPM that owns the EKPub

This mode requires local access to a real or simulated TPM to encrypt the data.


For a detailed description on how these modes work, see the `Background` section at the end
For a detailed description on how these modes work, see the [Background](#background) section at the end

This library is a a variation of [https://github.com/hashicorp/go-kms-wrapping](https://github.com/hashicorp/go-kms-wrapping)
This library builds off of Hashicorp Vault wrapping [https://github.com/hashicorp/go-kms-wrapping](https://github.com/hashicorp/go-kms-wrapping).

You can use this as a library or CLI

Expand All @@ -41,6 +41,14 @@ To configure the software TPM on your laptop for testing, see the `Using swtpm`

---

### CLI

You can build or download the cli from the `Releases` section

```bash
go build -o go-tpm-wrapping cmd/main.go
```

CLI Options:

| Option | Description |
Expand All @@ -60,21 +68,14 @@ CLI Options:

---

### CLI

You can build or download the cli from the `Releases` section

```bash
go build -o go-tpm-wrapping cmd/main.go
```

#### Usage Seal

To use, simply initialize the wrapper as shown below, specify a path to the TPM and optionally the PCR values to bind against

To use as a CLI, you can run `cmd/main.go` or download from the `Releases` page. If you want to use as an API, see the `example` folder
To use as a CLI, you can run `cmd/main.go` or download from the [Releases](/releases) page. If you want to use as an API, see the [example/](/tree/main/example) folder

- **encrypt/decrypt**

- encrypt/decrypt
```bash
$ go-tpm-wrapping --mode=seal --debug \
--dataToEncrypt=foo --encryptedBlob=/tmp/encrypted.json \
Expand All @@ -84,7 +85,7 @@ $ go-tpm-wrapping --mode=seal --debug --decrypt=true \
--encryptedBlob=/tmp/encrypted.json --tpm-path="127.0.0.1:2321"
```

- encrypt/decrypt with passphrase
- **encrypt/decrypt with passphrase**

```bash
$ go-tpm-wrapping --mode=seal --debug \
Expand All @@ -95,7 +96,7 @@ $ go-tpm-wrapping --mode=seal --debug --keyPass=testpass --decrypt=true \
--encryptedBlob=/tmp/encrypted.json --tpm-path="127.0.0.1:2321"
```

- encrypt/decrypt with passphrase and PCR values.
- **encrypt/decrypt with passphrase and PCR values**

```bash
### for example, if you want to stipulate the following PCR values must be present to unseal
Expand Down Expand Up @@ -176,7 +177,7 @@ Just to note, you don't *really* need access to a real, permanent TPM on the sys

The following encrypts some data using just the remote `ekpub`

- encrypt/decrypt
- **encrypt/decrypt**

```bash
# encrypt
Expand All @@ -197,7 +198,7 @@ $ go-tpm-wrapping --mode=import --debug --decrypt --encrypting_public_key=/tmp/e
--tpm-path="127.0.0.1:2341"
```

- With userAuth
- **With userAuth**

```bash
# encrypt
Expand All @@ -216,7 +217,7 @@ $ go-tpm-wrapping --mode=import --debug --decrypt \
--tpm-path="127.0.0.1:2341"
```

- With PCR
- **With PCR**

```bash
## encrypt/decrypt and bind the data to the **destination TPM's** values in
Expand Down Expand Up @@ -440,10 +441,9 @@ $ go run import_decrypt/main.go --encryptedBlob=/tmp/encrypted.json \
--tpm-path="127.0.0.1:2341"
```


### Session Encryption

Each operation uses encrypted sessions but by default, the library interrogates the TPM for the current EK directly.
Each operation uses [encrypted sessions](https://trustedcomputinggroup.org/wp-content/uploads/TCG_CPU_TPM_Bus_Protection_Guidance_Passive_Attack_Mitigation_8May23-3.pdf) 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

Expand All @@ -459,69 +459,6 @@ xxd -p -c 100 /tmp/ekpubAname.bin
--tpm-session-encrypt-with-name=000b47ab97fdda365cbb86a37548e38468f72e8baccc633cffc42402183679956608
```

also see

* [tpmrand Encrypted Session](https://github.com/salrashid123/tpmrand?tab=readme-ov-file#encrypted-session)
* [aws-tpm-process-credential Encrypted Sessions](https://github.com/salrashid123/aws-tpm-process-credential?tab=readme-ov-file#encrypted-tpm-sessions)
* [salrashid123/tpm2/Session Encryption](https://github.com/salrashid123/tpm2/tree/master/tpm_encrypted_session)


### Build

If you want to regenerate with protoc:

```bash
$ /usr/local/bin/protoc --version
libprotoc 25.1

$ go get -u github.com/golang/protobuf/protoc-gen-go

$ /usr/local/bin/protoc -I ./ --include_imports \
--experimental_allow_proto3_optional --include_source_info \
--descriptor_set_out=tpmwrappb/wrap.proto.pb \
--go_out=paths=source_relative:. tpmwrappb/wrap.proto
```

### Seal/Import with non-EKPub

_TODO_

The default mode for "import" utilizes the Endorsement Public key. A TODO is to allow _any_ encryption key you trust on the target TPM (`TPM-B`).

You would create an arbitrary encryption-only key using something like the following and evict it to a persistent handle as shown below on `TPM-B`


```bash
export TPM2TOOLS_TCTI="swtpm:port=2341"
export TPM2OPENSSL_TCTI="swtpm:port=2341"
tpm2_pcrread sha256:0,23

## create "H2 Template" as primary, you can setup any primary you want
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_create -G rsa -u key.pub -r key.priv -C primary.ctx -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|decrypt"
tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx

echo "meet me at..." > secret.txt
tpm2_rsaencrypt -c key.ctx -o secret.txt.enc secret.txt
tpm2_rsadecrypt -c key.ctx -o secret.txt.dec secret.txt.enc

tpm2_flushcontext -t

## cant' use this key for signing
## tpm2_sign -c key.ctx -g sha256 -o sig.rssa secret.txt

tpm2_readpublic -c key.ctx -o /tmp/pubA.pem -f PEM -Q
tpm2_evictcontrol -C o -c key.ctx 0x81010001
```

Copy `/tmp/pubA.pem` to `TPM-A` and start the import.

Copy the `encryptedblob.json` to `TPM-B`. Specify the persistent handle while importing on `TPM-B` (eg, use (`--mode=import --parentHandle=0x81010001`))

---

### Background

The following details some background how each of these modes works:
Expand All @@ -543,7 +480,7 @@ to `Encrypt`:

```
key1, ciphertext1, iv1: = go-kms-wrapping.Encrypt(plaintext1)
tpm_key = TPMKey.Seal(key1)
tpm_key = tpm2_seal(key1)
```

to `Decrypt`:
Expand All @@ -557,7 +494,7 @@ to `Decrypt`:
7. return the plaintext

```
key1 = TPMKey.Unseal()
key1 = tpm2_unseal()
plaintext1 = go-kms-wrapping.Decrypt(key1, iv1, ciphertext1)
```

Expand Down Expand Up @@ -585,9 +522,9 @@ on `TPM-A`:
```
key1, ciphertext1, iv1: = go-kms-wrapping.Encrypt(plaintext1)
per_use_iv = new random iv
tpm_key = new TPMKey(with_auth_policy)
ciphertext2 = tpm_key.Encrypt(key1, per_use_iv)
duplicate = TPMDuplicate(tpm_key, ekPubB.pem)
tpm_key = new tpm2_create(auth=with_auth_policy)
ciphertext2 = tpm2_encrypt(key1, per_use_iv)
duplicate = tpm2_duplicate(tpm_key, ekPubB.pem)
```

copy the duplicated key and wrapped _inner encryption key_,per_use_iv, iv1, ciphertext to `TPM-B` (all of which is encoded into one file)
Expand All @@ -600,8 +537,8 @@ on `TPM-B`:
11. use the inner key, IV and ciphertext to run [go-kms-wrapping.Decrypt()](https://pkg.go.dev/github.com/hashicorp/go-kms-wrapping#Envelope.Decrypt)

```
tpm_key = TPMImport(duplicate)
key1 = tpm_key.Decrypt(ciphertext2, per_use_iv)
tpm_key = tpm2_import(duplicate)
key1 = tpm2_decrypt(ciphertext2, per_use_iv)
plaintext1 = go-kms-wrapping.Decrypt(key1, iv1, ciphertext1)
```

Expand All @@ -612,8 +549,10 @@ on `TPM-B`:

on `TPM-A`:

3. given plaintext, use [go-kms-wrapping.Encrypt()](https://pkg.go.dev/github.com/hashicorp/go-kms-wrapping#Envelope.Encrypt) to encrypt.
3. given plaintext, use [go-kms-wrapping.Encrypt()](https://pkg.go.dev/github.com/hashicorp/go-kms-wrapping#Envelope.Encrypt).

`go-kms-wrapping.Encrypt` function will return a new _inner encryption key_, initialization vector and cipher text

4. create *NEW* random local (non-tpm) AES key
5. use the AES key to encrypt the _inner encryption key_
6. create a trial TPM `PolicyOR` session with a `PolicyPCR` and `PolicyDuplicateSelect` (the latter which bound to `TPM-B`'s ekpub)
Expand All @@ -625,11 +564,11 @@ on `TPM-A`:
```
key1, ciphertext1, iv1: = go-kms-wrapping.Encrypt(plaintext1)
per_use_iv = new random iv
per_useaes_key = new AESCFBKey() // this is a nonTPM key that is per-use
per_useaes_key = new go.crypto.AESCFBKey() // this is a nonTPM key that is per-use
wrapped_key1 = per_useaes_key.Encrypt(key1, per_use_iv) // we're doing this because we maynot able to fulfill the pcr policy on TPM-A
tpm_key = new TPMKey(with_auth_policy, per_useaes_key as senstitive ) // this is critical, we set the sentsitive to the per-use key;
duplicate = TPMDuplicate(tpm_key, ekPubB.pem)
tpm_key = new tpm2_create(auth=with_auth_policy, **sensitvie=per_useaes_key** ) // this is critical, we set the sentsitive to the per-use key;
duplicate = tpm2_duplicate(tpm_key, ekPubB.pem)
```

copy the duplicated tpm_key, wrapped_key1, iv1, per_use_iv to `TPM-B`
Expand All @@ -642,14 +581,77 @@ on `TPM-B`
13. Use the KEK to decrypt the DEK

```
tpm_key = TPMImport(duplicate)
key1 = tpm_key.Decrypt(wrapped_key1, per_use_iv) // we can do this because its the same key and iv which we encrypted with
tpm_key = tpm2_import(duplicate)
key1 = tpm2_decrypt(wrapped_key1, per_use_iv) // we can do this because its the same key and iv which we encrypted with
plaintext1 = go-kms-wrapping.Decrypt(key1, iv1, ciphertext1)
```

---

### Using swtpm
also see

* [tpmrand Encrypted Session](https://github.com/salrashid123/tpmrand?tab=readme-ov-file#encrypted-session)
* [aws-tpm-process-credential Encrypted Sessions](https://github.com/salrashid123/aws-tpm-process-credential?tab=readme-ov-file#encrypted-tpm-sessions)
* [salrashid123/tpm2/Session Encryption](https://github.com/salrashid123/tpm2/tree/master/tpm_encrypted_session)


#### Build

If you want to regenerate with protoc:

```bash
$ /usr/local/bin/protoc --version
libprotoc 25.1

$ go get -u github.com/golang/protobuf/protoc-gen-go

$ /usr/local/bin/protoc -I ./ --include_imports \
--experimental_allow_proto3_optional --include_source_info \
--descriptor_set_out=tpmwrappb/wrap.proto.pb \
--go_out=paths=source_relative:. tpmwrappb/wrap.proto
```

#### Seal/Import with non-EKPub

_TODO_

The default mode for "import" utilizes the Endorsement Public key. A TODO is to allow _any_ encryption key you trust on the target TPM (`TPM-B`).

You would create an arbitrary encryption-only key using something like the following and evict it to a persistent handle as shown below on `TPM-B`


```bash
export TPM2TOOLS_TCTI="swtpm:port=2341"
export TPM2OPENSSL_TCTI="swtpm:port=2341"
tpm2_pcrread sha256:0,23

## create "H2 Template" as primary, you can setup any primary you want
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_create -G rsa -u key.pub -r key.priv -C primary.ctx -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|decrypt"
tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx

echo "meet me at..." > secret.txt
tpm2_rsaencrypt -c key.ctx -o secret.txt.enc secret.txt
tpm2_rsadecrypt -c key.ctx -o secret.txt.dec secret.txt.enc

tpm2_flushcontext -t

## cant' use this key for signing
## tpm2_sign -c key.ctx -g sha256 -o sig.rssa secret.txt

tpm2_readpublic -c key.ctx -o /tmp/pubA.pem -f PEM -Q
tpm2_evictcontrol -C o -c key.ctx 0x81010001
```

Copy `/tmp/pubA.pem` to `TPM-A` and start the import.

Copy the `encryptedblob.json` to `TPM-B`. Specify the persistent handle while importing on `TPM-B` (eg, use (`--mode=import --parentHandle=0x81010001`))

---

#### Using swtpm

If you want to test locally with software TPMs:

Expand Down
15 changes: 3 additions & 12 deletions import.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,20 +219,11 @@ func (s *RemoteWrapper) Encrypt(ctx context.Context, plaintext []byte, opt ...wr

rwr := transport.FromReadWriter(rwc)

// create a basic encryption session
encsess := tpm2.HMAC(tpm2.TPMAlgSHA256, 16, tpm2.AESEncryption(128, tpm2.EncryptOut))
defer func() {
flushContextCmd := tpm2.FlushContext{
FlushHandle: encsess.Handle(),
}
_, _ = flushContextCmd.Execute(rwr)
}()

// get the endorsement key using that initial session
// get the endorsement key for the local TPM which we will use for parameter encryption
createEKRsp, err := tpm2.CreatePrimary{
PrimaryHandle: tpm2.TPMRHEndorsement,
InPublic: tpm2.New2B(tpm2.RSAEKTemplate),
}.Execute(rwr, encsess)
}.Execute(rwr)
if err != nil {
return nil, fmt.Errorf("error creating EK Primary %v", err)
}
Expand Down Expand Up @@ -844,7 +835,7 @@ func (s *RemoteWrapper) Decrypt(ctx context.Context, in *wrapping.BlobInfo, opt
}

// create an actual full encryption session using the EK we trust
rsessInOut := tpm2.HMAC(tpm2.TPMAlgSHA256, 16, tpm2.AESEncryption(128, tpm2.EncryptIn), tpm2.Salted(createEKRsp.ObjectHandle, *encryptionPub))
rsessInOut := tpm2.HMAC(tpm2.TPMAlgSHA256, 16, tpm2.AESEncryption(128, tpm2.EncryptInOut), tpm2.Salted(createEKRsp.ObjectHandle, *encryptionPub))
defer func() {
flushContextCmd := tpm2.FlushContext{
FlushHandle: rsessInOut.Handle(),
Expand Down
13 changes: 2 additions & 11 deletions seal.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,20 +176,11 @@ func (s *TPMWrapper) Encrypt(ctx context.Context, plaintext []byte, opt ...wrapp
return nil, fmt.Errorf("error wrapping data: %w", err)
}

// start an initial encryption session
encsess := tpm2.HMAC(tpm2.TPMAlgSHA256, 16, tpm2.AESEncryption(128, tpm2.EncryptOut))
defer func() {
flushContextCmd := tpm2.FlushContext{
FlushHandle: encsess.Handle(),
}
_, _ = flushContextCmd.Execute(rwr)
}()

// get the endorsement key using that initial session
// get the endorsement key for the local TPM which we will use for parameter encryption
createEKRsp, err := tpm2.CreatePrimary{
PrimaryHandle: tpm2.TPMRHEndorsement,
InPublic: tpm2.New2B(tpm2.RSAEKTemplate),
}.Execute(rwr, encsess)
}.Execute(rwr)
if err != nil {
return nil, fmt.Errorf("error creating EK Primary %v", err)
}
Expand Down

0 comments on commit 812cf3a

Please sign in to comment.