tpmwrap

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 10, 2024 License: Apache-2.0 Imports: 23 Imported by: 0

README

Go-TPM-Wrapping - Go library for encrypting values through Trusted Platform Module (TPM)

Library to encrypt and decrypt data using a wrapping key thats encoded inside a Trusted Platform Module (TPM).

In other words, you must have access to the TPM that encrypted the data to decrypt the wrapping key

There are two modes to using this library:

  • Seal/Unseal

    To use this, you must have access to the same TPM for both encrypting and decrypting.

    When you encrypt data, it can ONLY get decrypted by that SAME TPM.

    see Seal/Unseal using a TPM's Storage Root Key (SRK)

  • Remote encryption

    To use this, you do not need a TPM to encrypt but you DO need a TPM to decrypt.

    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

    see Remote Sealed TPM Import

This is a a variation of https://github.com/hashicorp/go-kms-wrapping

This library is NOT supported by google

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

import (
	wrapping "github.com/hashicorp/go-kms-wrapping/v2"
	tpmwrap "github.com/salrashid123/go-tpm-wrapping"
)

	wrapper := tpmwrap.NewWrapper()
	_, err := wrapper.SetConfig(ctx, wrapping.WithConfigMap(map[string]string{
		"tpm_path": "/dev/tpm0",
		"pcrs":     "23",
	}))

	blobInfo, err := wrapper.Encrypt(ctx, []byte("foo"))

	fmt.Printf("Encrypted: %s\n", hex.EncodeToString(blobInfo.Ciphertext))

	plaintext, err := wrapper.Decrypt(ctx, blobInfo)
	fmt.Printf("Decrypted %s\n", string(plaintext))

See the example folder for an example:

cd example

## encrypt/decrypt
$ go run seal/main.go 
Encrypted: d67b83180ae269a148cb86c2bd69d0cfba55d4
Decrypted foo

## encrypt/decrypt and bind the data to the current values in
### PCR banks 16,23
$ go run seal/main.go --pcrs=16,23
Encrypted: 19d1fd5fefeb37ec0964d2219cf7eeea4b548b
Decrypted foo

## encrypt/decrypt and bind the data to the current values in
### PCR banks 16,23
### Extend PCR bank 23 and attempt to decrypt (which is expected to fail)

$ go run seal/main.go --pcrs=16,23 --extendPCR=23
Encrypted: e886b584b5637006134f2eb1e81d2d679eebee
Decrypted foo
======= Extend PCR  ========
   Current PCR(23) e71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7   
   New PCR(23) 31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0Error decrypting failed to unsealing key: failed to certify PCRs: PCR 23 mismatch: expected e71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7, got 31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0
exit status 1

Usage Import

To use this mode, you must first acquire the Endorsement Public Key (ekPub).

The ekPub can be extracted from the Endorsement Certificate on a TPM or on GCE, via an API.

To use tpm2_tools on the target machine

$ tpm2_getekcertificate -X -o ECcert.bin

$ openssl x509 -in ECcert.bin -inform DER -noout -text

openssl  x509 -pubkey -noout -in ECcert.bin  -inform DER 

Copy the public key (ek to a remote host and save as encrypting_public_key

On a remote machine:

import (
	wrapping "github.com/hashicorp/go-kms-wrapping/v2"
	tpmwrap "github.com/salrashid123/go-tpm-wrapping"
)

		b, err := os.ReadFile(*encrypting_public_key)

		wrapper := tpmwrap.NewRemoteWrapper()
		_, err = wrapper.SetConfig(ctx, wrapping.WithConfigMap(map[string]string{
			"encrypting_public_key": hex.EncodeToString(b),
			"pcr_values":            *pcrValues,
		}))

		blobInfo, err := wrapper.Encrypt(ctx, []byte("foo"))

		eb, err := protojson.Marshal(blobInfo)

		err = os.WriteFile(*encrypted_blob, eb, 0644)

At this point, copy encrypted_blob to the machine with the TPM

On a TPM:

		wrapper := tpmwrap.NewRemoteWrapper()
		_, err := wrapper.SetConfig(ctx, wrapping.WithConfigMap(map[string]string{
			"tpm_path": *tpmPath,
		}))

		eb, err := os.ReadFile(*encrypted_blob)

		newBlobInfo := &wrapping.BlobInfo{}
		err = protojson.Unmarshal(eb, newBlobInfo)

		plaintext, err := wrapper.Decrypt(ctx, newBlobInfo)
		fmt.Printf("Decrypted %s\n", string(plaintext))

See the example/import folder.

The following encrypts some data and binds it to a PCR value

$ go run import/main.go --mode=encrypt  --encrypting_public_key=/tmp/ek.pem  \
   --pcrValues="23:f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b" \
   --encrypted_blob=/tmp/encrypted.dat

# now copy scp /tmp/encrypted.dat to VM

Then on a machine with the TPM, run

go run import/main.go --mode=decrypt  --encrypted_blob=/tmp/encrypted.dat

This will decrypt the data

Note, if you extend the PCR value successively,

$ tpm2_pcrread sha256:23
  sha256:
    23: 0x0000000000000000000000000000000000000000000000000000000000000000
$ tpm2_pcrextend 23:sha256=0x0000000000000000000000000000000000000000000000000000000000000000
$ tpm2_pcrread sha256:23
  sha256:
    23: 0xF5A5FD42D16A20302798EF6ED309979B43003D2320D9F0E8EA9831A92759FB4B
$ tpm2_pcrextend 23:sha256=0xF5A5FD42D16A20302798EF6ED309979B43003D2320D9F0E8EA9831A92759FB4B
$ tpm2_pcrread sha256:23
  sha256:
    23: 0xDB56114E00FDD4C1F85C892BF35AC9A89289AAECB1EBD0A96CDE606A748B5D71

and attempt to decrypt the data, it will fail with a policy check:

$ go run import/main.go --mode=decrypt  --encrypted_blob=/tmp/encrypted.dat
Error decrypting error decrypted key error: unseal failed: session 1, error code 0x1d : a policy check failed
exit status 1

As mentioned, you can acquire the ekPub for certain systems like GCP VM's via an API:

gcloud compute  instances create   tpm-device  \
      --zone=us-central1-a --machine-type=n1-standard-1    --tags tpm  \
	   --no-service-account  --no-scopes  \
	   --shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring \
	   --image-family=debian-11 --image-project=debian-cloud

gcloud compute instances get-shielded-identity  tpm-device --format="value(encryptionKey.ekPub)" > /tmp/ek.pem

Documentation

Index

Constants

View Source
const (
	EnvTPMPath             = "TPM_PATH"
	EnvPCRS                = "TPM_PCRS"
	EnvPCRValues           = "TPM_PCR_VALUES"
	EnvEncryptingPublicKey = "TPM_ENCRYPTING_PUBLIC_KEY"
)
View Source
const (
	TPMSeal = iota
	TPMImport
)
View Source
const (
	WrapperTypeRemoteTPM wrapping.WrapperType = "tpmimport"
)
View Source
const (
	WrapperTypeTPM wrapping.WrapperType = "tpm"
)

Variables

This section is empty.

Functions

func WithEncryptingPublicKey added in v0.1.0

func WithEncryptingPublicKey(with string) wrapping.Option

Encrypted public key Multiple PCR values are comma separated (.WithPCRValues("hex_encoded_string"))

func WithPCRS

func WithPCRS(with string) wrapping.Option

List of PCR banks to bind the key against. Multiple PCR values are comma separated (.WithPCRS("16,23"))

func WithPCRValues added in v0.1.0

func WithPCRValues(with string) wrapping.Option

List of PCR Value Multiple PCR values are comma separated (.WithPCRValues("0:123abc,7:abcae"))

func WithTPMPath

func WithTPMPath(with string) wrapping.Option

Path to the TPM device (/dev/tpm0)

func WithUserAgent

func WithUserAgent(with string) wrapping.Option

WithUserAgent provides a way to chose the user agent

Types

type OptionFunc

type OptionFunc func(*options) error

OptionFunc holds a function with local options

type RemoteWrapper added in v0.1.0

type RemoteWrapper struct {
	// contains filtered or unexported fields
}

Configures and manages the TPM SRK encryption wrapper

Values here are set using setConfig or options

func NewRemoteWrapper added in v0.1.0

func NewRemoteWrapper() *RemoteWrapper

Initialize a TPM based encryption wrapper

func (*RemoteWrapper) Decrypt added in v0.1.0

func (s *RemoteWrapper) Decrypt(ctx context.Context, in *wrapping.BlobInfo, opt ...wrapping.Option) ([]byte, error)

Decrypt is used to decrypt the ciphertext.

func (*RemoteWrapper) Encrypt added in v0.1.0

func (s *RemoteWrapper) Encrypt(ctx context.Context, plaintext []byte, opt ...wrapping.Option) (*wrapping.BlobInfo, error)

Encrypts data using a TPM's Storage Root Key (SRK)

func (*RemoteWrapper) KeyId added in v0.1.0

func (s *RemoteWrapper) KeyId(_ context.Context) (string, error)

func (*RemoteWrapper) SetConfig added in v0.1.0

Set the configuration options

func (*RemoteWrapper) Type added in v0.1.0

type Wrapper

type Wrapper struct {
	// contains filtered or unexported fields
}

Configures and manages the TPM SRK encryption wrapper

Values here are set using setConfig or options

func NewWrapper

func NewWrapper() *Wrapper

Initialize a TPM based encryption wrapper

func (*Wrapper) Decrypt

func (s *Wrapper) Decrypt(ctx context.Context, in *wrapping.BlobInfo, opt ...wrapping.Option) ([]byte, error)

Decrypt is used to decrypt the ciphertext.

func (*Wrapper) Encrypt

func (s *Wrapper) Encrypt(ctx context.Context, plaintext []byte, opt ...wrapping.Option) (*wrapping.BlobInfo, error)

Encrypts data using a TPM's Storage Root Key (SRK)

func (*Wrapper) KeyId

func (s *Wrapper) KeyId(_ context.Context) (string, error)

func (*Wrapper) SetConfig

func (s *Wrapper) SetConfig(_ context.Context, opt ...wrapping.Option) (*wrapping.WrapperConfig, error)

Set the configuration options

func (*Wrapper) Type

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL