| 1 | ====================================================== |
| 2 | QEMU Security Protocols and Data Models (SPDM) Support |
| 3 | ====================================================== |
| 4 | |
| 5 | SPDM enables authentication, attestation and key exchange to assist in |
| 6 | providing infrastructure security enablement. It's a standard published |
| 7 | by the `DMTF`_. |
| 8 | |
| 9 | QEMU supports connecting to a SPDM responder implementation. This allows an |
| 10 | external application to emulate the SPDM responder logic for an SPDM device. |
| 11 | |
| 12 | Setting up a SPDM server |
| 13 | ======================== |
| 14 | |
| 15 | When using QEMU with SPDM devices QEMU will connect to a server which |
| 16 | implements the SPDM functionality. |
| 17 | |
| 18 | SPDM-Utils |
| 19 | ---------- |
| 20 | |
| 21 | You can use `SPDM Utils`_ to emulate a responder. This is the simplest method. |
| 22 | |
| 23 | SPDM-Utils is a Linux applications to manage, test and develop devices |
| 24 | supporting DMTF Security Protocol and Data Model (SPDM). It is written in Rust |
| 25 | and utilises libspdm. |
| 26 | |
| 27 | To use SPDM-Utils you will need to do the following steps. Details are included |
| 28 | in the SPDM-Utils README. |
| 29 | |
| 30 | 1. `Build libspdm`_ |
| 31 | 2. `Build SPDM Utils`_ |
| 32 | 3. `Run it as a server`_ |
| 33 | |
| 34 | spdm-emu |
| 35 | -------- |
| 36 | |
| 37 | You can use `spdm emu`_ to model the |
| 38 | SPDM responder. |
| 39 | |
| 40 | .. code-block:: shell |
| 41 | |
| 42 | $ cd spdm-emu |
| 43 | $ git submodule init; git submodule update --recursive |
| 44 | $ mkdir build; cd build |
| 45 | $ cmake -DARCH=x64 -DTOOLCHAIN=GCC -DTARGET=Debug -DCRYPTO=openssl .. |
| 46 | $ make -j32 |
| 47 | $ make copy_sample_key # Build certificates, required for SPDM authentication. |
| 48 | |
| 49 | It is worth noting that the certificates should be in compliance with |
| 50 | PCIe r6.1 sec 6.31.3. This means you will need to add the following to |
| 51 | openssl.cnf |
| 52 | |
| 53 | .. code-block:: |
| 54 | |
| 55 | subjectAltName = otherName:2.23.147;UTF8:Vendor=1b36:Device=0010:CC=010802:REV=02:SSVID=1af4:SSID=1100 |
| 56 | 2.23.147 = ASN1:OID:2.23.147 |
| 57 | |
| 58 | and then manually regenerate some certificates with: |
| 59 | |
| 60 | .. code-block:: shell |
| 61 | |
| 62 | $ openssl req -nodes -newkey ec:param.pem -keyout end_responder.key \ |
| 63 | -out end_responder.req -sha384 -batch \ |
| 64 | -subj "/CN=DMTF libspdm ECP384 responder cert" |
| 65 | |
| 66 | $ openssl x509 -req -in end_responder.req -out end_responder.cert \ |
| 67 | -CA inter.cert -CAkey inter.key -sha384 -days 3650 -set_serial 3 \ |
| 68 | -extensions v3_end -extfile ../openssl.cnf |
| 69 | |
| 70 | $ openssl asn1parse -in end_responder.cert -out end_responder.cert.der |
| 71 | |
| 72 | $ cat ca.cert.der inter.cert.der end_responder.cert.der > bundle_responder.certchain.der |
| 73 | |
| 74 | You can use SPDM-Utils instead as it will generate the correct certificates |
| 75 | automatically. |
| 76 | |
| 77 | The responder can then be launched with |
| 78 | |
| 79 | .. code-block:: shell |
| 80 | |
| 81 | $ cd bin |
| 82 | $ ./spdm_responder_emu --trans PCI_DOE |
| 83 | |
| 84 | Connecting an SPDM NVMe device |
| 85 | ============================== |
| 86 | |
| 87 | Once a SPDM server is running we can start QEMU and connect to the server. |
| 88 | |
| 89 | For an NVMe device first let's setup a block we can use |
| 90 | |
| 91 | .. code-block:: shell |
| 92 | |
| 93 | $ cd qemu-spdm/linux/image |
| 94 | $ dd if=/dev/zero of=blknvme bs=1M count=2096 # 2GB NNMe Drive |
| 95 | |
| 96 | Then you can add this to your QEMU command line: |
| 97 | |
| 98 | .. code-block:: shell |
| 99 | |
| 100 | -drive file=blknvme,if=none,id=mynvme,format=raw \ |
| 101 | -device nvme,drive=mynvme,serial=deadbeef,spdm_port=2323,spdm_trans=doe |
| 102 | |
| 103 | At which point QEMU will try to connect to the SPDM server. |
| 104 | |
| 105 | Note that if using x86_64 you will want to use the q35 machine instead |
| 106 | of the default. So the entire QEMU command might look like this |
| 107 | |
| 108 | .. code-block:: shell |
| 109 | |
| 110 | qemu-system-x86_64 -M q35 \ |
| 111 | --kernel bzImage \ |
| 112 | -drive file=rootfs.ext2,if=virtio,format=raw \ |
| 113 | -append "root=/dev/vda console=ttyS0" \ |
| 114 | -net none -nographic \ |
| 115 | -drive file=blknvme,if=none,id=mynvme,format=raw \ |
| 116 | -device nvme,drive=mynvme,serial=deadbeef,spdm_port=2323,spdm_trans=doe |
| 117 | |
| 118 | The ``spdm_trans`` argument defines the underlying transport type that is |
| 119 | emulated by QEMU. For an PCIe NVMe controller, both "doe" and "nvme" are |
| 120 | supported. Where, "doe" does SPDM transport over the PCIe extended capability |
| 121 | Data Object Exchange (DOE), and "nvme" uses the NVMe Admin Security |
| 122 | Send/Receive commands to implement the SPDM transport. |
| 123 | |
| 124 | .. _DMTF: |
| 125 | https://www.dmtf.org/standards/SPDM |
| 126 | |
| 127 | .. _SPDM Utils: |
| 128 | https://github.com/westerndigitalcorporation/spdm-utils |
| 129 | |
| 130 | .. _spdm emu: |
| 131 | https://github.com/dmtf/spdm-emu |
| 132 | |
| 133 | .. _Build libspdm: |
| 134 | https://github.com/westerndigitalcorporation/spdm-utils?tab=readme-ov-file#build-libspdm |
| 135 | |
| 136 | .. _Build SPDM Utils: |
| 137 | https://github.com/westerndigitalcorporation/spdm-utils?tab=readme-ov-file#build-the-binary |
| 138 | |
| 139 | .. _Run it as a server: |
| 140 | https://github.com/westerndigitalcorporation/spdm-utils#qemu-spdm-device-emulation |