github.com/hhwill/poc-eth@v0.0.0-20240218063348-3bb107c90dbf/cmd/clef/docs/setup.md (about)

     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  ![Example](qubes/qrexec-example.png)
    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  ![Clef via qrexec](qubes/clef_qubes_qrexec.png)
    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  ![one](qubes/qubes_newaccount-1.png)
   141  
   142  Followed by a GTK-dialog to approve the operation
   143  
   144  ![two](qubes/qubes_newaccount-2.png)
   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  ![Clef via http](qubes/clef_qubes_http.png)
   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