|
| 1 | +# Setting up Clef |
| 2 | + |
| 3 | +This document describes how Clef can be used in a more secure manner than executing it from your everyday laptop, |
| 4 | +in order to ensure that the keys remain safe in the event that your computer should get compromised. |
| 5 | + |
| 6 | +## Qubes OS |
| 7 | + |
| 8 | + |
| 9 | +### Background |
| 10 | + |
| 11 | +The Qubes operating system is based around virtual machines (qubes), where a set of virtual machines are configured, typically for |
| 12 | +different purposes such as: |
| 13 | + |
| 14 | +- personal |
| 15 | + - Your personal email, browsing etc |
| 16 | +- work |
| 17 | + - Work email etc |
| 18 | +- vault |
| 19 | + - a VM without network access, where gpg-keys and/or keepass credentials are stored. |
| 20 | + |
| 21 | +A couple of dedicated virtual machines handle externalities: |
| 22 | + |
| 23 | +- sys-net provides networking to all other (network-enabled) machines |
| 24 | +- sys-firewall handles firewall rules |
| 25 | +- sys-usb handles USB devices, and can map usb-devices to certain qubes. |
| 26 | + |
| 27 | +The goal of this document is to describe how we can set up clef to provide secure transaction |
| 28 | +signing from a `vault` vm, to another networked qube which runs Dapps. |
| 29 | + |
| 30 | +### Setup |
| 31 | + |
| 32 | +There are two ways that this can be achieved: integrated via Qubes or integrated via networking. |
| 33 | + |
| 34 | + |
| 35 | +#### 1. Qubes Integrated |
| 36 | + |
| 37 | +Qubes provdes a facility for inter-qubes communication via `qrexec`. A qube can request to make a cross-qube RPC request |
| 38 | +to another qube. The OS then asks the user if the call is permitted. |
| 39 | + |
| 40 | + |
| 41 | + |
| 42 | +A policy-file can be created to allow such interaction. On the `target` domain, a service is invoked which can read the |
| 43 | +`stdin` from the `client` qube. |
| 44 | + |
| 45 | +This is how [Split GPG](https://www.qubes-os.org/doc/split-gpg/) is implemented. We can set up Clef the same way: |
| 46 | + |
| 47 | +##### Server |
| 48 | + |
| 49 | + |
| 50 | + |
| 51 | +On the `target` qubes, we need to define the rpc service. |
| 52 | + |
| 53 | +[qubes.Clefsign](qubes/qubes.Clefsign): |
| 54 | + |
| 55 | +```bash |
| 56 | +#!/bin/bash |
| 57 | + |
| 58 | +SIGNER_BIN="/home/user/tools/clef/clef" |
| 59 | +SIGNER_CMD="/home/user/tools/gtksigner/gtkui.py -s $SIGNER_BIN" |
| 60 | + |
| 61 | +# Start clef if not already started |
| 62 | +if [ ! -S /home/user/.clef/clef.ipc ]; then |
| 63 | + $SIGNER_CMD & |
| 64 | + sleep 1 |
| 65 | +fi |
| 66 | + |
| 67 | +# Should be started by now |
| 68 | +if [ -S /home/user/.clef/clef.ipc ]; then |
| 69 | + # Post incoming request to HTTP channel |
| 70 | + curl -H "Content-Type: application/json" -X POST -d @- http://localhost:8550 2>/dev/null |
| 71 | +fi |
| 72 | + |
| 73 | +``` |
| 74 | +This RPC service is not complete (see notes about HTTP headers below), but works as a proof-of-concept. |
| 75 | +It will forward the data received on `stdin` (forwarded by the OS) to Clef's HTTP channel. |
| 76 | + |
| 77 | +It would have been possible to send data directly to the `/home/user/.clef/.clef.ipc` |
| 78 | +socket via e.g `nc -U /home/user/.clef/clef.ipc`, but the reason for sending the request |
| 79 | +data over `HTTP` instead of `IPC` is that we want the ability to forward `HTTP` headers. |
| 80 | + |
| 81 | +To enable the service: |
| 82 | + |
| 83 | +``` bash |
| 84 | +sudo cp qubes.Clefsign /etc/qubes-rpc/ |
| 85 | +sudo chmod +x /etc/qubes-rpc/ qubes.Clefsign |
| 86 | +``` |
| 87 | + |
| 88 | +This setup uses [gtksigner](https://github.com/holiman/gtksigner), which is a very minimal GTK-based UI that works well |
| 89 | +with minimal requirements. |
| 90 | + |
| 91 | +##### Client |
| 92 | + |
| 93 | + |
| 94 | +On the `client` qube, we need to create a listener which will receive the request from the Dapp, and proxy it. |
| 95 | + |
| 96 | + |
| 97 | +[qubes-client.py](qubes/client/qubes-client.py): |
| 98 | + |
| 99 | +```python |
| 100 | + |
| 101 | +""" |
| 102 | +This implements a dispatcher which listens to localhost:8550, and proxies |
| 103 | +requests via qrexec to the service qubes.EthSign on a target domain |
| 104 | +""" |
| 105 | + |
| 106 | +import http.server |
| 107 | +import socketserver,subprocess |
| 108 | + |
| 109 | +PORT=8550 |
| 110 | +TARGET_DOMAIN= 'debian-work' |
| 111 | + |
| 112 | +class Dispatcher(http.server.BaseHTTPRequestHandler): |
| 113 | + def do_POST(self): |
| 114 | + post_data = self.rfile.read(int(self.headers['Content-Length'])) |
| 115 | + p = subprocess.Popen(['/usr/bin/qrexec-client-vm',TARGET_DOMAIN,'qubes.Clefsign'],stdin=subprocess.PIPE, stdout=subprocess.PIPE) |
| 116 | + output = p.communicate(post_data)[0] |
| 117 | + self.wfile.write(output) |
| 118 | + |
| 119 | + |
| 120 | +with socketserver.TCPServer(("",PORT), Dispatcher) as httpd: |
| 121 | + print("Serving at port", PORT) |
| 122 | + httpd.serve_forever() |
| 123 | + |
| 124 | + |
| 125 | +``` |
| 126 | + |
| 127 | +#### Testing |
| 128 | + |
| 129 | +To test the flow, if we have set up `debian-work` as the `target`, we can do |
| 130 | + |
| 131 | +```bash |
| 132 | +$ cat newaccnt.json |
| 133 | +{ "id": 0, "jsonrpc": "2.0","method": "account_new","params": []} |
| 134 | + |
| 135 | +$ cat newaccnt.json| qrexec-client-vm debian-work qubes.Clefsign |
| 136 | +``` |
| 137 | +
|
| 138 | +This should pop up first a dialog to allow the IPC call: |
| 139 | +
|
| 140 | + |
| 141 | +
|
| 142 | +Followed by a GTK-dialog to approve the operation |
| 143 | +
|
| 144 | + |
| 145 | +
|
| 146 | +To test the full flow, we use the client wrapper. Start it on the `client` qube: |
| 147 | +``` |
| 148 | +[user@work qubes]$ python3 qubes-client.py |
| 149 | +``` |
| 150 | +
|
| 151 | +Make the request over http (`client` qube): |
| 152 | +``` |
| 153 | +[user@work clef]$ cat newaccnt.json | curl -X POST -d @- http://localhost:8550 |
| 154 | +``` |
| 155 | +And it should show the same popups again. |
| 156 | +
|
| 157 | +##### Pros and cons |
| 158 | +
|
| 159 | +The benefits of this setup are: |
| 160 | +
|
| 161 | +- This is the qubes-os intended model for inter-qube communication, |
| 162 | +- and thus benefits from qubes-os dialogs and policies for user approval |
| 163 | +
|
| 164 | +However, it comes with a couple of drawbacks: |
| 165 | +
|
| 166 | +- The `qubes-gpg-client` must forward the http request via RPC to the `target` qube. When doing so, the proxy |
| 167 | + will either drop important headers, or replace them. |
| 168 | + - The `Host` header is most likely `localhost` |
| 169 | + - The `Origin` header must be forwarded |
| 170 | + - Information about the remote ip must be added as a `X-Forwarded-For`. However, Clef cannot always trust an `XFF` header, |
| 171 | + since malicious clients may lie about `XFF` in order to fool the http server into believing it comes from another address. |
| 172 | +- Even with a policy in place to allow rpc-calls between `caller` and `target`, there will be several popups: |
| 173 | + - One qubes-specific where the user specifies the `target` vm |
| 174 | + - One clef-specific to approve the transaction |
| 175 | + |
| 176 | +
|
| 177 | +#### 2. Network integrated |
| 178 | +
|
| 179 | +The second way to set up Clef on a qubes system is to allow networking, and have Clef listen to a port which is accessible |
| 180 | +form other qubes. |
| 181 | +
|
| 182 | + |
| 183 | +
|
| 184 | +
|
| 185 | +
|
| 186 | +
|
| 187 | +## USBArmory |
| 188 | +
|
| 189 | +The [USB armory](https://inversepath.com/usbarmory) is an open source hardware design with an 800 Mhz ARM processor. It is a pocket-size |
| 190 | +computer. When inserted into a laptop, it identifies itself as a USB network interface, basically adding another network |
| 191 | +to your computer. Over this new network interface, you can SSH into the device. |
| 192 | +
|
| 193 | +Running Clef off a USB armory means that you can use the armory as a very versatile offline computer, which only |
| 194 | +ever connects to a local network between your computer and the device itself. |
| 195 | +
|
| 196 | +Needless to say, the while this model should be fairly secure against remote attacks, an attacker with physical access |
| 197 | +to the USB Armory would trivially be able to extract the contents of the device filesystem. |
| 198 | +
|
0 commit comments