stefanberger / swtpm

Libtpms-based TPM emulator with socket, character device, and Linux CUSE interface.
Other
562 stars 137 forks source link

Running on FreeBSD #820

Open mekanix opened 1 year ago

mekanix commented 1 year ago

Describe the bug

There is a swtpm port in FreeBSD but I don't know how to use it. With socket and cuse there is an error. Socket can not be opened by client apps, cuse fails with an error.

Required: To Reproduce (without these steps your issue may be deleted)

Steps to reproduce the behavior/issue showing all commands on command line, needed XML or JSON (if necessary), etc.:

Socket

  1. pkg install swtpm
  2. mkdir /tmp/mytpm1
  3. swtpm socket --tpmstate dir=/tmp/mytpm1 --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock --tpm2 --log level=20
  4. swtpm_ioctl --tpm-device /tmp/mytpm1/swtpm-sock -i (error: Unable to open device '/tmp/mytpm1/swtpm-sock'.)

CUSE

  1. pkg install swtpm
  2. mkdir /tmp/mytpm1
  3. swtpm cuse -n mytpm1 --tpmstate dir=/tmp/mytpm1 --tpm2 (error: fuse: unknown option 'fsname=cuse')

Expected behavior

I expect no error at this stage. Maybe later, but I would expect that I can at least run it.

Desktop (please complete the following information):

Versions of relevant components

Log files No log files are produced, yet.

Additional context I know FreeBSD is not a target platform and that errors might indicate faults in other libraries, not swtpm itself, but can you help me at least narrow the problem down? It would be great if CUSE would start working as recently bhyve, FreeBSD's hypervisor, got TPM pass-through feature so swtpm could be used right away.

mekanix commented 1 year ago

Colegue told me that CUSE on FreeBSD is not extension of FUSE, hence the error. OK, that makes sense, now only to narrow down socket.

stefanberger commented 1 year ago

Try these steps with --unix:

swtpm socket --tpmstate dir=/tmp/mytpm1 --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock --tpm2 --log level=20
swtpm_ioctl --unix /tmp/mytpm1/swtpm-sock -i
mekanix commented 1 year ago

All right, that's a progress. On the "daemon" side I got

swtpm socket --tpmstate dir=/tmp/mytpm1 --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock --tpm2 --log level=20
 Ctrl Cmd: length 8
 00 00 00 02 00 00 00 01
 Ctrl Rsp: length 4
 00 00 00 00

Is that what I'm supposed to see?

stefanberger commented 1 year ago

Is that what I'm supposed to see?

Looks good.

Your swtpm only has a control channel. If you wanted to add a data/command channel you would need to add something like this so that you can send TPM commands to it. Have a look at this here.

swtpm socket --tpmstate dir=/tmp/mytpm1 --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock --tpm2 --log level=20 --server type=tcp,port=2321
mekanix commented 1 year ago

It does start, but I can't do anything with it. The port is opened on 127.0.0.1 and checking with nmap it appears to be so, but I get an error trying to reach it:

# sockstat -46l | grep 2321
root     swtpm      73007 4   tcp4   127.0.0.1:2321        *:*

# nmap -p 2321 127.0.0.1
Starting Nmap 7.94 ( https://nmap.org ) at 2023-08-19 09:57 CEST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00031s latency).

PORT     STATE SERVICE
2321/tcp open  rdlap

Nmap done: 1 IP address (1 host up) scanned in 0.02 seconds

# swtpm_ioctl -i --tcp 127.0.0.1:2321
Could not execute PTM_INIT: Operation timed out
mekanix commented 1 year ago

Oh, I realize what's my error here. swtpm_ioctl -i is for --ctrl and --server is used by tss* family of commands. OK, for now I can at least work on init function in bhyve. Thank you so much for your help!

mekanix commented 1 year ago

I created a little playground to learn and experiment more, and for now I have init, deinit and ctrlcmd ripped from swtpm_ioctl. I suppose logical next step is to implement something like datacmd? If yes, what command would be easiest to implement? I guess I will need to look into tss* commands to learn more, but if you have a suggestion how I can learn more, I'm all ears.

stefanberger commented 1 year ago

I created a little playground to learn and experiment more, and for now I have init, deinit and ctrlcmd ripped from swtpm_ioctl. I suppose logical next step is to implement something like datacmd? If yes, what command would be easiest to implement? I guess I will need to look into tss* commands to learn more, but if you have a suggestion how I can learn more, I'm all ears.

What do you want to achieve at this point?

Generally the first command you should implement support for is TPM_Startup() since this command is always needed. You could avoid implementing support for it if you passed swtpm ... --flags not-need-init,startup-clear or if you used the TSS 2 tools (IBM or Intel). The TSS 2 tools implement a whole lot of commands if you are fine with invoking them from command line or bash script.

mekanix commented 1 year ago

I would like to write backend for bhyve, which is FreeBSD's hypervisor. What I was thinking would be the easiest way to achieve that is by learning from existing tools and implementing at least one command for ctrl/data channel in order to verify it works. As my code will just be a proxy for the VM, I don't need comprehensive set of commands, just one or a handful to verify code works before I turn it into bhyve backend for TPM.

stefanberger commented 1 year ago

Next simple command would be TPM_PcrRead to read a PCR.

As for passthrough: We have that also with QEMU and I would not recommend using it but us a vTPM instance (swtpm) per VM. Multiple VMs sharing TPM 'resources' like PCRs is not 'good'.

mekanix commented 1 year ago

Maybe I used the wrong word. Passthrough is already implemented and I use it to learn about how to add swtpm to bhyve. Of course, it will be used as a one swtpm instance per VM. Anyway, when I make progress, I'll report it here. Thank you!