Skip to content

salrashid123/go_tpm_https_embed

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

49 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mTLS with TPM bound private key

Simple http client/server in golang where the private key used in the connection is generated and embedded within a Trusted Platform Module.

The steps here will create a client and server using a local software tpm swtpm. On that TPM, create two RSA keys, generate a CSR using those keys, then an external CA will issue an x509 cert using that csr.

Finally, the client will establish an mTLS https connection to the server


  • If you want to see one-way TLS where the server's private key is embedded in a TPM and the private key is cryptographically verified (tpm remote attestation), please instead see https://github.com/salrashid123/tls_ak

for python, see Python mTLS client/server with TPM based key


NOTE: this repo is not supported by Google

To use this sample, you'll need:

The TPM based private keys conforms to ASN.1 Specification for TPM 2.0 Key Files which in its basic mode is compatible with openssl

QuickStart

if you want to use the keys provided in this repo, you just need swtpm

Start swtpm

Start two software TPMs on different ports to simulate the client and server's TPMs

cd certs/
## tpm for server
swtpm socket --tpmstate dir=myvtpm --tpm2 --server type=tcp,port=2321 --ctrl type=tcp,port=2322 --flags not-need-init,startup-clear --log level=2

## in a new window, start tpm for the client
swtpm socket --tpmstate dir=myvtpm2 --tpm2 --server type=tcp,port=2341 --ctrl type=tcp,port=2342 --flags not-need-init,startup-clear --log level=2
Start Server

To start the server using the built in demo swtpm

go run src/server/server.go -cacert certs/ca/root-ca.crt \
   -servercert certs/server.crt \
    --severkey=certs/server_key.pem -port :8081 \
      --tpm-path="127.0.0.1:2321"

You can test the config locally using the pre-generated client certificates provided in this repo

(the following uses curl and ordinary (non-tpm) client certifcates)

curl -v -H "Host: server.domain.com"  --resolve  server.domain.com:8081:127.0.0.1 \
   --cert certs/user10.crt --key certs/user10.key \
    --cacert certs/ca/root-ca.crt https://server.domain.com:8081/index.html
Start Client

Run the client which uses TPM-based client certificates, in a new window:

go run src/client/client.go -cacert certs/ca/root-ca.crt \
  --clientkey=certs/client_key.pem --pubCert=certs/client.crt  \
   --address localhost --tpm-path="127.0.0.1:2341"

WHat this shows is mTLS where both ends have the TLS private key on the TPM.


Appendix

The following sets up your own certs and software or real TPMs.

If you want to use a real TPM, you need openssl tpm support but you don't need to export the TPM2* environment variables. For a real tpm, you'll also need to speicfy --tpm-path=/dev/tpmrm0

Server

The following will setup a server cert where the private key is on a TPM. For this you need to install openssl tpm support and tpm2_tools

if you'd rather use a real tpm than a sotware one, dont' export the TPM* env variables or start the swtpms.

Finally, while running the client or server set --tpm-path="/dev/tpmrm0"

For a swtpm:

mkdir myvtpm
sudo swtpm_setup --tpmstate myvtpm --tpm2 --create-ek-cert
sudo swtpm socket --tpmstate dir=myvtpm --tpm2 --server type=tcp,port=2321 --ctrl type=tcp,port=2322 --flags not-need-init,startup-clear --log level=2

export TPM2TOOLS_TCTI="swtpm:port=2321"
export TPM2OPENSSL_TCTI="swtpm:port=2321"
export TPM2TSSENGINE_TCTI="swtpm:port=2321"
export OPENSSL_MODULES=/usr/lib/x86_64-linux-gnu/ossl-modules/
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
# export TSS2_LOG=esys+debug


### first verify you have openssl installed and configured for TPM:
openssl list  -provider tpm2  -provider default  --providers

  Providers:
    default
      name: OpenSSL Default Provider
      version: 3.5.0
      status: active
    tpm2
      name: TPM 2.0 Provider
      version: 1.3.0
      status: active

cd certs/
printf '\x00\x00' > unique.dat
tpm2_createprimary -C o -G ecc -g sha256  -c rprimary.ctx -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda|restricted|decrypt" -u unique.dat

tpm2_create -G rsa2048:rsapss:null -g sha256 -u server.pub -r server.priv -C rprimary.ctx
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l
# tpm2_load -C rprimary.ctx -u server.pub -r server.priv -c server.ctx

## convert rkey.pub rkey.priv to PEM format
## note, you may need to add a -p parameter to tpm2_encodeobject if the version of tpm2_tools does not include (https://github.com/tpm2-software/tpm2-tools/issues/3458)
tpm2_encodeobject -C rprimary.ctx -u server.pub -r server.priv -o server_key.pem

### you'll know if you need to if you run the following and it prompts for a password
openssl rsa -provider tpm2  -provider default -in server_key.pem --text

export SAN="DNS:server.domain.com"
openssl req -new  -provider tpm2  -provider default    -config server.conf \
  -out server.csr  \
  -key server_key.pem  -reqexts server_reqext   \
  -subj "/C=US/O=Google/OU=Enterprise/CN=server.domain.com" 

openssl req -in server.csr -noout -text

openssl ca \
    -config single-root-ca.conf \
    -in server.csr \
    -out server.crt  \
    -extensions server_ext

# run the server as go
go run src/server/server.go -cacert certs/ca/root-ca.crt \
   -servercert certs/server.crt \
    --severkey=certs/server_key.pem -port :8081 \
      --tpm-path="127.0.0.1:2321"

Client

For the client,

mkdir myvtpm2
sudo swtpm_setup --tpmstate myvtpm2 --tpm2 --create-ek-cert
sudo swtpm socket --tpmstate dir=myvtpm2 --tpm2 --server type=tcp,port=2341 --ctrl type=tcp,port=2342 --flags not-need-init,startup-clear --log level=2

export TPM2TOOLS_TCTI="swtpm:port=2341"
export TPM2OPENSSL_TCTI="swtpm:port=2341"
export TPM2TSSENGINE_TCTI="swtpm:port=2341"
export OPENSSL_MODULES=/usr/lib/x86_64-linux-gnu/ossl-modules/
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l

printf '\x00\x00' > unique.dat
tpm2_createprimary -C o -G ecc -g sha256  -c rcprimary.ctx -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda|restricted|decrypt" -u unique.dat

tpm2_create -G rsa2048:rsapss:null -g sha256 -u client.pub -r client.priv -C rcprimary.ctx
tpm2_load -C rcprimary.ctx -u client.pub -r client.priv -c client.ctx

## note, you may need to add a -p parameter to tpm2_encodeobject (https://github.com/tpm2-software/tpm2-tools/issues/3458)
tpm2_encodeobject -C rcprimary.ctx -u client.pub -r client.priv -o client_key.pem

# create a csr using the tpm key...i have it in this repo:
openssl rsa -provider tpm2  -provider default -in client_key.pem --text

export SAN="DNS:client.domain.com"
openssl req -new  -provider tpm2  -provider default    -config client.conf \
  -out client.csr  \
  -key client_key.pem  -reqexts client_reqext   \
  -subj "/C=US/O=Google/OU=Enterprise/CN=client.domain.com" 

openssl req -in client.csr -noout -text

openssl ca \
    -config single-root-ca.conf \
    -in client.csr \
    -out client.crt  \
    -extensions client_ext

go run src/client/client.go -cacert certs/ca/root-ca.crt \
  --clientkey=certs/client_key.pem --pubCert=certs/client.crt  \
   --address localhost --tpm-path="127.0.0.1:2341"

At this point, you should see a simple 'ok' from the sever

Openssl

If you would rather test the client/server using openssl

swtpm socket --tpmstate dir=myvtpm --tpm2 --server type=tcp,port=2321 --ctrl type=tcp,port=2322 --flags not-need-init,startup-clear --log level=2

export TPM2TOOLS_TCTI="swtpm:port=2321"
export TPM2OPENSSL_TCTI="swtpm:port=2321"
export TPM2TSSENGINE_TCTI="swtpm:port=2321"
export OPENSSL_MODULES=/usr/lib/x86_64-linux-gnu/ossl-modules/
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l

openssl s_server  -provider tpm2  -provider default  \
        -cert server.crt \
      -key server_key.pem \
      -port 8081 \
      -CAfile ca/root-ca.crt \
      -tlsextdebug \
      -tls1_3  \
      -trace \
      -WWW
swtpm socket --tpmstate dir=myvtpm2 --tpm2 --server type=tcp,port=2341 --ctrl type=tcp,port=2342 --flags not-need-init,startup-clear --log level=2

export TPM2TOOLS_TCTI="swtpm:port=2341"
export TPM2OPENSSL_TCTI="swtpm:port=2341"
export TPM2TSSENGINE_TCTI="swtpm:port=2341"
export OPENSSL_MODULES=/usr/lib/x86_64-linux-gnu/ossl-modules/
tpm2_flushcontext -t && tpm2_flushcontext -s && tpm2_flushcontext -l

## in new window
go run src/client/client.go -cacert certs/ca/root-ca.crt \
  --clientkey=certs/client_key.pem --pubCert=certs/client.crt  \
   --address localhost --tpm-path="127.0.0.1:2341"

References

Other references:

RSA-PSS padding:

Releases

No releases published

Packages

No packages published

Languages