mirror of
https://github.com/QubesOS/qubes-doc.git
synced 2024-12-29 09:16:22 -05:00
Merge branch 'pierwill-security-docs-semantic-newline-fixes'
This commit is contained in:
commit
f1b593aeee
@ -40,9 +40,18 @@ More information regarding configuration in the [README](https://github.com/Qube
|
||||
Security Considerations
|
||||
-----------------------
|
||||
|
||||
[Qubes security guidelines](/doc/security-guidelines/) dictate that USB devices should never be attached directly to dom0, since this can result in the entire system being compromised. However, in its default configuration, installing and using AEM requires attaching a USB drive (i.e., [mass storage device](https://en.wikipedia.org/wiki/USB_mass_storage_device_class)) directly to dom0. (The other option is to install AEM to an internal disk. However, this carries significant security implications, as explained [here](https://blog.invisiblethings.org/2011/09/07/anti-evil-maid.html).) This presents us with a classic security trade-off: each Qubes user must make a choice between protecting dom0 from a potentially malicious USB drive, on the one hand, and protecting the system from Evil Maid attacks, on the other hand. Given the practical feasibility of attacks like [BadUSB](https://srlabs.de/badusb/) and revelations regarding pervasive government hardware backdoors, this is no longer a straightforward decision. New, factory-sealed USB drives cannot simply be assumed to be "clean" (e.g., to have non-malicious microcontroller firmware). Therefore, it is up to each individual Qubes user to evaluate the relative risk of each attack vector against his or her security model.
|
||||
[Qubes security guidelines](/doc/security-guidelines/) dictate that USB devices should never be attached directly to dom0, since this can result in the entire system being compromised.
|
||||
However, in its default configuration, installing and using AEM requires attaching a USB drive (i.e., [mass storage device](https://en.wikipedia.org/wiki/USB_mass_storage_device_class)) directly to dom0.
|
||||
(The other option is to install AEM to an internal disk.
|
||||
However, this carries significant security implications, as explained [here](https://blog.invisiblethings.org/2011/09/07/anti-evil-maid.html).) This presents us with a classic security trade-off: each Qubes user must make a choice between protecting dom0 from a potentially malicious USB drive, on the one hand, and protecting the system from Evil Maid attacks, on the other hand.
|
||||
Given the practical feasibility of attacks like [BadUSB](https://srlabs.de/badusb/) and revelations regarding pervasive government hardware backdoors, this is no longer a straightforward decision.
|
||||
New, factory-sealed USB drives cannot simply be assumed to be "clean" (e.g., to have non-malicious microcontroller firmware).
|
||||
Therefore, it is up to each individual Qubes user to evaluate the relative risk of each attack vector against his or her security model.
|
||||
|
||||
For example, a user who frequently travels with a Qubes laptop holding sensitive data may be at a much higher risk of Evil Maid attacks than a home user with a stationary Qubes desktop. If the frequent traveler judges her risk of an Evil Maid attack to be higher than the risk of a malicious USB device, she might reasonably opt to install and use AEM. On the other hand, the home user might deem the probability of an Evil Maid attack occurring in her own home to be so low that there is a higher probability that any USB drive she purchases is already compromised, in which case she might reasonably opt never to attach any USB devices directly to dom0. (In either case, users can--and should--secure dom0 against further USB-related attacks through the use of a [USBVM](/doc/security-guidelines/#creating-and-using-a-usbvm).)
|
||||
For example, a user who frequently travels with a Qubes laptop holding sensitive data may be at a much higher risk of Evil Maid attacks than a home user with a stationary Qubes desktop.
|
||||
If the frequent traveler judges her risk of an Evil Maid attack to be higher than the risk of a malicious USB device, she might reasonably opt to install and use AEM.
|
||||
On the other hand, the home user might deem the probability of an Evil Maid attack occurring in her own home to be so low that there is a higher probability that any USB drive she purchases is already compromised, in which case she might reasonably opt never to attach any USB devices directly to dom0.
|
||||
(In either case, users can--and should--secure dom0 against further USB-related attacks through the use of a [USBVM](/doc/security-guidelines/#creating-and-using-a-usbvm).)
|
||||
|
||||
For more information, please see [this discussion thread](https://groups.google.com/d/msg/qubes-devel/EBc4to5IBdg/n1hfsHSfbqsJ).
|
||||
|
||||
|
@ -16,11 +16,23 @@ The Role of the Firewall
|
||||
|
||||
**[Firewalling in Qubes](/doc/firewall/) is not intended to be a leak-prevention mechanism.**
|
||||
|
||||
There are several reasons for this, which will be explained below. However, the main reason is that Qubes cannot prevent an attacker who has compromised one AppVM with restrictive firewall rules from leaking data via cooperative covert channels through another compromised AppVM with nonrestrictive firewall rules.
|
||||
There are several reasons for this, which will be explained below.
|
||||
However, the main reason is that Qubes cannot prevent an attacker who has compromised one AppVM with restrictive firewall rules from leaking data via cooperative covert channels through another compromised AppVM with nonrestrictive firewall rules.
|
||||
|
||||
For example, suppose you have an `email` AppVM. You have set the firewall rules for `email` such that it can communicate only with your email server. Now suppose that an attacker sends you a GPG-encrypted message which exploits a hypothetical bug in the GnuPG process. There are now multiple ways the attacker could proceed to leak data (such as confidential email messages) from `email`. The most obvious way is by simply emailing the data to himself. Another possibility is that the attacker has also compromised another one of your AppVMs, such as your `netvm`, which is normally assumed to be untrusted and has unrestricted access to the network. In this case, the attacker might move data from `email` to the `netvm` via a covert channel, such as the CPU cache. Such covert channels have been described and even implemented in some "lab environments" and might allow for bandwidths of even a few tens of bits/sec. It is unclear whether such channels could be implemented in a real world system, where multiple VMs are running at the same time, each handling tens or hundreds of processes, all using the same cache memory, but it is worth keeping in mind. Of course, this would require special malware written specifically to attack Qubes OS, and perhaps even a specific Qubes OS version and/or configuration. Nevertheless, it might be possible.
|
||||
For example, suppose you have an `email` AppVM.
|
||||
You have set the firewall rules for `email` such that it can communicate only with your email server.
|
||||
Now suppose that an attacker sends you a GPG-encrypted message which exploits a hypothetical bug in the GnuPG process.
|
||||
There are now multiple ways the attacker could proceed to leak data (such as confidential email messages) from `email`.
|
||||
The most obvious way is by simply emailing the data to himself.
|
||||
Another possibility is that the attacker has also compromised another one of your AppVMs, such as your `netvm`, which is normally assumed to be untrusted and has unrestricted access to the network.
|
||||
In this case, the attacker might move data from `email` to the `netvm` via a covert channel, such as the CPU cache.
|
||||
Such covert channels have been described and even implemented in some "lab environments" and might allow for bandwidths of even a few tens of bits/sec.
|
||||
It is unclear whether such channels could be implemented in a real world system, where multiple VMs are running at the same time, each handling tens or hundreds of processes, all using the same cache memory, but it is worth keeping in mind.
|
||||
Of course, this would require special malware written specifically to attack Qubes OS, and perhaps even a specific Qubes OS version and/or configuration.
|
||||
Nevertheless, it might be possible.
|
||||
|
||||
Note that physically air-gapped machines are not necessarily immune to this problem. Covert channels can potentially take many forms (e.g., sneakernet thumb drive, bluetooth, or even microphone and speakers).
|
||||
Note that physically air-gapped machines are not necessarily immune to this problem.
|
||||
Covert channels can potentially take many forms (e.g., sneakernet thumb drive, bluetooth, or even microphone and speakers).
|
||||
|
||||
For a further discussion of covert channels, see [this thread](https://groups.google.com/d/topic/qubes-users/AqZV65yZLuU/discussion) and [#817](https://github.com/QubesOS/qubes-issues/issues/817).
|
||||
|
||||
@ -31,10 +43,15 @@ In order to understand and attempt to prevent data leaks in Qubes, we must disti
|
||||
|
||||
1. **Intentional leaks.** Malicious software which actively tries to leak data out of an AppVM, perhaps via cooperative covert channels established with other malicious software in another AppVM or on some server via networking, if networking, even limited, is allowed for the AppVM.
|
||||
|
||||
2. **Intentional sniffing.** Malicious software trying to use side channels to, e.g., actively guess some key material used in another VM by some non-malicious software there (e.g., non-leak-proof GPG accidentally leaking out bits of the private key by generating some timing patterns when using this key for some crypto operation). Such attacks have been described in the academic literature, but it is doubtful that they would succeed in practice in a moderately busy general purpose system like Qubes OS where the attacker normally has no way to trigger the target crypto operation explicitly and it is normally required that the attacker trigger many such operations.
|
||||
2. **Intentional sniffing.** Malicious software trying to use side channels to, e.g., actively guess some key material used in another VM by some non-malicious software there (e.g., non-leak-proof GPG accidentally leaking out bits of the private key by generating some timing patterns when using this key for some crypto operation).
|
||||
Such attacks have been described in the academic literature, but it is doubtful that they would succeed in practice in a moderately busy general purpose system like Qubes OS where the attacker normally has no way to trigger the target crypto operation explicitly and it is normally required that the attacker trigger many such operations.
|
||||
|
||||
3. **Unintentional leaks.** Non-malicious software which is either buggy or doesn't maintain the privacy of user data, whether by design or accident. For example, software which automatically sends error reports to a remote server, where these reports contain details about the system which the user did not want to share.
|
||||
3. **Unintentional leaks.** Non-malicious software which is either buggy or doesn't maintain the privacy of user data, whether by design or accident.
|
||||
For example, software which automatically sends error reports to a remote server, where these reports contain details about the system which the user did not want to share.
|
||||
|
||||
Both Qubes firewall and an empty NetVM (i.e., setting the NetVM of an AppVM to "none") can fully protect against leaks of type 3. However, neither Qubes firewall nor an empty NetVM are guaranteed to protect against leaks of types 1 and 2. There are few effective, practical policy measures available to end-users today to stop the leaks of type 1. It is likely that the only way to fully protect against leaks of type 2 is to either pause or shut down all other VMs while performing sensitive operations in the target VM(s) (such as key generation).
|
||||
Both Qubes firewall and an empty NetVM (i.e., setting the NetVM of an AppVM to "none") can fully protect against leaks of type 3.
|
||||
However, neither Qubes firewall nor an empty NetVM are guaranteed to protect against leaks of types 1 and 2.
|
||||
There are few effective, practical policy measures available to end-users today to stop the leaks of type 1.
|
||||
It is likely that the only way to fully protect against leaks of type 2 is to either pause or shut down all other VMs while performing sensitive operations in the target VM(s) (such as key generation).
|
||||
|
||||
For further discussion, see [this thread](https://groups.google.com/d/topic/qubes-users/t0cmNfuVduw/discussion).
|
||||
|
@ -6,7 +6,8 @@ permalink: /doc/device-handling-security/
|
||||
|
||||
# Device Handling Security #
|
||||
|
||||
Any additional ability a VM gains is additional attack surface. It's a good idea to always attach the minimum entity required in a VM.
|
||||
Any additional ability a VM gains is additional attack surface.
|
||||
It's a good idea to always attach the minimum entity required in a VM.
|
||||
|
||||
For example, attaching a full USB-device offers [more attack surface than attaching a single block device][USB security], while
|
||||
attaching a full block device (e.g. `sda`) again offers more attack surface than attaching a single partition (e.g. `sda1`), since the targetVM doesn't have to parse the partition-table.
|
||||
@ -15,22 +16,38 @@ attaching a full block device (e.g. `sda`) again offers more attack surface than
|
||||
|
||||
## PCI Security ##
|
||||
|
||||
Attaching a PCI device to a qube has serious security implications. It exposes the device driver running in the qube to an external device (and sourceVM, which contains the device - e.g. `sys-usb`). In many cases a malicious device can choose what driver will be loaded (for example by manipulating device metadata like vendor and product identifiers) - even if the intended driver is sufficiently secure, the device may try to attack a different, less secure driver.
|
||||
Furthermore that VM has full control of the device and may be able to exploit bugs or malicious implementation of the hardware, as well as plain security problems the hardware may pose. (For example, if you attach a USB controller, all the security implications of USB passthrough apply as well.)
|
||||
Attaching a PCI device to a qube has serious security implications.
|
||||
It exposes the device driver running in the qube to an external device (and sourceVM, which contains the device - e.g. `sys-usb`).
|
||||
In many cases a malicious device can choose what driver will be loaded (for example by manipulating device metadata like vendor and product identifiers) - even if the intended driver is sufficiently secure, the device may try to attack a different, less secure driver.
|
||||
Furthermore that VM has full control of the device and may be able to exploit bugs or malicious implementation of the hardware, as well as plain security problems the hardware may pose.
|
||||
(For example, if you attach a USB controller, all the security implications of USB passthrough apply as well.)
|
||||
|
||||
By default, Qubes requires any PCI device to be resettable from the outside (i.e. via the hypervisor), which completely reinitialises the device. This ensures that any device that was attached to a compromised VM, even if that VM was able to use bugs in the PCI device to inject malicious code, can be trusted again. (Or at least as trusted as it was when Qubes booted.)
|
||||
By default, Qubes requires any PCI device to be resettable from the outside (i.e. via the hypervisor), which completely reinitialises the device.
|
||||
This ensures that any device that was attached to a compromised VM, even if that VM was able to use bugs in the PCI device to inject malicious code, can be trusted again.
|
||||
(Or at least as trusted as it was when Qubes booted.)
|
||||
|
||||
Some devices do not implement a reset option. In these cases, Qubes by default does not allow attaching the device to any VM. If you decide to override this precaution, beware that the device may only be trusted when attached to the first VM. Afterwards, it should be **considered tainted** until the whole system is shut down. Even without malicious intent, usage data may be leaked.
|
||||
Some devices do not implement a reset option.
|
||||
In these cases, Qubes by default does not allow attaching the device to any VM.
|
||||
If you decide to override this precaution, beware that the device may only be trusted when attached to the first VM.
|
||||
Afterwards, it should be **considered tainted** until the whole system is shut down.
|
||||
Even without malicious intent, usage data may be leaked.
|
||||
|
||||
In case device reset is disabled for any reason, detaching the device should be considered a risk. Ideally, devices for which the `no-strict-reset` option is set are attached once to a VM which isn't shut down until the system is shut down.
|
||||
In case device reset is disabled for any reason, detaching the device should be considered a risk.
|
||||
Ideally, devices for which the `no-strict-reset` option is set are attached once to a VM which isn't shut down until the system is shut down.
|
||||
|
||||
Additionally, Qubes restricts the config-space a VM may use to communicate with a PCI device. Only whitelisted registers are accessible. However, some devices or applications require full PCI access. In these cases, the whole config-space may be allowed. you're potentially weakening the device isolation, especially if your system is not equipped with a VT-d Interrupt Remapping unit. This increases the VM's ability to run a [side channel attack] and vulnerability to the same.
|
||||
Additionally, Qubes restricts the config-space a VM may use to communicate with a PCI device.
|
||||
Only whitelisted registers are accessible.
|
||||
However, some devices or applications require full PCI access.
|
||||
In these cases, the whole config-space may be allowed.
|
||||
You're potentially weakening the device isolation, especially if your system is not equipped with a VT-d Interrupt Remapping unit.
|
||||
This increases the VM's ability to run a [side channel attack] and vulnerability to the same.
|
||||
See [Xen PCI Passthrough: PV guests and PCI quirks] and [Software Attacks on Intel VT-d] \(page 7) for more details.
|
||||
|
||||
|
||||
## USB Security ##
|
||||
|
||||
The connection of an untrusted USB device to dom0 is a security risk since the device can attack an arbitrary USB driver (which are included in the linux kernel), exploit bugs during partition-table-parsing or simply pretend to be a keyboard. There are many ready-to-use implementations of such attacks, e.g. a [USB Rubber Ducky][rubber duck].
|
||||
The connection of an untrusted USB device to dom0 is a security risk since the device can attack an arbitrary USB driver (which are included in the linux kernel), exploit bugs during partition-table-parsing or simply pretend to be a keyboard.
|
||||
There are many ready-to-use implementations of such attacks, e.g. a [USB Rubber Ducky][rubber duck].
|
||||
The whole USB stack is put to work to parse the data presented by the USB device in order to determine if it is a USB mass storage device, to read its configuration, etc.
|
||||
This happens even if the drive is then assigned and mounted in another qube.
|
||||
|
||||
|
@ -16,9 +16,8 @@ The Qubes Firewall
|
||||
Understanding firewalling in Qubes
|
||||
----------------------------------
|
||||
|
||||
Every qube in Qubes is connected to the network via a FirewallVM, which is used to
|
||||
enforce network-level policies. By default there is one default FirewallVM, but
|
||||
the user is free to create more, if needed.
|
||||
Every qube in Qubes is connected to the network via a FirewallVM, which is used to enforce network-level policies.
|
||||
By default there is one default FirewallVM, but the user is free to create more, if needed.
|
||||
|
||||
For more information, see the following:
|
||||
|
||||
@ -29,24 +28,19 @@ For more information, see the following:
|
||||
How to edit rules
|
||||
-----------------
|
||||
|
||||
In order to edit rules for a given qube, select it in the Qubes
|
||||
Manager and press the "firewall" button:
|
||||
In order to edit rules for a given qube, select it in the Qubes Manager and press the "firewall" button:
|
||||
|
||||
![r2b1-manager-firewall.png](/attachment/wiki/QubesFirewall/r2b1-manager-firewall.png)
|
||||
|
||||
*R4.0 note:* ICMP and DNS are no longer accessible in the GUI, but can be changed
|
||||
via `qvm-firewall` described below. Connections to Updates Proxy are no longer made
|
||||
over network so can not be allowed or blocked with firewall rules
|
||||
(see [R4.0 Updates proxy](https://www.qubes-os.org/doc/software-update-vm/) for more detail.
|
||||
*R4.0 note:* ICMP and DNS are no longer accessible in the GUI, but can be changed via `qvm-firewall` described below.
|
||||
Connections to Updates Proxy are no longer made over network so can not be allowed or blocked with firewall rules (see [R4.0 Updates proxy](https://www.qubes-os.org/doc/software-update-vm/) for more detail.
|
||||
|
||||
Note that if you specify a rule by DNS name it will be resolved to IP(s)
|
||||
*at the moment of applying the rules*, and not on the fly for each new
|
||||
connection. This means it will not work for servers using load balancing. More
|
||||
on this in the message quoted below.
|
||||
Note that if you specify a rule by DNS name it will be resolved to IP(s) *at the moment of applying the rules*, and not on the fly for each new connection.
|
||||
This means it will not work for servers using load balancing.
|
||||
More on this in the message quoted below.
|
||||
|
||||
Alternatively, one can use the `qvm-firewall` command from Dom0 to edit the
|
||||
firewall rules by hand. The firewall rules for each VM are saved in an XML file
|
||||
in that VM's directory in dom0:
|
||||
Alternatively, one can use the `qvm-firewall` command from Dom0 to edit the firewall rules by hand.
|
||||
The firewall rules for each VM are saved in an XML file in that VM's directory in dom0:
|
||||
|
||||
/var/lib/qubes/appvms/<vm-name>/firewall.xml
|
||||
|
||||
@ -55,31 +49,22 @@ This equates to somewhere between 35 and 39 rules.
|
||||
If this limit is exceeded, the qube will not start.
|
||||
The limit was removed in R4.0.
|
||||
|
||||
It is possible to work around this limit by enforcing the rules on the qube itself
|
||||
by putting appropriate rules in `/rw/config`.
|
||||
It is possible to work around this limit by enforcing the rules on the qube itself by putting appropriate rules in `/rw/config`.
|
||||
See [Where to put firewall rules](#where-to-put-firewall-rules).
|
||||
In complex cases, it might be appropriate to load a ruleset using `iptables-restore`
|
||||
called from `/rw/config/rc.local`.
|
||||
In complex cases, it might be appropriate to load a ruleset using `iptables-restore` called from `/rw/config/rc.local`.
|
||||
|
||||
|
||||
Reconnecting VMs after a NetVM reboot
|
||||
-------------------------------------
|
||||
|
||||
Normally Qubes doesn't let the user stop a NetVM if there are other qubes
|
||||
running which use it as their own NetVM. But in case the NetVM stops for
|
||||
whatever reason (e.g. it crashes, or the user forces its shutdown via qvm-kill
|
||||
via terminal in Dom0), Qubes R4.0 will often automatically repair the
|
||||
connection. If it does not, then there is an easy way to restore the connection to
|
||||
the NetVM by issuing:
|
||||
Normally Qubes doesn't let the user stop a NetVM if there are other qubes running which use it as their own NetVM.
|
||||
But in case the NetVM stops for whatever reason (e.g. it crashes, or the user forces its shutdown via qvm-kill via terminal in Dom0), Qubes R4.0 will often automatically repair the connection.
|
||||
If it does not, then there is an easy way to restore the connection to the NetVM by issuing:
|
||||
|
||||
` qvm-prefs <vm> netvm <netvm> `
|
||||
|
||||
Normally qubes do not connect directly to the actual NetVM which has networking
|
||||
devices, but rather to the default sys-firewall first, and in most cases it would
|
||||
be the NetVM that will crash, e.g. in response to S3 sleep/restore or other
|
||||
issues with WiFi drivers. In that case it is only necessary to issue the above
|
||||
command once, for the sys-firewall (this assumes default VM-naming used by the
|
||||
default Qubes installation):
|
||||
Normally qubes do not connect directly to the actual NetVM which has networking devices, but rather to the default sys-firewall first, and in most cases it would be the NetVM that will crash, e.g. in response to S3 sleep/restore or other issues with WiFi drivers.
|
||||
In that case it is only necessary to issue the above command once, for the sys-firewall (this assumes default VM-naming used by the default Qubes installation):
|
||||
|
||||
` qvm-prefs sys-firewall netvm sys-net `
|
||||
|
||||
@ -107,18 +92,14 @@ Enabling networking between two qubes
|
||||
-------------------------------------
|
||||
|
||||
Normally any networking traffic between qubes is prohibited for security reasons.
|
||||
However, in special situations, one might want to selectively allow specific qubes
|
||||
to establish networking connectivity between each other. For example,
|
||||
this might be useful in some development work, when one wants to test
|
||||
networking code, or to allow file exchange between HVM domains (which do not
|
||||
have Qubes tools installed) via SMB/scp/NFS protocols.
|
||||
However, in special situations, one might want to selectively allow specific qubes to establish networking connectivity between each other.
|
||||
For example, this might be useful in some development work, when one wants to test networking code, or to allow file exchange between HVM domains (which do not have Qubes tools installed) via SMB/scp/NFS protocols.
|
||||
|
||||
In order to allow networking between qubes A and B follow these steps:
|
||||
|
||||
* Make sure both A and B are connected to the same firewall vm (by default all
|
||||
VMs use the same firewall VM).
|
||||
* Note the Qubes IP addresses assigned to both qubes. This can be done using the
|
||||
`qvm-ls -n` command, or via the Qubes Manager preferences pane for each qube.
|
||||
* Make sure both A and B are connected to the same firewall vm (by default all VMs use the same firewall VM).
|
||||
* Note the Qubes IP addresses assigned to both qubes.
|
||||
This can be done using the `qvm-ls -n` command, or via the Qubes Manager preferences pane for each qube.
|
||||
* Start both qubes, and also open a terminal in the firewall VM
|
||||
* In the firewall VM's terminal enter the following iptables rule:
|
||||
|
||||
@ -132,19 +113,12 @@ sudo iptables -I FORWARD 2 -s <IP address of A> -d <IP address of B> -j ACCEPT
|
||||
sudo iptables -I INPUT -s <IP address of A> -j ACCEPT
|
||||
~~~
|
||||
|
||||
* Now you should be able to reach B from A -- test it using e.g. ping
|
||||
issued from A. Note however, that this doesn't allow you to reach A from
|
||||
B -- for this you would need two more rules, with A and B swapped.
|
||||
* If everything works as expected, then the above iptables rules should be
|
||||
written into firewallVM's `qubes-firewall-user-script` script which is run
|
||||
on every firewall update, and A and B's `rc.local` script which is run when
|
||||
the qube is launched. The `qubes-firewall-user-script` is necessary because Qubes
|
||||
orders every firewallVM to update all the rules whenever a new connected qube is
|
||||
started. If we didn't enter our rules into this "hook" script, then shortly
|
||||
our custom rules would disappear and inter-VM networking would stop working.
|
||||
Here's an example how to update the script (note that, by default, there is no
|
||||
script file present, so we will probably be creating it, unless we had some other
|
||||
custom rules defined earlier in this firewallVM):
|
||||
* Now you should be able to reach B from A -- test it using e.g. ping issued from A.
|
||||
Note however, that this doesn't allow you to reach A from B -- for this you would need two more rules, with A and B swapped.
|
||||
* If everything works as expected, then the above iptables rules should be written into firewallVM's `qubes-firewall-user-script` script which is run on every firewall update, and A and B's `rc.local` script which is run when the qube is launched.
|
||||
The `qubes-firewall-user-script` is necessary because Qubes orders every firewallVM to update all the rules whenever a new connected qube is started.
|
||||
If we didn't enter our rules into this "hook" script, then shortly our custom rules would disappear and inter-VM networking would stop working.
|
||||
Here's an example how to update the script (note that, by default, there is no script file present, so we will probably be creating it, unless we had some other custom rules defined earlier in this firewallVM):
|
||||
|
||||
~~~
|
||||
[user@sys-firewall ~]$ sudo bash
|
||||
@ -164,10 +138,7 @@ sudo iptables -I INPUT -s <IP address of A> -j ACCEPT
|
||||
Port forwarding to a qube from the outside world
|
||||
------------------------------------------------
|
||||
|
||||
In order to allow a service present in a qube to be exposed to the outside world
|
||||
in the default setup (where the qube has sys-firewall as network VM, which in
|
||||
turn has sys-net as network VM)
|
||||
the following needs to be done:
|
||||
In order to allow a service present in a qube to be exposed to the outside world in the default setup (where the qube has sys-firewall as network VM, which in turn has sys-net as network VM) the following needs to be done:
|
||||
|
||||
* In the sys-net VM:
|
||||
* Route packets from the outside world to the sys-firewall VM
|
||||
@ -178,9 +149,7 @@ the following needs to be done:
|
||||
* In the qube:
|
||||
* Allow packets through the qube firewall to reach the service
|
||||
|
||||
As an example we can take the use case of a web server listening on port 443
|
||||
that we want to expose on our physical interface eth0, but only to our local
|
||||
network 192.168.x.0/24.
|
||||
As an example we can take the use case of a web server listening on port 443 that we want to expose on our physical interface eth0, but only to our local network 192.168.x.0/24.
|
||||
|
||||
> Note: To have all interfaces available and configured, make sure the 3 qubes are up and running
|
||||
|
||||
@ -188,26 +157,22 @@ network 192.168.x.0/24.
|
||||
|
||||
**1. Route packets from the outside world to the FirewallVM**
|
||||
|
||||
From a Terminal window in sys-net VM, take note of the 'Interface name' and
|
||||
'IP address' on which you want to expose your service (i.e. ens5, 192.168.x.x)
|
||||
From a Terminal window in sys-net VM, take note of the 'Interface name' and 'IP address' on which you want to expose your service (i.e. ens5, 192.168.x.x)
|
||||
|
||||
` ifconfig | grep -i cast `
|
||||
|
||||
> Note: The vifx.0 interface is the one connected to your sys-firewall VM so it
|
||||
is _not_ an outside world interface...
|
||||
|
||||
From a Terminal window in sys-firewall VM, take note of the 'IP address' for
|
||||
interface Eth0 (10.137.1.x or 10.137.0.x in Qubes R4)
|
||||
From a Terminal window in sys-firewall VM, take note of the 'IP address' for interface Eth0 (10.137.1.x or 10.137.0.x in Qubes R4)
|
||||
|
||||
` ifconfig | grep -i cast `
|
||||
|
||||
Back into the sys-net VM's Terminal, code a natting firewall rule to route
|
||||
traffic on the outside interface for the service to the sys-firewall VM
|
||||
Back into the sys-net VM's Terminal, code a natting firewall rule to route traffic on the outside interface for the service to the sys-firewall VM
|
||||
|
||||
` iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -d 192.168.x.x -j DNAT --to-destination 10.137.1.x `
|
||||
|
||||
Code the appropriate new filtering firewall rule to allow new connections for
|
||||
the service
|
||||
Code the appropriate new filtering firewall rule to allow new connections for the service
|
||||
|
||||
` iptables -I FORWARD 2 -i eth0 -d 10.137.1.x -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT `
|
||||
|
||||
@ -218,8 +183,7 @@ the service
|
||||
|
||||
`nft add rule ip qubes-firewall forward meta iifname eth0 ip daddr 10.137.0.x tcp dport 443 ct state new counter accept`
|
||||
|
||||
Verify you are cutting through the sys-net VM firewall by looking at its
|
||||
counters (column 2)
|
||||
Verify you are cutting through the sys-net VM firewall by looking at its counters (column 2)
|
||||
|
||||
` iptables -t nat -L -v -n `
|
||||
|
||||
@ -233,8 +197,7 @@ Send a test packet by trying to connect to the service from an external device
|
||||
|
||||
` telnet 192.168.x.x 443 `
|
||||
|
||||
Once you have confirmed that the counters increase, store these command in
|
||||
`/rw/config/rc.local` so they get set on sys-net start-up
|
||||
Once you have confirmed that the counters increase, store these command in `/rw/config/rc.local` so they get set on sys-net start-up
|
||||
|
||||
` sudo nano /rw/config/rc.local `
|
||||
|
||||
@ -303,18 +266,15 @@ Finally make this file executable, so it runs at each boot
|
||||
|
||||
**2. Route packets from the FirewallVM to the VM**
|
||||
|
||||
From a Terminal window in the VM where the service to be exposed is running, take note of the 'IP address' for
|
||||
interface Eth0 (i.e. 10.137.2.y, 10.137.0.y in Qubes R4)
|
||||
From a Terminal window in the VM where the service to be exposed is running, take note of the 'IP address' for interface Eth0 (i.e. 10.137.2.y, 10.137.0.y in Qubes R4)
|
||||
|
||||
` ifconfig | grep -i cast `
|
||||
|
||||
Back into the sys-firewall VM's Terminal, code a natting firewall rule to route
|
||||
traffic on its outside interface for the service to the qube
|
||||
Back into the sys-firewall VM's Terminal, code a natting firewall rule to route traffic on its outside interface for the service to the qube
|
||||
|
||||
` iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -d 10.137.1.x -j DNAT --to-destination 10.137.2.y `
|
||||
|
||||
Code the appropriate new filtering firewall rule to allow new connections for
|
||||
the service
|
||||
Code the appropriate new filtering firewall rule to allow new connections for the service
|
||||
|
||||
` iptables -I FORWARD 2 -i eth0 -s 192.168.x.0/24 -d 10.137.2.y -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT `
|
||||
|
||||
@ -392,8 +352,8 @@ sudo chmod +x /rw/config/qubes-firewall-user-script
|
||||
|
||||
**3. Allow packets into the qube to reach the service**
|
||||
|
||||
Here no routing is required, only filtering. Proceed in the same way as above
|
||||
but store the filtering rule in the `/rw/config/rc.local` script.
|
||||
Here no routing is required, only filtering.
|
||||
Proceed in the same way as above but store the filtering rule in the `/rw/config/rc.local` script.
|
||||
|
||||
` sudo name /rw/config/rc.local `
|
||||
|
||||
@ -418,17 +378,12 @@ if ! iptables -n -L FORWARD | grep --quiet MY-HTTPS; then
|
||||
fi
|
||||
~~~
|
||||
|
||||
This time testing should allow connectivity to the service as long as the
|
||||
service is up :-)
|
||||
This time testing should allow connectivity to the service as long as the service is up :-)
|
||||
|
||||
|
||||
Where to put firewall rules
|
||||
---------------------------
|
||||
|
||||
Implicit in the above example [scripts](/doc/config-files/), but worth
|
||||
calling attention to: for all qubes *except* AppVMs supplying networking,
|
||||
iptables commands should be added to the `/rw/config/rc.local` script. For
|
||||
AppVMs supplying networking (`sys-firewall` inclusive),
|
||||
iptables commands should be added to
|
||||
`/rw/config/qubes-firewall-user-script`.
|
||||
Implicit in the above example [scripts](/doc/config-files/), but worth calling attention to: for all qubes *except* AppVMs supplying networking, iptables commands should be added to the `/rw/config/rc.local` script.
|
||||
For AppVMs supplying networking (`sys-firewall` inclusive), iptables commands should be added to `/rw/config/qubes-firewall-user-script`.
|
||||
|
||||
|
@ -18,17 +18,10 @@ redirect_from:
|
||||
|
||||
## What is Split GPG and why should I use it instead of the standard GPG? ##
|
||||
|
||||
Split GPG implements a concept similar to having a smart card with your
|
||||
private GPG keys, except that the role of the "smart card" plays another Qubes
|
||||
AppVM. This way one, not-so-trusted domain, e.g. the one where Thunderbird is
|
||||
running, can delegate all crypto operations, such as encryption/decryption
|
||||
and signing to another, more trusted, network-isolated, domain. This way
|
||||
the compromise of your domain where Thunderbird or another client app is
|
||||
running -- arguably a not-so-unthinkable scenario -- does not allow the
|
||||
attacker to automatically also steal all your keys. (We should make a rather
|
||||
obvious comment here that the so-often-used passphrases on private keys are
|
||||
pretty meaningless because the attacker can easily set up a simple backdoor
|
||||
which would wait until the user enters the passphrase and steal the key then.)
|
||||
Split GPG implements a concept similar to having a smart card with your private GPG keys, except that the role of the "smart card" plays another Qubes AppVM.
|
||||
This way one, not-so-trusted domain, e.g. the one where Thunderbird is running, can delegate all crypto operations, such as encryption/decryption and signing to another, more trusted, network-isolated, domain.
|
||||
This way the compromise of your domain where Thunderbird or another client app is running -- arguably a not-so-unthinkable scenario -- does not allow the attacker to automatically also steal all your keys.
|
||||
(We should make a rather obvious comment here that the so-often-used passphrases on private keys are pretty meaningless because the attacker can easily set up a simple backdoor which would wait until the user enters the passphrase and steal the key then.)
|
||||
|
||||
The diagram below presents the big picture of Split GPG architecture.
|
||||
|
||||
@ -36,54 +29,35 @@ The diagram below presents the big picture of Split GPG architecture.
|
||||
|
||||
### Advantages of Split GPG vs. traditional GPG with a smart card ###
|
||||
|
||||
It is often thought that the use of smart cards for private key storage
|
||||
guarantees ultimate safety. While this might be true (unless the attacker
|
||||
can find a usually-very-expensive-and-requiring-physical-presence way to
|
||||
extract the key from the smart card) but only with regards to the safety of
|
||||
the private key itself. However, there is usually nothing that could stop
|
||||
the attacker from requesting the smart card to perform decryption of all the
|
||||
user documents the attacker has found or need to decrypt. In other words,
|
||||
while protecting the user's private key is an important task, we should not
|
||||
forget that ultimately it is the user data that are to be protected and that
|
||||
the smart card chip has no way of knowing the requests to decrypt documents
|
||||
are now coming from the attacker's script and not from the user sitting in
|
||||
front of the monitor. (Similarly the smart card doesn't make the process
|
||||
of digitally signing a document or a transaction in any way more secure --
|
||||
the user cannot know what the chip is really signing. Unfortunately this
|
||||
problem of signing reliability is not solvable by Split GPG)
|
||||
It is often thought that the use of smart cards for private key storage guarantees ultimate safety.
|
||||
While this might be true (unless the attacker can find a usually-very-expensive-and-requiring-physical-presence way to extract the key from the smart card) but only with regards to the safety of the private key itself.
|
||||
However, there is usually nothing that could stop the attacker from requesting the smart card to perform decryption of all the user documents the attacker has found or need to decrypt.
|
||||
In other words, while protecting the user's private key is an important task, we should not forget that ultimately it is the user data that are to be protected and that the smart card chip has no way of knowing the requests to decrypt documents are now coming from the attacker's script and not from the user sitting in front of the monitor.
|
||||
(Similarly the smart card doesn't make the process of digitally signing a document or a transaction in any way more secure -- the user cannot know what the chip is really signing.
|
||||
Unfortunately this problem of signing reliability is not solvable by Split GPG)
|
||||
|
||||
With Qubes Split GPG this problem is drastically minimized, because each time
|
||||
the key is to be used the user is asked for consent (with a definable time
|
||||
out, 5 minutes by default), plus is always notified each time the key is used
|
||||
via a tray notification from the domain where GPG backend is running. This
|
||||
way it would be easy to spot unexpected requests to decrypt documents.
|
||||
With Qubes Split GPG this problem is drastically minimized, because each time the key is to be used the user is asked for consent (with a definable time out, 5 minutes by default), plus is always notified each time the key is used via a tray notification from the domain where GPG backend is running.
|
||||
This way it would be easy to spot unexpected requests to decrypt documents.
|
||||
|
||||
![r2-split-gpg-1.png](/attachment/wiki/SplitGpg/r2-split-gpg-1.png)
|
||||
![r2-split-gpg-3.png](/attachment/wiki/SplitGpg/r2-split-gpg-3.png)
|
||||
|
||||
### Current limitations ###
|
||||
|
||||
- Current implementation requires importing of public keys to the vault
|
||||
domain. This opens up an avenue to attack the gpg running in the backend domain
|
||||
via a hypothetical bug in public key importing code. See ticket [#474] for more
|
||||
details and plans how to get around this problem, as well as the section on
|
||||
[using split GPG with subkeys] below.
|
||||
- Current implementation requires importing of public keys to the vault domain.
|
||||
This opens up an avenue to attack the gpg running in the backend domain via a hypothetical bug in public key importing code.
|
||||
See ticket [#474] for more details and plans how to get around this problem, as well as the section on [using split GPG with subkeys] below.
|
||||
|
||||
- It doesn't solve the problem of allowing the user to know what is to be
|
||||
signed before the operation gets approved. Perhaps the GPG backend domain
|
||||
could start a DisposableVM and have the to-be-signed document displayed
|
||||
there? To Be Determined.
|
||||
- It doesn't solve the problem of allowing the user to know what is to be signed before the operation gets approved.
|
||||
Perhaps the GPG backend domain could start a DisposableVM and have the to-be-signed document displayed there? To Be Determined.
|
||||
|
||||
- The Split GPG client will fail to sign or encrypt if the private key in the
|
||||
GnuPG backend is protected by a passphrase. It will give an `Inappropriate ioctl
|
||||
for device` error. Do not set passphrases for the private keys in the GPG
|
||||
backend domain. Doing so won't provide any extra security anyway, as explained
|
||||
[above][intro] and [below][using split GPG with subkeys]. If you are generating
|
||||
a new key pair, or if you have a private key that already has a passphrase, you
|
||||
can use `gpg2 --edit-key <key_id>` then `passwd` to set an empty passphrase.
|
||||
Note that `pinentry` might show an error when you try to set an empty
|
||||
passphrase, but it will still make the change. (See [this StackExchange
|
||||
answer][se-pinentry] for more information.)
|
||||
- The Split GPG client will fail to sign or encrypt if the private key in the GnuPG backend is protected by a passphrase.
|
||||
It will give an `Inappropriate ioctl for device` error.
|
||||
Do not set passphrases for the private keys in the GPG backend domain.
|
||||
Doing so won't provide any extra security anyway, as explained [above][intro] and [below][using split GPG with subkeys].
|
||||
If you are generating a new key pair, or if you have a private key that already has a passphrase, you can use `gpg2 --edit-key <key_id>` then `passwd` to set an empty passphrase.
|
||||
Note that `pinentry` might show an error when you try to set an empty passphrase, but it will still make the change.
|
||||
(See [this StackExchange answer][se-pinentry] for more information.)
|
||||
|
||||
## Configuring Split GPG ##
|
||||
|
||||
@ -91,8 +65,7 @@ In dom0, make sure the `qubes-gpg-split-dom0` package is installed.
|
||||
|
||||
[user@dom0 ~]$ sudo qubes-dom0-update qubes-gpg-split-dom0
|
||||
|
||||
If using templates based on Debian or Whonix, make sure you have the `qubes-gpg-split`
|
||||
package installed.
|
||||
If using templates based on Debian or Whonix, make sure you have the `qubes-gpg-split` package installed.
|
||||
|
||||
[user@debian-8 ~]$ sudo apt install qubes-gpg-split
|
||||
|
||||
@ -100,15 +73,13 @@ For Fedora.
|
||||
|
||||
[user@fedora-25 ~]$ sudo dnf install qubes-gpg-split
|
||||
|
||||
Start with creating a dedicated AppVM for storing your keys (the GPG backend
|
||||
domain). It is recommended that this domain be network disconnected (set its
|
||||
netvm to `none`) and only used for this one purpose. In later examples this
|
||||
AppVM is named `work-gpg`, but of course it might have any other name.
|
||||
Start with creating a dedicated AppVM for storing your keys (the GPG backend domain).
|
||||
It is recommended that this domain be network disconnected (set its netvm to `none`) and only used for this one purpose.
|
||||
In later examples this AppVM is named `work-gpg`, but of course it might have any other name.
|
||||
|
||||
### Setting up the GPG backend domain ###
|
||||
|
||||
Make sure that gpg is installed there, and there are some private keys in the
|
||||
keyring, e.g.:
|
||||
Make sure that gpg is installed there, and there are some private keys in the keyring, e.g.:
|
||||
|
||||
[user@work-gpg ~]$ gpg -K
|
||||
/home/user/.gnupg/secring.gpg
|
||||
@ -118,10 +89,9 @@ keyring, e.g.:
|
||||
ssb 4096R/30498E2A 2012-11-15
|
||||
(...)
|
||||
|
||||
This is pretty much all that is required.
|
||||
However, you might want to modify the default timeout: this tells the backend for how long the user's approval for key access should be valid.
|
||||
(The default is 5 minutes.)
|
||||
You can change this via the `QUBES_GPG_AUTOACCEPT` variable.
|
||||
This is pretty much all that is required.
|
||||
However, you might want to modify the default timeout: this tells the backend for how long the user's approval for key access should be valid.
|
||||
(The default is 5 minutes.) You can change this via the `QUBES_GPG_AUTOACCEPT` variable.
|
||||
You can override it e.g. in `~/.profile`:
|
||||
|
||||
[user@work-gpg ~]$ echo "export QUBES_GPG_AUTOACCEPT=86400" >> ~/.profile
|
||||
@ -131,13 +101,11 @@ Please note that at one time, this parameter was set in ~/.bash_profile.
|
||||
This will no longer work.
|
||||
If you have the parameter set in ~/.bash_profile you *must* update your configuration.
|
||||
|
||||
Please be aware of the caveat regarding passphrase-protected keys in the
|
||||
[Current limitations][current-limitations] section.
|
||||
Please be aware of the caveat regarding passphrase-protected keys in the [Current limitations][current-limitations] section.
|
||||
|
||||
### Configuring the client apps to use Split GPG backend ###
|
||||
|
||||
Normally it should be enough to set the `QUBES_GPG_DOMAIN` to the GPG backend
|
||||
domain name and use `qubes-gpg-client` in place of `gpg`, e.g.:
|
||||
Normally it should be enough to set the `QUBES_GPG_DOMAIN` to the GPG backend domain name and use `qubes-gpg-client` in place of `gpg`, e.g.:
|
||||
|
||||
[user@work ~]$ export QUBES_GPG_DOMAIN=work-gpg
|
||||
[user@work ~]$ gpg -K
|
||||
@ -152,53 +120,41 @@ domain name and use `qubes-gpg-client` in place of `gpg`, e.g.:
|
||||
[user@work ~]$ qubes-gpg-client secret_message.txt.asc
|
||||
(...)
|
||||
|
||||
Note that running normal `gpg -K` in the demo above shows no private keys
|
||||
stored in this AppVM.
|
||||
Note that running normal `gpg -K` in the demo above shows no private keys stored in this AppVM.
|
||||
|
||||
A note on `gpg` and `gpg2`:
|
||||
|
||||
Throughout this guide, we refer to `gpg`, but note that Split-GPG uses `gpg2`
|
||||
under the hood for compatibility with programs like Enigmail (which now supports
|
||||
only `gpg2`). If you encounter trouble while trying to set up Split-GPG, make
|
||||
sure you're using `gpg2` for your configuration and testing, since keyring data
|
||||
may differ between the two installations.
|
||||
Throughout this guide, we refer to `gpg`, but note that Split-GPG uses `gpg2` under the hood for compatibility with programs like Enigmail (which now supports only `gpg2`).
|
||||
If you encounter trouble while trying to set up Split-GPG, make sure you're using `gpg2` for your configuration and testing, since keyring data may differ between the two installations.
|
||||
|
||||
### Using Thunderbird + Enigmail with Split GPG ###
|
||||
|
||||
However, when using Thunderbird with Enigmail extension it is
|
||||
not enough, because Thunderbird doesn't preserve the environment
|
||||
variables. Instead it is recommended to use a simple script provided by
|
||||
`/usr/bin/qubes-gpg-client-wrapper` file by pointing Enigmail to use this
|
||||
script instead of the standard GnuPG binary:
|
||||
However, when using Thunderbird with Enigmail extension it is not enough, because Thunderbird doesn't preserve the environment variables.
|
||||
Instead it is recommended to use a simple script provided by `/usr/bin/qubes-gpg-client-wrapper` file by pointing Enigmail to use this script instead of the standard GnuPG binary:
|
||||
|
||||
![tb-enigmail-split-gpg-settings-2.png](/attachment/wiki/SplitGpg/tb-enigmail-split-gpg-settings-2.png)
|
||||
|
||||
The script also sets the `QUBES_GPG_DOMAIN` variable automatically based on
|
||||
the content of the file `/rw/config/gpg-split-domain`, which should be set to
|
||||
the name of the GPG backend VM. This file survives the AppVM reboot, of course.
|
||||
The script also sets the `QUBES_GPG_DOMAIN` variable automatically based on the content of the file `/rw/config/gpg-split-domain`, which should be set to the name of the GPG backend VM.
|
||||
This file survives the AppVM reboot, of course.
|
||||
|
||||
[user@work ~]$ sudo bash
|
||||
[root@work ~]$ echo "work-gpg" > /rw/config/gpg-split-domain
|
||||
|
||||
#### Qubes 4.0 Specifics ####
|
||||
|
||||
New qrexec policies in Qubes R4.0 by default require the user to enter the name
|
||||
of the domain containing GPG keys each time it is accessed. To improve usability
|
||||
for Thunderbird+Enigmail, in `dom0` place the following line at the top of the file
|
||||
`/etc/qubes-rpc/policy/qubes.Gpg`:
|
||||
New qrexec policies in Qubes R4.0 by default require the user to enter the name of the domain containing GPG keys each time it is accessed.
|
||||
To improve usability for Thunderbird+Enigmail, in `dom0` place the following line at the top of the file `/etc/qubes-rpc/policy/qubes.Gpg`:
|
||||
|
||||
```
|
||||
work-email work-gpg allow
|
||||
```
|
||||
where `work-email` is the Thunderbird+Enigmail AppVM and `work-gpg` contains
|
||||
your GPG keys.
|
||||
|
||||
where `work-email` is the Thunderbird+Enigmail AppVM and `work-gpg` contains your GPG keys.
|
||||
|
||||
## Using Git with Split GPG ##
|
||||
|
||||
Git can be configured to used with Split-GPG, something useful if you would
|
||||
like to contribute to the Qubes OS Project as every commit is required to be
|
||||
signed. The most basic `~/.gitconfig` file to with working Split-GPG looks
|
||||
something like this.
|
||||
Git can be configured to used with Split-GPG, something useful if you would like to contribute to the Qubes OS Project as every commit is required to be signed.
|
||||
The most basic `~/.gitconfig` file to with working Split-GPG looks something like this.
|
||||
|
||||
[user]
|
||||
name = YOUR NAME
|
||||
@ -208,8 +164,8 @@ something like this.
|
||||
[gpg]
|
||||
program = qubes-gpg-client-wrapper
|
||||
|
||||
Your key id is the public id of your signing key, which can be found by running
|
||||
`qubes-gpg-client -k`. In this instance, the key id is DD160C74.
|
||||
Your key id is the public id of your signing key, which can be found by running `qubes-gpg-client -k`.
|
||||
In this instance, the key id is DD160C74.
|
||||
|
||||
[user@work ~]$ qubes-gpg-client -k
|
||||
/home/user/.gnupg/pubring.kbx
|
||||
@ -217,30 +173,25 @@ Your key id is the public id of your signing key, which can be found by running
|
||||
pub rsa4096/DD160C74 2016-04-26
|
||||
uid Qubes User
|
||||
|
||||
To sign commits, you now add the "-S" flag to your commit command, which should
|
||||
prompt for Split-GPG usage. If you would like automatically sign all commits,
|
||||
you can add the following snippet to `~/.gitconfig`.
|
||||
To sign commits, you now add the "-S" flag to your commit command, which should prompt for Split-GPG usage.
|
||||
If you would like automatically sign all commits, you can add the following snippet to `~/.gitconfig`.
|
||||
|
||||
[commit]
|
||||
gpgsign = true
|
||||
|
||||
Lastly, if you would like to add aliases to sign and verify tags using the
|
||||
conventions the Qubes OS Project recommends, you can add the following snippet
|
||||
to `~/.gitconfig`.
|
||||
Lastly, if you would like to add aliases to sign and verify tags using the conventions the Qubes OS Project recommends, you can add the following snippet to `~/.gitconfig`.
|
||||
|
||||
[alias]
|
||||
stag = "!id=`git rev-parse --verify HEAD`; git tag -s user_${id:0:8} -m \"Tag for commit $id\""
|
||||
vtag = !git tag -v `git describe`
|
||||
|
||||
Replace `user` with your short, unique nickname. Now you can use `git stag` to
|
||||
add a signed tag to a commit and `git vtag` to verify the most recent tag that
|
||||
is reachable from a commit.
|
||||
Replace `user` with your short, unique nickname.
|
||||
Now you can use `git stag` to add a signed tag to a commit and `git vtag` to verify the most recent tag that is reachable from a commit.
|
||||
|
||||
## Importing public keys ###
|
||||
|
||||
Use `qubes-gpg-import-key` in the client AppVM to import the key into the
|
||||
GPG backend VM. Of course a (safe, unspoofable) user consent dialog box is
|
||||
displayed to accept this.
|
||||
Use `qubes-gpg-import-key` in the client AppVM to import the key into the GPG backend VM.
|
||||
Of course a (safe, unspoofable) user consent dialog box is displayed to accept this.
|
||||
|
||||
[user@work ~]$ export QUBES_GPG_DOMAIN=work-gpg
|
||||
[user@work ~]$ qubes-gpg-import-key ~/Downloads/marmarek.asc
|
||||
@ -252,17 +203,13 @@ displayed to accept this.
|
||||
|
||||
## Advanced: Using Split GPG with Subkeys ##
|
||||
|
||||
Users with particularly high security requirements may wish to use Split
|
||||
GPG with [subkeys]. However, this setup
|
||||
comes at a significant cost: It will be impossible to sign other people's keys
|
||||
with the master secret key without breaking this security model. Nonetheless,
|
||||
if signing others' keys is not required, then Split GPG with subkeys offers
|
||||
unparalleled security for one's master secret key.
|
||||
Users with particularly high security requirements may wish to use Split GPG with [subkeys].
|
||||
However, this setup comes at a significant cost: It will be impossible to sign other people's keys with the master secret key without breaking this security model.
|
||||
Nonetheless, if signing others' keys is not required, then Split GPG with subkeys offers unparalleled security for one's master secret key.
|
||||
|
||||
### Setup Description ###
|
||||
|
||||
In this example, the following keys are stored in the following locations
|
||||
(see below for definitions of these terms):
|
||||
In this example, the following keys are stored in the following locations (see below for definitions of these terms):
|
||||
|
||||
| PGP Key(s) | VM Name |
|
||||
| ---------- | ------------ |
|
||||
@ -274,123 +221,79 @@ In this example, the following keys are stored in the following locations
|
||||
|
||||
* `sec` (master secret key)
|
||||
|
||||
Depending on your needs, you may wish to create this as a **certify-only
|
||||
(C)** key, i.e., a key which is capable only of signing (a.k.a.,
|
||||
"certifying") other keys. This key may be created *without* an expiration
|
||||
date. This is for two reasons. First, the master secret key is never to
|
||||
leave the `vault` VM, so it is extremely unlikely ever to be obtained by
|
||||
an adversary (see below). Second, an adversary who *does* manage to obtain
|
||||
the master secret key either possesses the passphrase to unlock the key
|
||||
(if one is used) or does not. An adversary who *does* possess the passphrase
|
||||
can simply use it to legally extend the expiration date of the key
|
||||
(or remove it entirely). An adversary who does *not* possess the passphrase
|
||||
cannot use the key at all. In either case, an expiration date provides no
|
||||
additional benefit.
|
||||
Depending on your needs, you may wish to create this as a **certify-only (C)** key, i.e., a key which is capable only of signing (a.k.a., "certifying") other keys.
|
||||
This key may be created *without* an expiration date.
|
||||
This is for two reasons.
|
||||
First, the master secret key is never to leave the `vault` VM, so it is extremely unlikely ever to be obtained by an adversary (see below).
|
||||
Second, an adversary who *does* manage to obtain the master secret key either possesses the passphrase to unlock the key (if one is used) or does not.
|
||||
An adversary who *does* possess the passphrase can simply use it to legally extend the expiration date of the key (or remove it entirely).
|
||||
An adversary who does *not* possess the passphrase cannot use the key at all.
|
||||
In either case, an expiration date provides no additional benefit.
|
||||
|
||||
By the same token, however, having a passphrase on the key is of little
|
||||
value. An adversary who is capable of stealing the key from your `vault`
|
||||
would almost certainly also be capable of stealing the passphrase as
|
||||
you enter it. An adversary who obtains the passphrase can then use it
|
||||
in order to change or remove the passphrase from the key. Therefore,
|
||||
using a passphrase at all should be considered optional. It is, however,
|
||||
recommended that a **revocation certificate** be created and safely stored
|
||||
in multiple locations so that the master keypair can be revoked in the
|
||||
(exceedingly unlikely) event that it is ever compromised.
|
||||
By the same token, however, having a passphrase on the key is of little value.
|
||||
An adversary who is capable of stealing the key from your `vault` would almost certainly also be capable of stealing the passphrase as you enter it.
|
||||
An adversary who obtains the passphrase can then use it in order to change or remove the passphrase from the key.
|
||||
Therefore, using a passphrase at all should be considered optional.
|
||||
It is, however, recommended that a **revocation certificate** be created and safely stored in multiple locations so that the master keypair can be revoked in the (exceedingly unlikely) event that it is ever compromised.
|
||||
|
||||
* `ssb` (secret subkey)
|
||||
|
||||
Depending on your needs, you may wish to create two different subkeys: one
|
||||
for **signing (S)** and one for **encryption (E)**. You may also wish to
|
||||
give these subkeys reasonable expiration dates (e.g., one year). Once these
|
||||
keys expire, it is up to you whether to *renew* these keys by extending the
|
||||
expiration dates or to create *new* subkeys when the existing set expires.
|
||||
Depending on your needs, you may wish to create two different subkeys: one for **signing (S)** and one for **encryption (E)**.
|
||||
You may also wish to give these subkeys reasonable expiration dates (e.g., one year).
|
||||
Once these keys expire, it is up to you whether to *renew* these keys by extending the expiration dates or to create *new* subkeys when the existing set expires.
|
||||
|
||||
On the one hand, an adversary who obtains any existing encryption subkey
|
||||
(for example) will be able to use it in order to decrypt all emails (for
|
||||
example) which were encrypted to that subkey. If the same subkey were to
|
||||
continue to be used--and its expiration date continually extended--only
|
||||
that one key would need to be stolen (e.g., as a result of the `work-gpg`
|
||||
VM being compromised; see below) in order to decrypt *all* of the user's
|
||||
emails. If, on the other hand, each encryption subkey is used for at most
|
||||
approximately one year, then an adversary who obtains the secret subkey will
|
||||
be capable of decrypting at most approximately one year's worth of emails.
|
||||
On the one hand, an adversary who obtains any existing encryption subkey (for example) will be able to use it in order to decrypt all emails (for example) which were encrypted to that subkey.
|
||||
If the same subkey were to continue to be used--and its expiration date continually extended--only that one key would need to be stolen (e.g., as a result of the `work-gpg` VM being compromised; see below) in order to decrypt *all* of the user's emails.
|
||||
If, on the other hand, each encryption subkey is used for at most approximately one year, then an adversary who obtains the secret subkey will be capable of decrypting at most approximately one year's worth of emails.
|
||||
|
||||
On the other hand, creating a new signing subkey each year without
|
||||
renewing (i.e., extending the expiration dates of) existing signing
|
||||
subkeys would mean that all of your old signatures would eventually
|
||||
read as "EXPIRED" whenever someone attempts to verify them. This can be
|
||||
problematic, since there is no consensus on how expired signatures should
|
||||
be handled. Generally, digital signatures are intended to last forever,
|
||||
so this is a strong reason against regularly retiring one's signing subkeys.
|
||||
On the other hand, creating a new signing subkey each year without renewing (i.e., extending the expiration dates of) existing signing subkeys would mean that all of your old signatures would eventually read as "EXPIRED" whenever someone attempts to verify them.
|
||||
This can be problematic, since there is no consensus on how expired signatures should be handled.
|
||||
Generally, digital signatures are intended to last forever, so this is a strong reason against regularly retiring one's signing subkeys.
|
||||
|
||||
* `pub` (public key)
|
||||
|
||||
This is the complement of the master secret key. It can be uploaded to
|
||||
keyservers (or otherwise publicly distributed) and may be signed by others.
|
||||
This is the complement of the master secret key.
|
||||
It can be uploaded to keyservers (or otherwise publicly distributed) and may be signed by others.
|
||||
|
||||
* `vault`
|
||||
|
||||
This is a network-isolated VM. The initial master keypair and subkeys are
|
||||
generated in this VM. The master secret key *never* leaves this VM under
|
||||
*any* circumstances. No files or text is *ever* [copied] or [pasted] into
|
||||
this VM under *any* circumstances.
|
||||
This is a network-isolated VM.
|
||||
The initial master keypair and subkeys are generated in this VM.
|
||||
The master secret key *never* leaves this VM under *any* circumstances.
|
||||
No files or text is *ever* [copied] or [pasted] into this VM under *any* circumstances.
|
||||
|
||||
* `work-gpg`
|
||||
|
||||
This is a network-isolated VM. This VM is used *only* as the GPG backend for
|
||||
`work-email`. The secret subkeys (but *not* the master secret key) are
|
||||
[copied] from the `vault` VM to this VM. Files from less trusted VMs are
|
||||
*never* [copied] into this VM under *any* circumstances.
|
||||
This is a network-isolated VM.
|
||||
This VM is used *only* as the GPG backend for `work-email`.
|
||||
The secret subkeys (but *not* the master secret key) are [copied] from the `vault` VM to this VM.
|
||||
Files from less trusted VMs are *never* [copied] into this VM under *any* circumstances.
|
||||
|
||||
* `work-email`
|
||||
|
||||
This VM has access to the mail server. It accesses the `work-gpg` VM via
|
||||
the Split GPG protocol. The public key may be stored in this VM so that
|
||||
it can be attached to emails and for other such purposes.
|
||||
This VM has access to the mail server.
|
||||
It accesses the `work-gpg` VM via the Split GPG protocol.
|
||||
The public key may be stored in this VM so that it can be attached to emails and for other such purposes.
|
||||
|
||||
### Security Benefits ###
|
||||
|
||||
In the standard Split GPG setup, there are at least two ways in
|
||||
which the `work-gpg` VM might be compromised. First, an attacker
|
||||
who is capable of exploiting a hypothetical bug in `work-email`'s
|
||||
[MUA] could gain control of
|
||||
the `work-email` VM and send a malformed request which exploits a hypothetical
|
||||
bug in the GPG backend (running in the `work-gpg` VM), giving the attacker
|
||||
control of the `work-gpg` VM. Second, a malicious public key file which is
|
||||
imported into the `work-gpg` VM might exploit a hypothetical bug in the GPG
|
||||
backend which is running there, again giving the attacker control of the
|
||||
`work-gpg` VM. In either case, such an attacker might then be able to leak
|
||||
both the master secret key and its passphrase (if any is used, it would
|
||||
regularly be input in the work-gpg VM and therefore easily obtained by an
|
||||
attacker who controls this VM) back to the `work-email` VM or to another VM
|
||||
(e.g., the `netvm`, which is always untrusted by default) via the Split GPG
|
||||
protocol or other [covert channels]. Once the master secret
|
||||
key is in the `work-email` VM, the attacker could simply email it to himself
|
||||
(or to the world).
|
||||
In the standard Split GPG setup, there are at least two ways in which the `work-gpg` VM might be compromised.
|
||||
First, an attacker who is capable of exploiting a hypothetical bug in `work-email`'s [MUA] could gain control of the `work-email` VM and send a malformed request which exploits a hypothetical bug in the GPG backend (running in the `work-gpg` VM), giving the attacker control of the `work-gpg` VM.
|
||||
Second, a malicious public key file which is imported into the `work-gpg` VM might exploit a hypothetical bug in the GPG backend which is running there, again giving the attacker control of the `work-gpg` VM.
|
||||
In either case, such an attacker might then be able to leak both the master secret key and its passphrase (if any is used, it would regularly be input in the work-gpg VM and therefore easily obtained by an attacker who controls this VM) back to the `work-email` VM or to another VM (e.g., the `netvm`, which is always untrusted by default) via the Split GPG protocol or other [covert channels].
|
||||
Once the master secret key is in the `work-email` VM, the attacker could simply email it to himself (or to the world).
|
||||
|
||||
In the alternative setup described in this section (i.e., the subkey
|
||||
setup), even an attacker who manages to gain access to the `work-gpg` VM
|
||||
will not be able to obtain the user's master secret key since it is simply
|
||||
not there. Rather, the master secret key remains in the `vault` VM, which
|
||||
is extremely unlikely to be compromised, since nothing is ever copied or
|
||||
transferred into it.<sup>\*</sup> The attacker might nonetheless be able to
|
||||
leak the secret subkeys from the `work-gpg` VM in the manner described above,
|
||||
but even if this is successful, the secure master secret key can simply be
|
||||
used to revoke the compromised subkeys and to issue new subkeys in their
|
||||
place. (This is significantly less devastating than having to create a new
|
||||
*master* keypair.)
|
||||
In the alternative setup described in this section (i.e., the subkey setup), even an attacker who manages to gain access to the `work-gpg` VM will not be able to obtain the user's master secret key since it is simply not there.
|
||||
Rather, the master secret key remains in the `vault` VM, which is extremely unlikely to be compromised, since nothing is ever copied or transferred into it.
|
||||
<sup>\*</sup> The attacker might nonetheless be able to leak the secret subkeys from the `work-gpg` VM in the manner described above, but even if this is successful, the secure master secret key can simply be used to revoke the compromised subkeys and to issue new subkeys in their place.
|
||||
(This is significantly less devastating than having to create a new *master* keypair.)
|
||||
|
||||
<sup>\*</sup>In order to gain access to the `vault` VM, the attacker
|
||||
would require the use of, e.g., a general Xen VM escape exploit
|
||||
or a [signed, compromised package which is already installed in the
|
||||
TemplateVM][trusting-templates]
|
||||
upon which the `vault` VM is based.
|
||||
<sup>\*</sup>In order to gain access to the `vault` VM, the attacker would require the use of, e.g., a general Xen VM escape exploit or a [signed, compromised package which is already installed in the TemplateVM][trusting-templates] upon which the `vault` VM is based.
|
||||
|
||||
### Subkey Tutorials and Discussions ###
|
||||
|
||||
(Note: Although the tutorials below were not written with Qubes Split GPG
|
||||
in mind, they can be adapted with a few commonsense adjustments. As always,
|
||||
exercise caution and use your good judgment.)
|
||||
(Note: Although the tutorials below were not written with Qubes Split GPG in mind, they can be adapted with a few commonsense adjustments.
|
||||
As always, exercise caution and use your good judgment.)
|
||||
|
||||
- ["OpenPGP in Qubes OS" on the qubes-users mailing list][openpgp-in-qubes-os]
|
||||
- ["Creating the Perfect GPG Keypair" by Alex Cabal][cabal]
|
||||
|
@ -6,115 +6,68 @@ permalink: /doc/u2f-proxy/
|
||||
|
||||
# The Qubes U2F Proxy
|
||||
|
||||
The [Qubes U2F Proxy] is a secure proxy intended
|
||||
to make use of U2F two-factor authentication devices with web browsers without
|
||||
exposing the browser to the full USB stack, not unlike the [USB keyboard and
|
||||
mouse proxies][USB] implemented in Qubes.
|
||||
The [Qubes U2F Proxy] is a secure proxy intended to make use of U2F two-factor authentication devices with web browsers without exposing the browser to the full USB stack, not unlike the [USB keyboard and mouse proxies][USB] implemented in Qubes.
|
||||
|
||||
## What is U2F?
|
||||
|
||||
[U2F], which stands for "Universal 2nd Factor", is a framework for
|
||||
authentication using hardware devices (U2F tokens) as "second factors", i.e.
|
||||
*what you have* as opposed to *what you know*, like a passphrase. This
|
||||
additional control provides [good protection][krebs] in cases in which the
|
||||
passphrase is stolen (e.g. by phishing or keylogging). While passphrase
|
||||
compromise may not be obvious to the user, a physical device that cannot be
|
||||
duplicated must be stolen to be used outside of the owner's control.
|
||||
Nonetheless, it is important to note at the outset that U2F cannot guarantee
|
||||
security when the host system is compromised (e.g. a malware-infected operating
|
||||
system under an adversary's control).
|
||||
[U2F], which stands for "Universal 2nd Factor", is a framework for authentication using hardware devices (U2F tokens) as "second factors", i.e. *what you have* as opposed to *what you know*, like a passphrase.
|
||||
This additional control provides [good protection][krebs] in cases in which the passphrase is stolen (e.g. by phishing or keylogging).
|
||||
While passphrase compromise may not be obvious to the user, a physical device that cannot be duplicated must be stolen to be used outside of the owner's control.
|
||||
Nonetheless, it is important to note at the outset that U2F cannot guarantee security when the host system is compromised (e.g. a malware-infected operating system under an adversary's control).
|
||||
|
||||
The U2F specification defines protocols for multiple layers from USB to the
|
||||
browser API, and the whole stack is intended to be used with web applications
|
||||
(most commonly websites) in browsers. In most cases, tokens are USB dongles.
|
||||
The protocol is very simple, allowing the devices to store very little state
|
||||
inside (so the tokens may be reasonably cheap) while simultaneously
|
||||
authenticating a virtually unlimited number of services (so each person needs
|
||||
only one token, not one token per application). The user interface is usually
|
||||
limited to a single LED and a button that is pressed to confirm each
|
||||
transaction, so the devices themselves are also easy to use.
|
||||
The U2F specification defines protocols for multiple layers from USB to the browser API, and the whole stack is intended to be used with web applications (most commonly websites) in browsers.
|
||||
In most cases, tokens are USB dongles.
|
||||
The protocol is very simple, allowing the devices to store very little state inside (so the tokens may be reasonably cheap) while simultaneously authenticating a virtually unlimited number of services (so each person needs only one token, not one token per application).
|
||||
The user interface is usually limited to a single LED and a button that is pressed to confirm each transaction, so the devices themselves are also easy to use.
|
||||
|
||||
Currently, the most common form of two-step authentication consists of a numeric
|
||||
code that the user manually types into a web application. These codes are
|
||||
typically generated by an app on the user's smartphone or sent via SMS. By now,
|
||||
it is well-known that this form of two-step authentication is vulnerable to
|
||||
phishing and man-in-the-middle attacks due to the fact that the application
|
||||
requesting the two-step authentication code is typically not itself
|
||||
authenticated by the user. (In other words, users can accidentally give their
|
||||
codes to attackers because they do not always know who is really requesting the
|
||||
code.) In the U2F model, by contrast, the browser ensures that the token
|
||||
receives valid information about the web application requesting authentication,
|
||||
so the token knows which application it is authenticating (for details, see
|
||||
[here][u2f-details]). Nonetheless, [some attacks are still possible][wired] even
|
||||
with U2F (more on this below).
|
||||
Currently, the most common form of two-step authentication consists of a numeric code that the user manually types into a web application.
|
||||
These codes are typically generated by an app on the user's smartphone or sent via SMS.
|
||||
By now, it is well-known that this form of two-step authentication is vulnerable to phishing and man-in-the-middle attacks due to the fact that the application requesting the two-step authentication code is typically not itself authenticated by the user.
|
||||
(In other words, users can accidentally give their codes to attackers because they do not always know who is really requesting the code.) In the U2F model, by contrast, the browser ensures that the token receives valid information about the web application requesting authentication, so the token knows which application it is authenticating (for details, see [here][u2f-details]).
|
||||
Nonetheless, [some attacks are still possible][wired] even with U2F (more on this below).
|
||||
|
||||
## The Qubes approach to U2F
|
||||
|
||||
In a conventional setup, web browsers and the USB stack (to which the U2F token
|
||||
is connected) are all running in the same monolithic OS. Since the U2F model
|
||||
assumes that the browser is trustworthy, any browser in the OS is able to access
|
||||
any key stored on the U2F token. The user has no way to know which keys have
|
||||
been accessed by which browsers for which services. If any of the browsers are
|
||||
compromised, it should be assumed that all of the token's keys have been
|
||||
compromised. (This problem can be mitigated, however, if the U2F device has a
|
||||
special display to show the user what's being authenticated.) Moreover, since
|
||||
the USB stack is in the same monolithic OS, the system is vulnerable to attacks
|
||||
like [BadUSB].
|
||||
In a conventional setup, web browsers and the USB stack (to which the U2F token is connected) are all running in the same monolithic OS.
|
||||
Since the U2F model assumes that the browser is trustworthy, any browser in the OS is able to access any key stored on the U2F token.
|
||||
The user has no way to know which keys have been accessed by which browsers for which services.
|
||||
If any of the browsers are compromised, it should be assumed that all of the token's keys have been compromised.
|
||||
(This problem can be mitigated, however, if the U2F device has a special display to show the user what's being authenticated.) Moreover, since the USB stack is in the same monolithic OS, the system is vulnerable to attacks like [BadUSB].
|
||||
|
||||
In Qubes OS, by contrast, it is possible to securely compartmentalise the
|
||||
browser in one qube and the USB stack in another so that they are always kept
|
||||
separate from each other. The Qubes U2F Proxy then allows the token connected to
|
||||
the USB stack in one qube to communicate with the browser in a separate qube. We
|
||||
operate under the assumption that the USB stack is untrusted from the point of
|
||||
view of the browser and also that the browser is not to be trusted blindly by
|
||||
the token. Therefore, the token is never in the same qube as the browser. Our
|
||||
proxy forwards only the data necessary to actually perform the authentication,
|
||||
leaving all unnecessary data out, so it won't become a vector of attack. This is
|
||||
depicted in the diagram below (click for full size).
|
||||
In Qubes OS, by contrast, it is possible to securely compartmentalise the browser in one qube and the USB stack in another so that they are always kept separate from each other.
|
||||
The Qubes U2F Proxy then allows the token connected to the USB stack in one qube to communicate with the browser in a separate qube.
|
||||
We operate under the assumption that the USB stack is untrusted from the point of view of the browser and also that the browser is not to be trusted blindly by the token.
|
||||
Therefore, the token is never in the same qube as the browser.
|
||||
Our proxy forwards only the data necessary to actually perform the authentication, leaving all unnecessary data out, so it won't become a vector of attack.
|
||||
This is depicted in the diagram below (click for full size).
|
||||
|
||||
[![Qubes U2F Proxy diagram](/attachment/wiki/posts/u2f.svg)](/attachment/wiki/posts/u2f.svg)
|
||||
|
||||
The Qubes U2F Proxy has two parts: the frontend and the backend. The frontend
|
||||
runs in the same qube as the browser and presents a fake USB-like HID device
|
||||
using `uhid`. The backend runs in `sys-usb` and behaves like a browser. This is
|
||||
done using the `u2flib_host` reference library. All of our code was written in
|
||||
Python. The standard [qrexec] policy is responsible for directing calls to the
|
||||
appropriate domains.
|
||||
The Qubes U2F Proxy has two parts: the frontend and the backend.
|
||||
The frontend runs in the same qube as the browser and presents a fake USB-like HID device using `uhid`.
|
||||
The backend runs in `sys-usb` and behaves like a browser.
|
||||
This is done using the `u2flib_host` reference library.
|
||||
All of our code was written in Python.
|
||||
The standard [qrexec] policy is responsible for directing calls to the appropriate domains.
|
||||
|
||||
The `vault` qube with a dashed line in the bottom portion of the diagram depicts
|
||||
future work in which we plan to implement the Qubes U2F Proxy with a software
|
||||
token in an isolated qube rather than a physical hardware token. This is similar
|
||||
to the manner in which [Split GPG] allows us to emulate the smart card model
|
||||
without physical smart cards.
|
||||
The `vault` qube with a dashed line in the bottom portion of the diagram depicts future work in which we plan to implement the Qubes U2F Proxy with a software token in an isolated qube rather than a physical hardware token.
|
||||
This is similar to the manner in which [Split GPG] allows us to emulate the smart card model without physical smart cards.
|
||||
|
||||
One very important assumption of U2F is that the browser verifies every request
|
||||
sent to the U2F token --- in particular, that the web application sending an
|
||||
authentication request matches the application that would be authenticated by
|
||||
answering that request (in order to prevent, e.g., a phishing site from sending
|
||||
an authentication request for your bank's site). With the WebUSB feature in
|
||||
Chrome, however, a malicious website can [bypass][wired] this safeguard by
|
||||
connecting directly to the token instead of using the browser's U2F API.
|
||||
One very important assumption of U2F is that the browser verifies every request sent to the U2F token --- in particular, that the web application sending an authentication request matches the application that would be authenticated by answering that request (in order to prevent, e.g., a phishing site from sending an authentication request for your bank's site).
|
||||
With the WebUSB feature in Chrome, however, a malicious website can [bypass][wired] this safeguard by connecting directly to the token instead of using the browser's U2F API.
|
||||
|
||||
The Qubes U2F Proxy also prevents this class of attacks by implementing an
|
||||
additional verification layer. This verification layer allows you to enforce,
|
||||
for example, that the web browser in your `twitter` qube can only access the U2F
|
||||
key associated with `https://twitter.com`. This means that if anything in your
|
||||
`twitter` qube were compromised --- the browser or even the OS itself --- it
|
||||
would still not be able to access the U2F keys on your token for any other
|
||||
websites or services, like your email and bank accounts. This is another
|
||||
significant security advantage over monolithic systems. (For details and
|
||||
instructions, see the [Advanced usage] section below.)
|
||||
The Qubes U2F Proxy also prevents this class of attacks by implementing an additional verification layer.
|
||||
This verification layer allows you to enforce, for example, that the web browser in your `twitter` qube can only access the U2F key associated with `https://twitter.com`.
|
||||
This means that if anything in your `twitter` qube were compromised --- the browser or even the OS itself --- it would still not be able to access the U2F keys on your token for any other websites or services, like your email and bank accounts.
|
||||
This is another significant security advantage over monolithic systems.
|
||||
(For details and instructions, see the [Advanced usage] section below.)
|
||||
|
||||
For even more protection, you can combine this with the [Qubes firewall] to
|
||||
ensure, for example, that the browser in your `banking` qube accesses only one
|
||||
website (your bank's website). By configuring the Qubes firewall to prevent your
|
||||
`banking` qube from accessing any other websites, you reduce the risk of another
|
||||
website compromising the browser in an attempt to bypass U2F authentication.
|
||||
For even more protection, you can combine this with the [Qubes firewall] to ensure, for example, that the browser in your `banking` qube accesses only one website (your bank's website).
|
||||
By configuring the Qubes firewall to prevent your `banking` qube from accessing any other websites, you reduce the risk of another website compromising the browser in an attempt to bypass U2F authentication.
|
||||
|
||||
## Installation
|
||||
|
||||
These instructions assume that there is a `sys-usb` qube that holds the USB
|
||||
stack, which is the default configuration in most Qubes OS installations.
|
||||
These instructions assume that there is a `sys-usb` qube that holds the USB stack, which is the default configuration in most Qubes OS installations.
|
||||
|
||||
In dom0:
|
||||
|
||||
@ -135,59 +88,41 @@ In Debian TemplateVMs:
|
||||
$ sudo apt install qubes-u2f
|
||||
```
|
||||
|
||||
Repeat `qvm-service --enable` (or do this in VM settings -> Services in the Qube
|
||||
Manager) for all qubes that should have the proxy enabled. As usual with
|
||||
software updates, shut down the templates after installation, then restart
|
||||
`sys-usb` and all qubes that use the proxy. After that, you may use your U2F
|
||||
token (but see [Browser support] below).
|
||||
Repeat `qvm-service --enable` (or do this in VM settings -> Services in the Qube Manager) for all qubes that should have the proxy enabled.
|
||||
As usual with software updates, shut down the templates after installation, then restart `sys-usb` and all qubes that use the proxy.
|
||||
After that, you may use your U2F token (but see [Browser support] below).
|
||||
|
||||
## Advanced usage: per-qube key access
|
||||
|
||||
If you are using Qubes 4.0, you can further compartmentalise your U2F keys by
|
||||
restricting each qube's access to specific keys. For example, you could make it
|
||||
so that your `twitter` qube (and, therefore, all web browsers in your `twitter`
|
||||
qube) can access only the key on your U2F token for `https://twitter.com`,
|
||||
regardless of whether any of the web browsers in your `twitter` qube or the
|
||||
`twitter` qube itself are compromised. If your `twitter` qube makes an
|
||||
authentication request for your bank website, it will be denied at the Qubes
|
||||
policy level.
|
||||
If you are using Qubes 4.0, you can further compartmentalise your U2F keys by restricting each qube's access to specific keys.
|
||||
For example, you could make it so that your `twitter` qube (and, therefore, all web browsers in your `twitter` qube) can access only the key on your U2F token for `https://twitter.com`, regardless of whether any of the web browsers in your `twitter` qube or the `twitter` qube itself are compromised.
|
||||
If your `twitter` qube makes an authentication request for your bank website, it will be denied at the Qubes policy level.
|
||||
|
||||
To enable this, create a file in dom0 named
|
||||
`/etc/qubes-rpc/policy/policy.RegisterArgument+u2f.Authenticate` with the
|
||||
following content:
|
||||
To enable this, create a file in dom0 named `/etc/qubes-rpc/policy/policy.RegisterArgument+u2f.Authenticate` with the following content:
|
||||
|
||||
```
|
||||
sys-usb @anyvm allow,target=dom0
|
||||
```
|
||||
|
||||
Next, empty the contents of `/etc/qubes-rpc/policy/u2f.Authenticate` so that it
|
||||
is a blank file. Do not delete the file itself. (If you do, the default file
|
||||
will be recreated the next time you update, so it will no longer be empty.)
|
||||
Finally, follow your web application's instructions to enroll your token and use
|
||||
it as usual. (This enrollment process depends on the web application and is in
|
||||
no way specific to Qubes U2F.)
|
||||
Next, empty the contents of `/etc/qubes-rpc/policy/u2f.Authenticate` so that it is a blank file.
|
||||
Do not delete the file itself.
|
||||
(If you do, the default file will be recreated the next time you update, so it will no longer be empty.) Finally, follow your web application's instructions to enroll your token and use it as usual.
|
||||
(This enrollment process depends on the web application and is in no way specific to Qubes U2F.)
|
||||
|
||||
The default model is to allow a qube to access all and only the keys that were
|
||||
enrolled by that qube. For example, if your `banking` qube enrolls your banking
|
||||
key, and your `twitter` qube enrolls your Twitter key, then your `banking` qube
|
||||
will have access to your banking key but not your Twitter key, and your
|
||||
`twitter` qube will have access to your Twitter key but not your banking key.
|
||||
The default model is to allow a qube to access all and only the keys that were enrolled by that qube.
|
||||
For example, if your `banking` qube enrolls your banking key, and your `twitter` qube enrolls your Twitter key, then your `banking` qube will have access to your banking key but not your Twitter key, and your `twitter` qube will have access to your Twitter key but not your banking key.
|
||||
|
||||
## TemplateVM and browser support
|
||||
|
||||
The large number of possible combinations of
|
||||
TemplateVM (Fedora 27, 28; Debian 8, 9) and browser (multiple Google Chrome
|
||||
versions, multiple Chromium versions, multiple Firefox versions) made it
|
||||
impractical for us to test every combination that users are likely to attempt
|
||||
with the Qubes U2F Proxy. In some cases, you may be the first person to try a
|
||||
particular combination. Consequently (and as with any new feature), users will
|
||||
inevitably encounter bugs. We ask for your patience and understanding in this
|
||||
regard. As always, please [report any bugs you encounter].
|
||||
The large number of possible combinations of TemplateVM (Fedora 27, 28; Debian 8, 9) and browser (multiple Google Chrome versions, multiple Chromium versions, multiple Firefox versions) made it impractical for us to test every combination that users are likely to attempt with the Qubes U2F Proxy.
|
||||
In some cases, you may be the first person to try a particular combination.
|
||||
Consequently (and as with any new feature), users will inevitably encounter bugs.
|
||||
We ask for your patience and understanding in this regard.
|
||||
As always, please [report any bugs you encounter].
|
||||
|
||||
Please note that, in Firefox before Quantum (e.g. Firefox 52 in Debian 9), you
|
||||
have to install the [U2F Support Add-on][ff-u2f-addon]. In Firefox post-Quantum
|
||||
you may have to enable the `security.webauth.u2f` flag in `about:config`. Chrome
|
||||
and Chromium do not require any special browser extensions.
|
||||
Please note that, in Firefox before Quantum (e.g. Firefox 52 in Debian 9), you have to install the [U2F Support Add-on][ff-u2f-addon].
|
||||
In Firefox post-Quantum you may have to enable the `security.webauth.u2f` flag in `about:config`.
|
||||
Chrome and Chromium do not require any special browser extensions.
|
||||
|
||||
|
||||
[Qubes U2F Proxy]: https://github.com/QubesOS/qubes-app-u2f
|
||||
|
@ -85,7 +85,9 @@ Below is a complete list of configuration made according to the above statement,
|
||||
|
||||
- NetworkManager configuration from normal user (nm-applet)
|
||||
- updates installation (gpk-update-viewer)
|
||||
- user can use pkexec just like sudo Note: above is needed mostly because Qubes user GUI session isn't treated by PolicyKit/logind as "local" session because of the way in which X server and session is started. Perhaps we will address this issue in the future, but this is really low priority. Patches welcomed anyway.
|
||||
- user can use pkexec just like sudo Note: above is needed mostly because Qubes user GUI session isn't treated by PolicyKit/logind as "local" session because of the way in which X server and session is started.
|
||||
Perhaps we will address this issue in the future, but this is really low priority.
|
||||
Patches welcomed anyway.
|
||||
|
||||
3. Empty root password
|
||||
- used for access to 'root' account from text console (xl console) - the only way to access the VM when GUI isn't working
|
||||
@ -94,12 +96,11 @@ Below is a complete list of configuration made according to the above statement,
|
||||
Replacing passwordless root access with Dom0 user prompt
|
||||
--------------------------------------------------------
|
||||
|
||||
While ITL supports the statement above, some Qubes users may wish to enable
|
||||
user/root isolation in VMs anyway. We do not support it in any of our packages,
|
||||
but of course nothing is preventing the user from modifying his or her own
|
||||
system. A list of steps to do so is provided here **without any guarantee of
|
||||
safety, accuracy, or completeness. Proceed at your own risk. Do not rely on
|
||||
this for extra security.**
|
||||
While ITL supports the statement above, some Qubes users may wish to enable user/root isolation in VMs anyway.
|
||||
We do not support it in any of our packages, but of course nothing is preventing the user from modifying his or her own system.
|
||||
A list of steps to do so is provided here **without any guarantee of safety, accuracy, or completeness.
|
||||
Proceed at your own risk.
|
||||
Do not rely on this for extra security.**
|
||||
|
||||
1. Adding Dom0 "VMAuth" service:
|
||||
|
||||
@ -116,7 +117,8 @@ this for extra security.**
|
||||
auth requisite pam_deny.so
|
||||
auth required pam_permit.so
|
||||
|
||||
- Require authentication for sudo. Replace the first line of /etc/sudoers.d/qubes with:
|
||||
- Require authentication for sudo.
|
||||
Replace the first line of /etc/sudoers.d/qubes with:
|
||||
|
||||
user ALL=(ALL) ALL
|
||||
|
||||
@ -132,7 +134,8 @@ this for extra security.**
|
||||
auth requisite pam_deny.so
|
||||
auth required pam_permit.so
|
||||
|
||||
- Require authentication for sudo. Replace the first line of /etc/sudoers.d/qubes with:
|
||||
- Require authentication for sudo.
|
||||
Replace the first line of /etc/sudoers.d/qubes with:
|
||||
|
||||
user ALL=(ALL) ALL
|
||||
|
||||
@ -156,4 +159,5 @@ this for extra security.**
|
||||
Dom0 passwordless root access
|
||||
-----------------------------
|
||||
|
||||
There is also passwordless user->root access in dom0. As stated in comment in sudo configuration there (different one than VMs one), there is really no point in user/root isolation, because all the user data (and VM management interface) is already accessible from dom0 user level, so there is nothing more to get from dom0 root account.
|
||||
There is also passwordless user->root access in dom0.
|
||||
As stated in comment in sudo configuration there (different one than VMs one), there is really no point in user/root isolation, because all the user data (and VM management interface) is already accessible from dom0 user level, so there is nothing more to get from dom0 root account.
|
||||
|
@ -10,33 +10,28 @@ redirect_from:
|
||||
Using YubiKey to Qubes authentication
|
||||
=====================================
|
||||
|
||||
You can use YubiKey to enhance Qubes user authentication, for example to mitigate
|
||||
risk of snooping the password. This can also slightly improve security when you have [USB keyboard](/doc/device-handling-security/#security-warning-on-usb-input-devices).
|
||||
You can use YubiKey to enhance Qubes user authentication, for example to mitigate risk of snooping the password.
|
||||
This can also slightly improve security when you have [USB keyboard](/doc/device-handling-security/#security-warning-on-usb-input-devices).
|
||||
|
||||
There (at least) two possible configurations: using OTP mode and using challenge-response mode.
|
||||
|
||||
OTP mode
|
||||
--------
|
||||
|
||||
This can be configured using
|
||||
[app-linux-yubikey](https://github.com/adubois/qubes-app-linux-yubikey)
|
||||
package. This package does not support sharing the same key slot with other
|
||||
applications (it will deny further authentications if you try).
|
||||
This can be configured using [app-linux-yubikey](https://github.com/adubois/qubes-app-linux-yubikey) package.
|
||||
This package does not support sharing the same key slot with other applications (it will deny further authentications if you try).
|
||||
|
||||
Contrary to instruction there, currently there is no binary package in the Qubes
|
||||
repository and you need to compile it yourself. This might change in the future.
|
||||
Contrary to instruction there, currently there is no binary package in the Qubes repository and you need to compile it yourself.
|
||||
This might change in the future.
|
||||
|
||||
Challenge-response mode
|
||||
----------------------
|
||||
|
||||
In this mode, your YubiKey will generate a response based on the secret key, and
|
||||
random challenge (instead of counter). This means that it isn't possible to
|
||||
generate a response in advance even if someone gets access to your YubiKey. This
|
||||
makes it reasonably safe to use the same YubiKey for other services (also in
|
||||
challenge-response mode).
|
||||
In this mode, your YubiKey will generate a response based on the secret key, and random challenge (instead of counter).
|
||||
This means that it isn't possible to generate a response in advance even if someone gets access to your YubiKey.
|
||||
This makes it reasonably safe to use the same YubiKey for other services (also in challenge-response mode).
|
||||
|
||||
Same as in the OTP case, you will need to set up your YubiKey, choose a separate
|
||||
password (other than your login password!) and apply the configuration.
|
||||
Same as in the OTP case, you will need to set up your YubiKey, choose a separate password (other than your login password!) and apply the configuration.
|
||||
|
||||
To use this mode you need to:
|
||||
|
||||
@ -50,13 +45,10 @@ To use this mode you need to:
|
||||
|
||||
sudo apt-get install yubikey-personalization yubikey-personalization-gui
|
||||
|
||||
Shut down your TemplateVM. Then reboot your USB VM (so changes inside the TemplateVM take effect
|
||||
in your TemplateBased USB VM or install the packages inside your USB VM if you would like to avoid
|
||||
rebooting your USB VM.
|
||||
Shut down your TemplateVM.
|
||||
Then reboot your USB VM (so changes inside the TemplateVM take effect in your TemplateBased USB VM or install the packages inside your USB VM if you would like to avoid rebooting your USB VM.
|
||||
|
||||
2. Configure your YubiKey for challenge-response `HMAC-SHA1` mode, for example
|
||||
[following this
|
||||
tutorial](https://www.yubico.com/products/services-software/personalization-tools/challenge-response/).
|
||||
2. Configure your YubiKey for challenge-response `HMAC-SHA1` mode, for example [following this tutorial](https://www.yubico.com/products/services-software/personalization-tools/challenge-response/).
|
||||
|
||||
On Debian, you can run the graphical user interface `yubikey-personalization-gui` from the command line.
|
||||
|
||||
@ -91,17 +83,18 @@ To use this mode you need to:
|
||||
|
||||
echo -n "$password" | openssl dgst -sha1
|
||||
|
||||
7. Edit `/etc/pam.d/login` in dom0. Add this line at the beginning:
|
||||
7. Edit `/etc/pam.d/login` in dom0.
|
||||
Add this line at the beginning:
|
||||
|
||||
auth include yubikey
|
||||
|
||||
8. Edit `/etc/pam.d/xscreensaver` (or appropriate file if you are using other
|
||||
screen locker program) in dom0. Add this line at the beginning:
|
||||
8. Edit `/etc/pam.d/xscreensaver` (or appropriate file if you are using screen locker program) in dom0.
|
||||
Add this line at the beginning:
|
||||
|
||||
auth include yubikey
|
||||
|
||||
9. Edit `/etc/pam.d/lightdm` (or appropriate file if you are using other
|
||||
display manager) in dom0. Add this line at the beginning:
|
||||
9. Edit `/etc/pam.d/lightdm` (or appropriate file if you are using other display manager) in dom0.
|
||||
Add this line at the beginning:
|
||||
|
||||
auth include yubikey
|
||||
|
||||
@ -116,46 +109,44 @@ When you want to unlock your screen...
|
||||
|
||||
When everything is ok, your screen will be unlocked.
|
||||
|
||||
In any case you can still use your login password, but do it in a secure location
|
||||
where no one can snoop your password.
|
||||
In any case you can still use your login password, but do it in a secure location where no one can snoop your password.
|
||||
|
||||
### Mandatory YubiKey Login
|
||||
|
||||
Edit `/etc/pam.d/yubikey` (or appropriate file if you are using other screen locker program)
|
||||
and remove `default=ignore` so the line looks like this.
|
||||
Edit `/etc/pam.d/yubikey` (or appropriate file if you are using other screen locker program) and remove `default=ignore` so the line looks like this.
|
||||
|
||||
auth [success=done] pam_exec.so expose_authtok quiet /usr/bin/yk-auth
|
||||
|
||||
Locking the screen when YubiKey is removed
|
||||
------------------------------------------
|
||||
|
||||
You can setup your system to automatically lock the screen when you unplug your
|
||||
YubiKey. This will require creating a simple qrexec service which will expose
|
||||
the ability to lock the screen to your USB VM, and then adding a udev hook to
|
||||
actually call that service.
|
||||
You can setup your system to automatically lock the screen when you unplug your YubiKey.
|
||||
This will require creating a simple qrexec service which will expose the ability to lock the screen to your USB VM, and then adding a udev hook to actually call that service.
|
||||
|
||||
In dom0:
|
||||
|
||||
1. First configure the qrexec service. Create `/etc/qubes-rpc/custom.LockScreen`
|
||||
with a simple command to lock the screen. In the case of xscreensaver (used in Xfce)
|
||||
it would be:
|
||||
1. First configure the qrexec service.
|
||||
Create `/etc/qubes-rpc/custom.LockScreen` with a simple command to lock the screen.
|
||||
In the case of xscreensaver (used in Xfce) it would be:
|
||||
|
||||
DISPLAY=:0 xscreensaver-command -lock
|
||||
|
||||
2. Allow your USB VM to call that service. Assuming that it's named `sys-usb` it
|
||||
would require creating `/etc/qubes-rpc/policy/custom.LockScreen` with:
|
||||
2. Allow your USB VM to call that service.
|
||||
Assuming that it's named `sys-usb` it would require creating `/etc/qubes-rpc/policy/custom.LockScreen` with:
|
||||
|
||||
sys-usb dom0 allow
|
||||
|
||||
In your USB VM:
|
||||
|
||||
3. Create udev hook. Store it in `/rw/config` to have it
|
||||
persist across VM restarts. For example name the file
|
||||
`/rw/config/yubikey.rules`. Add the following line:
|
||||
3. Create udev hook.
|
||||
Store it in `/rw/config` to have it persist across VM restarts.
|
||||
For example name the file `/rw/config/yubikey.rules`.
|
||||
Add the following line:
|
||||
|
||||
ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_SECURITY_TOKEN}=="1", RUN+="/usr/bin/qrexec-client-vm dom0 custom.LockScreen"
|
||||
|
||||
4. Ensure that the udev hook is placed in the right place after VM restart. Append to `/rw/config/rc.local`:
|
||||
4. Ensure that the udev hook is placed in the right place after VM restart.
|
||||
Append to `/rw/config/rc.local`:
|
||||
|
||||
ln -s /rw/config/yubikey.rules /etc/udev/rules.d/
|
||||
udevadm control --reload
|
||||
|
Loading…
Reference in New Issue
Block a user