1# Setting up Clef
2
3This document describes how Clef can be used in a more secure manner than executing it from your everyday laptop,
4in 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
11The Qubes operating system is based around virtual machines (qubes), where a set of virtual machines are configured, typically for
12different 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
21A 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
27The goal of this document is to describe how we can set up clef to provide secure transaction
28signing from a `vault` vm, to another networked qube which runs Dapps.
29
30### Setup
31
32There are two ways that this can be achieved: integrated via Qubes or integrated via networking.
33
34
35#### 1. Qubes Integrated
36
37Qubes provides a facility for inter-qubes communication via `qrexec`. A qube can request to make a cross-qube RPC request
38to another qube. The OS then asks the user if the call is permitted.
39
40![Example](qubes/qrexec-example.png)
41
42A 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
45This 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![Clef via qrexec](qubes/clef_qubes_qrexec.png)
50
51On the `target` qubes, we need to define the RPC service.
52
53[qubes.Clefsign](qubes/qubes.Clefsign):
54
55```bash
56#!/bin/bash
57
58SIGNER_BIN="/home/user/tools/clef/clef"
59SIGNER_CMD="/home/user/tools/gtksigner/gtkui.py -s $SIGNER_BIN"
60
61# Start clef if not already started
62if [ ! -S /home/user/.clef/clef.ipc ]; then
63	$SIGNER_CMD &
64	sleep 1
65fi
66
67# Should be started by now
68if [ -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
71fi
72
73```
74This RPC service is not complete (see notes about HTTP headers below), but works as a proof-of-concept.
75It will forward the data received on `stdin` (forwarded by the OS) to Clef's HTTP channel.
76
77It would have been possible to send data directly to the `/home/user/.clef/.clef.ipc`
78socket via e.g `nc -U /home/user/.clef/clef.ipc`, but the reason for sending the request
79data over `HTTP` instead of `IPC` is that we want the ability to forward `HTTP` headers.
80
81To enable the service:
82
83``` bash
84sudo cp qubes.Clefsign /etc/qubes-rpc/
85sudo chmod +x /etc/qubes-rpc/ qubes.Clefsign
86```
87
88This setup uses [gtksigner](https://github.com/holiman/gtksigner), which is a very minimal GTK-based UI that works well
89with minimal requirements.
90
91##### Client
92
93
94On 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/qubes-client.py):
98
99```python
100
101"""
102This implements a dispatcher which listens to localhost:8550, and proxies
103requests via qrexec to the service qubes.EthSign on a target domain
104"""
105
106import http.server
107import socketserver,subprocess
108
109PORT=8550
110TARGET_DOMAIN= 'debian-work'
111
112class 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
120with socketserver.TCPServer(("",PORT), Dispatcher) as httpd:
121    print("Serving at port", PORT)
122    httpd.serve_forever()
123
124
125```
126
127#### Testing
128
129To 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
138A dialog should pop up first to allow the IPC call:
139
140![one](qubes/qubes_newaccount-1.png)
141
142Followed by a GTK-dialog to approve the operation:
143
144![two](qubes/qubes_newaccount-2.png)
145
146To 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
151Make the request over http (`client` qube):
152```
153[user@work clef]$ cat newaccnt.json | curl -X POST -d @- http://localhost:8550
154```
155And it should show the same popups again.
156
157##### Pros and cons
158
159The 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
164However, 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
179The second way to set up Clef on a qubes system is to allow networking, and have Clef listen to a port which is accessible
180from other qubes.
181
182![Clef via http](qubes/clef_qubes_http.png)
183
184
185
186
187## USBArmory
188
189The [USB armory](https://inversepath.com/usbarmory) is an open source hardware design with an 800 MHz ARM processor. It is a pocket-size
190computer. When inserted into a laptop, it identifies itself as a USB network interface, basically adding another network
191to your computer. Over this new network interface, you can SSH into the device.
192
193Running Clef off a USB armory means that you can use the armory as a very versatile offline computer, which only
194ever connects to a local network between your computer and the device itself.
195
196Needless to say, while this model should be fairly secure against remote attacks, an attacker with physical access
197to the USB Armory would trivially be able to extract the contents of the device filesystem.
198
199