| 1 | .. _canokey: |
| 2 | |
| 3 | CanoKey QEMU |
| 4 | ------------ |
| 5 | |
| 6 | CanoKey [1]_ is an open-source secure key with supports of |
| 7 | |
| 8 | * U2F / FIDO2 with Ed25519 and HMAC-secret |
| 9 | * OpenPGP Card V3.4 with RSA4096, Ed25519 and more [2]_ |
| 10 | * PIV (NIST SP 800-73-4) |
| 11 | * HOTP / TOTP |
| 12 | * NDEF |
| 13 | |
| 14 | All these platform-independent features are in canokey-core [3]_. |
| 15 | |
| 16 | For different platforms, CanoKey has different implementations, |
| 17 | including both hardware implementations and virtual cards: |
| 18 | |
| 19 | * CanoKey STM32 [4]_ |
| 20 | * CanoKey Pigeon [5]_ |
| 21 | * (virt-card) CanoKey USB/IP |
| 22 | * (virt-card) CanoKey FunctionFS |
| 23 | |
| 24 | In QEMU, yet another CanoKey virt-card is implemented. |
| 25 | CanoKey QEMU exposes itself as a USB device to the guest OS. |
| 26 | |
| 27 | With the same software configuration as a hardware key, |
| 28 | the guest OS can use all the functionalities of a secure key as if |
| 29 | there was actually an hardware key plugged in. |
| 30 | |
| 31 | CanoKey QEMU provides much convenience for debugging: |
| 32 | |
| 33 | * libcanokey-qemu supports debugging output thus developers can |
| 34 | inspect what happens inside a secure key |
| 35 | * CanoKey QEMU supports trace event thus event |
| 36 | * QEMU USB stack supports pcap thus USB packet between the guest |
| 37 | and key can be captured and analysed |
| 38 | |
| 39 | Then for developers: |
| 40 | |
| 41 | * For developers on software with secure key support (e.g. FIDO2, OpenPGP), |
| 42 | they can see what happens inside the secure key |
| 43 | * For secure key developers, USB packets between guest OS and CanoKey |
| 44 | can be easily captured and analysed |
| 45 | |
| 46 | Also since this is a virtual card, it can be easily used in CI for testing |
| 47 | on code coping with secure key. |
| 48 | |
| 49 | Building |
| 50 | ======== |
| 51 | |
| 52 | libcanokey-qemu is required to use CanoKey QEMU. |
| 53 | |
| 54 | .. code-block:: shell |
| 55 | |
| 56 | git clone https://github.com/canokeys/canokey-qemu |
| 57 | mkdir canokey-qemu/build |
| 58 | pushd canokey-qemu/build |
| 59 | |
| 60 | If you want to install libcanokey-qemu in a different place, |
| 61 | add ``-DCMAKE_INSTALL_PREFIX=/path/to/your/place`` to cmake below. |
| 62 | |
| 63 | .. code-block:: shell |
| 64 | |
| 65 | cmake .. |
| 66 | make |
| 67 | make install # may need sudo |
| 68 | popd |
| 69 | |
| 70 | Then configuring and building: |
| 71 | |
| 72 | .. code-block:: shell |
| 73 | |
| 74 | # depending on your env, lib/pkgconfig can be lib64/pkgconfig |
| 75 | export PKG_CONFIG_PATH=/path/to/your/place/lib/pkgconfig:$PKG_CONFIG_PATH |
| 76 | ./configure --enable-canokey && make |
| 77 | |
| 78 | Using CanoKey QEMU |
| 79 | ================== |
| 80 | |
| 81 | CanoKey QEMU stores all its data on a file of the host specified by the argument |
| 82 | when invoking qemu. |
| 83 | |
| 84 | .. parsed-literal:: |
| 85 | |
| 86 | |qemu_system| -usb -device canokey,file=$HOME/.canokey-file |
| 87 | |
| 88 | Note: you should keep this file carefully as it may contain your private key! |
| 89 | |
| 90 | The first time when the file is used, it is created and initialized by CanoKey, |
| 91 | afterwards CanoKey QEMU would just read this file. |
| 92 | |
| 93 | After the guest OS boots, you can check that there is a USB device. |
| 94 | |
| 95 | For example, If the guest OS is an Linux machine. You may invoke lsusb |
| 96 | and find CanoKey QEMU there: |
| 97 | |
| 98 | .. code-block:: shell |
| 99 | |
| 100 | $ lsusb |
| 101 | Bus 001 Device 002: ID 20a0:42d4 Clay Logic CanoKey QEMU |
| 102 | |
| 103 | You may setup the key as guided in [6]_. The console for the key is at [7]_. |
| 104 | |
| 105 | Debugging |
| 106 | ========= |
| 107 | |
| 108 | CanoKey QEMU consists of two parts, ``libcanokey-qemu.so`` and ``canokey.c``, |
| 109 | the latter of which resides in QEMU. The former provides core functionality |
| 110 | of a secure key while the latter provides platform-dependent functions: |
| 111 | USB packet handling. |
| 112 | |
| 113 | If you want to trace what happens inside the secure key, when compiling |
| 114 | libcanokey-qemu, you should add ``-DQEMU_DEBUG_OUTPUT=ON`` in cmake command |
| 115 | line: |
| 116 | |
| 117 | .. code-block:: shell |
| 118 | |
| 119 | cmake .. -DQEMU_DEBUG_OUTPUT=ON |
| 120 | |
| 121 | If you want to trace events happened in canokey.c, use |
| 122 | |
| 123 | .. parsed-literal:: |
| 124 | |
| 125 | |qemu_system| --trace "canokey_*" \\ |
| 126 | -usb -device canokey,file=$HOME/.canokey-file |
| 127 | |
| 128 | If you want to capture USB packets between the guest and the host, you can: |
| 129 | |
| 130 | .. parsed-literal:: |
| 131 | |
| 132 | |qemu_system| -usb -device canokey,file=$HOME/.canokey-file,pcap=key.pcap |
| 133 | |
| 134 | Limitations |
| 135 | =========== |
| 136 | |
| 137 | Currently libcanokey-qemu.so has dozens of global variables as it was originally |
| 138 | designed for embedded systems. Thus one qemu instance can not have |
| 139 | multiple CanoKey QEMU running, namely you can not |
| 140 | |
| 141 | .. parsed-literal:: |
| 142 | |
| 143 | |qemu_system| -usb -device canokey,file=$HOME/.canokey-file \\ |
| 144 | -device canokey,file=$HOME/.canokey-file2 |
| 145 | |
| 146 | Also, there is no lock on canokey-file, thus two CanoKey QEMU instance |
| 147 | can not read one canokey-file at the same time. |
| 148 | |
| 149 | References |
| 150 | ========== |
| 151 | |
| 152 | .. [1] `<https://canokeys.org>`_ |
| 153 | .. [2] `<https://docs.canokeys.org/userguide/openpgp/#supported-algorithm>`_ |
| 154 | .. [3] `<https://github.com/canokeys/canokey-core>`_ |
| 155 | .. [4] `<https://github.com/canokeys/canokey-stm32>`_ |
| 156 | .. [5] `<https://github.com/canokeys/canokey-pigeon>`_ |
| 157 | .. [6] `<https://docs.canokeys.org/>`_ |
| 158 | .. [7] `<https://console.canokeys.org/>`_ |