<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Alexander Bakker&#39;s Blog</title>
    <link>https://alexbakker.me</link>
    <description>Personal blog where I occasionally post about my projects, programming and security</description>
    <item>
      <title>Setting up a Site-to-Site VPN between AWS and on-premises VyOS (IPSec &amp; BGP)</title>
      <link>https://alexbakker.me/post/setting-up-site-to-site-vpn-to-aws-on-vyos-ipsec-bgp.html</link>
      <description>&lt;p&gt;VyOS is an open-source operating system based on Linux that provides&#xA;software-based networking. There&amp;rsquo;s &lt;a href=&#34;https://vyos.io/documents/aws-partnership/VyOS%E2%80%94AWS-Site-to-Site-VPN-and-BGP.pdf&#34;&gt;an official&#xA;guide&lt;/a&gt;&#xA;for setting up a Site-to-Site VPN between an on-premises VyOS router and AWS,&#xA;but it is fairly outdated, as it was written for VyOS 1.3, not for the current&#xA;LTS: VyOS 1.4 (sagitta). AWS also has the option to download a sample&#xA;configuration for Vyatta (the project that VyOS was forked from), which is&#xA;helpful, but also outdated. I&amp;rsquo;m publishing my notes in case it&amp;rsquo;s helpful to&#xA;anyone else.&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;aws-create-cgw-vgw-tgw-and-vpn&#34;&gt;AWS: Create CGW, VGW/TGW and VPN&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;This post assumes that you understand IPSec, have some experience in AWS and&#xA;have already created the CGW, VGW/TGW and VPN. I assume you&amp;rsquo;re here because the&#xA;tunnel status says &lt;span style=&#34;color:red&#34;&gt;DOWN&lt;/span&gt; and now you&amp;rsquo;re sad&#xA;because you&amp;rsquo;re not sure what magical spells to cast towards the VyOS command&#xA;prompt to make it say &lt;span style=&#34;color:green&#34;&gt;UP&lt;/span&gt;.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;img src=&#34;/img/aws-s2s-1.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;When initially setting op the VPN in AWS, you&amp;rsquo;ll be asked to choose the type of&#xA;routing that&amp;rsquo;s going to be used. The options are fairly self-explanatory:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Static&lt;/strong&gt; requires both sides to configure static routes for traffic they&#xA;wish to route through the IPSec tunnel.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Dynamic&lt;/strong&gt; requires establishing a BGP session between both sides through the&#xA;IPSec tunnel. Since VyOS supports BGP, we&amp;rsquo;ll be using this option.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;In this example, we&amp;rsquo;ll terminate the VPN connection into a VGW on the AWS side.&#xA;The VGW is associated with a VPC with CIDR range &lt;code&gt;10.137.0.0/16&lt;/code&gt; and the route&#xA;tables of the VPC are configured to have the VGW propagate routes it has&#xA;discovered into them. You can also use a TGW if you have a more advanced use&#xA;case.&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;vyos-ipsec-tunnel&#34;&gt;VyOS: IPSec tunnel&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;First, let&amp;rsquo;s collect some important info from the &lt;code&gt;vpn-01&lt;/code&gt; Site-to-Site VPN I&#xA;created for test purposes in AWS, along with some info about the on-premises&#xA;side&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;&#xA;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;&lt;/th&gt;&#xA;&lt;th&gt;Outside IP&lt;/th&gt;&#xA;&lt;th&gt;Inside IPv4 CIDR&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Tunnel 1&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;34.193.192.160&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;169.254.18.92/30&lt;/code&gt;&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Tunnel 2&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;54.92.230.59&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;169.254.107.244/30&lt;/code&gt;&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;On-premises&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;1.2.3.4&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;n/a&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;We&amp;rsquo;ll start by configuring the encryption parameters. Download the &amp;ldquo;Generic&amp;rdquo;&#xA;example configuration for your VPN from AWS. This will contain the pre-shared&#xA;keys for the tunnels. Based on &lt;a href=&#34;https://www.ncsc.gov.uk/guidance/using-ipsec-protect-data#recprofile&#34;&gt;NCSC&amp;rsquo;s&#xA;recommendations&lt;/a&gt;&#xA;and the example configuration from AWS, I arrived at the following settings for&#xA;VyOS:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec esp-group aws-s2s lifetime &lt;span class=&#34;s1&#34;&gt;&amp;#39;3600&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec esp-group aws-s2s pfs &lt;span class=&#34;s1&#34;&gt;&amp;#39;enable&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec esp-group aws-s2s proposal &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; encryption &lt;span class=&#34;s1&#34;&gt;&amp;#39;aes128gcm128&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec ike-group aws-s2s dead-peer-detection action &lt;span class=&#34;s1&#34;&gt;&amp;#39;restart&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec ike-group aws-s2s dead-peer-detection interval &lt;span class=&#34;s1&#34;&gt;&amp;#39;10&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec ike-group aws-s2s dead-peer-detection timeout &lt;span class=&#34;s1&#34;&gt;&amp;#39;30&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec ike-group aws-s2s key-exchange &lt;span class=&#34;s1&#34;&gt;&amp;#39;ikev2&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec ike-group aws-s2s lifetime &lt;span class=&#34;s1&#34;&gt;&amp;#39;28800&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec ike-group aws-s2s proposal &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; dh-group &lt;span class=&#34;s1&#34;&gt;&amp;#39;19&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec ike-group aws-s2s proposal &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; encryption &lt;span class=&#34;s1&#34;&gt;&amp;#39;aes128gcm128&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec ike-group aws-s2s proposal &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; prf &lt;span class=&#34;s1&#34;&gt;&amp;#39;prfsha256&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# NOTE: Replace the values below with the tunnel 1/2 outside IP&amp;#39;s and corresponding pre-shared secrets&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec authentication psk aws-s2s-tunnel1 id &lt;span class=&#34;s1&#34;&gt;&amp;#39;34.193.192.160&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec authentication psk aws-s2s-tunnel1 secret &lt;span class=&#34;s1&#34;&gt;&amp;#39;wDRS31kXtW8Rd0o9QJSAKje76WdJyM6.&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec authentication psk aws-s2s-tunnel2 id &lt;span class=&#34;s1&#34;&gt;&amp;#39;54.92.230.59&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec authentication psk aws-s2s-tunnel2 secret &lt;span class=&#34;s1&#34;&gt;&amp;#39;20xllijzqZuLy6UogMVAS5VCVjcPwHP0&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Next, we&amp;rsquo;ll set up our VTI interfaces. AWS assigns a separate &lt;code&gt;/30&lt;/code&gt; CIDR block&#xA;in the &lt;code&gt;169.254.0.0/16&lt;/code&gt; range for use inside each tunnel. The first usable&#xA;address in these networks is the AWS side and the second address is the&#xA;on-premises side. So in this case that&amp;rsquo;d be:&lt;/p&gt;&#xA;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;&lt;/th&gt;&#xA;&lt;th&gt;AWS&lt;/th&gt;&#xA;&lt;th&gt;On-premises&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Tunnel 1&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;169.254.18.93&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;169.254.18.94&lt;/code&gt;&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Tunnel 2&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;169.254.107.245&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;169.254.107.246&lt;/code&gt;&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Taking the overhead of the IPSec header into account, and assuming an MTU of&#xA;1500 on the interface IPSec is bound to, the MTU for the VTI should be 1436.&#xA;This is all highly dependent on what your specific setup looks like, of course.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Setting up the VTI interfaces:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# NOTE: Replace the addresses&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; interfaces vti vti0 address &lt;span class=&#34;s1&#34;&gt;&amp;#39;169.254.18.94/30&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; interfaces vti vti0 mtu &lt;span class=&#34;s1&#34;&gt;&amp;#39;1436&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; interfaces vti vti0 ip adjust-mss &lt;span class=&#34;m&#34;&gt;1396&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; interfaces vti vti1 address &lt;span class=&#34;s1&#34;&gt;&amp;#39;169.254.107.246/30&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; interfaces vti vti1 mtu &lt;span class=&#34;s1&#34;&gt;&amp;#39;1436&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; interfaces vti vti1 ip adjust-mss &lt;span class=&#34;m&#34;&gt;1396&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Tunnels:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec interface &lt;span class=&#34;s1&#34;&gt;&amp;#39;pppoe0&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec options disable-route-autoinstall&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# NOTE: Replace the remote-id, local-address and remote-address&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec site-to-site peer aws-s2s-tunnel1 authentication mode &lt;span class=&#34;s1&#34;&gt;&amp;#39;pre-shared-secret&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec site-to-site peer aws-s2s-tunnel1 authentication remote-id &lt;span class=&#34;s1&#34;&gt;&amp;#39;34.193.192.160&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec site-to-site peer aws-s2s-tunnel1 connection-type &lt;span class=&#34;s1&#34;&gt;&amp;#39;initiate&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec site-to-site peer aws-s2s-tunnel1 ike-group &lt;span class=&#34;s1&#34;&gt;&amp;#39;aws-s2s&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec site-to-site peer aws-s2s-tunnel1 local-address &lt;span class=&#34;s1&#34;&gt;&amp;#39;1.2.3.4&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec site-to-site peer aws-s2s-tunnel1 remote-address &lt;span class=&#34;s1&#34;&gt;&amp;#39;34.193.192.160&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec site-to-site peer aws-s2s-tunnel1 vti &lt;span class=&#34;nb&#34;&gt;bind&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;vti0&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec site-to-site peer aws-s2s-tunnel1 vti esp-group &lt;span class=&#34;s1&#34;&gt;&amp;#39;aws-s2s&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec site-to-site peer aws-s2s-tunnel2 authentication mode &lt;span class=&#34;s1&#34;&gt;&amp;#39;pre-shared-secret&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec site-to-site peer aws-s2s-tunnel2 authentication remote-id &lt;span class=&#34;s1&#34;&gt;&amp;#39;54.92.230.59&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec site-to-site peer aws-s2s-tunnel2 connection-type &lt;span class=&#34;s1&#34;&gt;&amp;#39;initiate&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec site-to-site peer aws-s2s-tunnel2 ike-group &lt;span class=&#34;s1&#34;&gt;&amp;#39;aws-s2s&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec site-to-site peer aws-s2s-tunnel2 local-address &lt;span class=&#34;s1&#34;&gt;&amp;#39;1.2.3.4&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec site-to-site peer aws-s2s-tunnel2 remote-address &lt;span class=&#34;s1&#34;&gt;&amp;#39;54.92.230.59&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec site-to-site peer aws-s2s-tunnel2 vti &lt;span class=&#34;nb&#34;&gt;bind&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;vti1&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vpn ipsec site-to-site peer aws-s2s-tunnel2 vti esp-group &lt;span class=&#34;s1&#34;&gt;&amp;#39;aws-s2s&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I&amp;rsquo;m configuring IPSec to use the Point-to-Point interface &lt;code&gt;pppoe0&lt;/code&gt; directly,&#xA;as it has a public IPv4 address assigned by my ISP configured on it. Your&#xA;interface will probably have a different name.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Next, we&amp;rsquo;ll update the firewall rules to allow IPSec traffic from AWS. Replace&#xA;&lt;code&gt;WAN_LOCAL&lt;/code&gt; with the name of your WAN ruleset:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# NOTE: Replace the addresses with the outside IP&amp;#39;s of your Site-to-Site VPN in AWS&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall group address-group aws-s2s-vpn address &lt;span class=&#34;s1&#34;&gt;&amp;#39;34.193.192.160&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall group address-group aws-s2s-vpn address &lt;span class=&#34;s1&#34;&gt;&amp;#39;54.92.230.59&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 name WAN_LOCAL rule &lt;span class=&#34;m&#34;&gt;30&lt;/span&gt; action &lt;span class=&#34;s1&#34;&gt;&amp;#39;accept&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 name WAN_LOCAL rule &lt;span class=&#34;m&#34;&gt;30&lt;/span&gt; description &lt;span class=&#34;s1&#34;&gt;&amp;#39;AWS Site-to-Site VPN&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 name WAN_LOCAL rule &lt;span class=&#34;m&#34;&gt;30&lt;/span&gt; destination port &lt;span class=&#34;s1&#34;&gt;&amp;#39;500,4500&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 name WAN_LOCAL rule &lt;span class=&#34;m&#34;&gt;30&lt;/span&gt; protocol &lt;span class=&#34;s1&#34;&gt;&amp;#39;udp&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 name WAN_LOCAL rule &lt;span class=&#34;m&#34;&gt;30&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt; group address-group &lt;span class=&#34;s1&#34;&gt;&amp;#39;aws-s2s-vpn&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Now we can &lt;code&gt;commit&lt;/code&gt; the changes, wait for a few moments and check that the&#xA;IPSec tunnel is now up:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ show vpn ipsec connections&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Connection           State    Type    Remote address    Local TS    Remote TS    Local id    Remote id       Proposal&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-------------------  -------  ------  ----------------  ----------  -----------  ----------  --------------  ------------------------&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;aws-s2s-tunnel1      up       IKEv2   34.193.192.160    -           -                        34.193.192.160  AES_GCM/128/None/ECP_256&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;aws-s2s-tunnel1-vti  up       IPsec   34.193.192.160    0.0.0.0/0   0.0.0.0/0                34.193.192.160  AES_GCM/128/None/None&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                                        ::/0        ::/0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;aws-s2s-tunnel2      up       IKEv2   54.92.230.59      -           -                        54.92.230.59    AES_GCM/128/None/ECP_256&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;aws-s2s-tunnel2-vti  up       IPsec   54.92.230.59      0.0.0.0/0   0.0.0.0/0                54.92.230.59    AES_GCM/128/None/None&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                                        ::/0        ::/0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The AWS console still reports that the tunnel is &lt;span&#xA;style=&#34;color:red&#34;&gt;DOWN&lt;/span&gt;, so we&amp;rsquo;re still a little sad, but the IPSec tunnel&#xA;is now up:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;img src=&#34;/img/aws-s2s-2.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;If you&amp;rsquo;ve opted to use &amp;ldquo;Static&amp;rdquo; routing when creating the VPN in AWS, the status&#xA;will say &lt;span style=&#34;color:green&#34;&gt;UP&lt;/span&gt; and you&amp;rsquo;ll only have to configure&#xA;some static routes to start using the VPN. BGP is more fun though, so let&amp;rsquo;s set&#xA;up dynamic routing.&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;vyos-bgp&#34;&gt;VyOS: BGP&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Finally, we&amp;rsquo;ll set up BGP to dynamically exchange routes between AWS and&#xA;on-premises.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# NOTE: Replace ASN as configured on the customer gateway in AWS&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp system-as &lt;span class=&#34;s1&#34;&gt;&amp;#39;65111&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp parameters router-id &lt;span class=&#34;s1&#34;&gt;&amp;#39;192.168.0.1&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# NOTE: Replace ASN as configured on the VGW/TGW in AWS&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp peer-group aws-s2s-vpn address-family ipv4-unicast soft-reconfiguration inbound&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp peer-group aws-s2s-vpn remote-as &lt;span class=&#34;s1&#34;&gt;&amp;#39;64512&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# NOTE: Replace the neighbour address with the AWS-side tunnel inside address&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# and replace the source address with the on-premises tunnel inside address&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp neighbor 169.254.18.93 description &lt;span class=&#34;s1&#34;&gt;&amp;#39;BGP - AWS tunnel 1&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp neighbor 169.254.18.93 peer-group &lt;span class=&#34;s1&#34;&gt;&amp;#39;aws-s2s-vpn&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp neighbor 169.254.18.93 timers holdtime &lt;span class=&#34;s1&#34;&gt;&amp;#39;30&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp neighbor 169.254.18.93 timers keepalive &lt;span class=&#34;s1&#34;&gt;&amp;#39;10&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp neighbor 169.254.18.93 update-source &lt;span class=&#34;s1&#34;&gt;&amp;#39;169.254.18.94&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp neighbor 169.254.107.245 description &lt;span class=&#34;s1&#34;&gt;&amp;#39;BGP - AWS tunnel 2&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp neighbor 169.254.107.245 peer-group &lt;span class=&#34;s1&#34;&gt;&amp;#39;aws-s2s-vpn&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp neighbor 169.254.107.245 timers holdtime &lt;span class=&#34;s1&#34;&gt;&amp;#39;30&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp neighbor 169.254.107.245 timers keepalive &lt;span class=&#34;s1&#34;&gt;&amp;#39;10&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp neighbor 169.254.107.245 update-source &lt;span class=&#34;s1&#34;&gt;&amp;#39;169.254.107.246&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;There are a few ways to configure which routes to advertise. A common one is to&#xA;include all locally known routes:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp address-family ipv4-unicast redistribute connected&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;In my case, I only want to advertise a specific list of routes:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp address-family ipv4-unicast network 192.168.0.0/24&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; protocols bgp address-family ipv4-unicast network 192.168.200.0/24&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Update firewall rules to allow BGP traffic from VTI interfaces:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 input filter rule &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt; action &lt;span class=&#34;s1&#34;&gt;&amp;#39;jump&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 input filter rule &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt; inbound-interface name &lt;span class=&#34;s1&#34;&gt;&amp;#39;vti0&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 input filter rule &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt; jump-target &lt;span class=&#34;s1&#34;&gt;&amp;#39;AWS_S2S_LOCAL&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 input filter rule &lt;span class=&#34;m&#34;&gt;21&lt;/span&gt; action &lt;span class=&#34;s1&#34;&gt;&amp;#39;jump&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 input filter rule &lt;span class=&#34;m&#34;&gt;21&lt;/span&gt; inbound-interface name &lt;span class=&#34;s1&#34;&gt;&amp;#39;vti1&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 input filter rule &lt;span class=&#34;m&#34;&gt;21&lt;/span&gt; jump-target &lt;span class=&#34;s1&#34;&gt;&amp;#39;AWS_S2S_LOCAL&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 name AWS_S2S_LOCAL default-action &lt;span class=&#34;s1&#34;&gt;&amp;#39;drop&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 name AWS_S2S_LOCAL default-log&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 name AWS_S2S_LOCAL rule &lt;span class=&#34;m&#34;&gt;10&lt;/span&gt; action &lt;span class=&#34;s1&#34;&gt;&amp;#39;accept&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 name AWS_S2S_LOCAL rule &lt;span class=&#34;m&#34;&gt;10&lt;/span&gt; state &lt;span class=&#34;s1&#34;&gt;&amp;#39;established&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 name AWS_S2S_LOCAL rule &lt;span class=&#34;m&#34;&gt;10&lt;/span&gt; state &lt;span class=&#34;s1&#34;&gt;&amp;#39;related&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 name AWS_S2S_LOCAL rule &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt; action &lt;span class=&#34;s1&#34;&gt;&amp;#39;accept&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 name AWS_S2S_LOCAL rule &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt; description &lt;span class=&#34;s1&#34;&gt;&amp;#39;BGP&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 name AWS_S2S_LOCAL rule &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt; destination port &lt;span class=&#34;s1&#34;&gt;&amp;#39;179&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; firewall ipv4 name AWS_S2S_LOCAL rule &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt; protocol &lt;span class=&#34;s1&#34;&gt;&amp;#39;tcp&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Now we can &lt;code&gt;commit&lt;/code&gt; all configuration changes again, wait for a few moments,&#xA;and check the BGP status. We can see that we&amp;rsquo;ve now established a BGP session&#xA;over the two tunnels:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ show bgp summary&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IPv4 Unicast Summary (VRF default):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BGP router identifier 192.168.0.1, local AS number 65111 vrf-id 0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BGP table version 9&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RIB entries 5, using 480 bytes of memory&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Peers 2, using 40 KiB of memory&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Peer groups 1, using 64 bytes of memory&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Neighbor        V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt Desc&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;169.254.18.93   4      64512        48        51        9    0    0 00:07:11            1        3 BGP - AWS tunnel 1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;169.254.107.245 4      64512        48        51        9    0    0 00:07:11            1        3 BGP - AWS tunnel 2&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Total number of neighbors 2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Looking at the BGP route table, we see our own advertised routes and a learned&#xA;route with two paths that have a different MED for each path:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ show bgp ipv4&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BGP table version is 9, local router ID is 192.168.0.1, vrf id 0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Default local pref 100, local AS 65111&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Status codes:  s suppressed, d damped, h history, * valid, &amp;gt; best, = multipath,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               i internal, r RIB-failure, S Stale, R Removed&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Nexthop codes: @NNN nexthop&amp;#39;s vrf id, &amp;lt; announce-nh-self&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Origin codes:  i - IGP, e - EGP, ? - incomplete&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RPKI validation codes: V valid, I invalid, N Not found&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    Network          Next Hop            Metric LocPrf Weight Path&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; *  10.137.0.0/16    169.254.18.93          200             0 64512 i&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; *&amp;gt;                  169.254.107.245        100             0 64512 i&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; *&amp;gt; 192.168.0.0/24   0.0.0.0                  0         32768 i&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; *&amp;gt; 192.168.200.0/24 0.0.0.0                  0         32768 i&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;If you attached the VPN to a TGW instead and have ECMP enabled, you&amp;rsquo;ll notice&#xA;that the MED is equal for the two paths, and that multipath is enabled:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ show bgp ipv4&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BGP table version is 19, local router ID is 192.168.0.1, vrf id 0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Default local pref 100, local AS 65111&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Status codes:  s suppressed, d damped, h history, * valid, &amp;gt; best, = multipath,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               i internal, r RIB-failure, S Stale, R Removed&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Nexthop codes: @NNN nexthop&amp;#39;s vrf id, &amp;lt; announce-nh-self&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Origin codes:  i - IGP, e - EGP, ? - incomplete&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RPKI validation codes: V valid, I invalid, N Not found&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    Network          Next Hop            Metric LocPrf Weight Path&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; *= 10.137.0.0/16    169.254.18.93          100             0 64512 i&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; *&amp;gt;                  169.254.107.245        100             0 64512 i&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; *&amp;gt; 192.168.0.0/24   0.0.0.0                  0         32768 i&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; *&amp;gt; 192.168.200.0/24 0.0.0.0                  0         32768 i&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;And the Linux route table now includes the newly learned route from AWS:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ip r&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;***&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;10.137.0.0/16 nhid 232 via 169.254.107.245 dev vti1 proto bgp metric 20&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;***&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;If you attached the VPN to a TGW instead and have ECMP enabled, you&amp;rsquo;ll notice&#xA;that the route has two paths with equal weights:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ip r&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;***&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;10.137.0.0/16 nhid 249 proto bgp metric 20&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;nexthop via 169.254.107.245 dev vti1 weight 1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;nexthop via 169.254.18.93 dev vti0 weight 1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;***&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The AWS console now also reports that both tunnels are &lt;span&#xA;style=&#34;color:green&#34;&gt;UP&lt;/span&gt; and that it has learned two routes. AWS looks&#xA;happy, so we&amp;rsquo;re happy:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;img src=&#34;/img/aws-s2s-3.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The VGW has also propagated the routes into the VPC route tables:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;img src=&#34;/img/aws-s2s-4.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;We can also ping back and forth between machines in the AWS VPC and the&#xA;on-premises network:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ping 192.168.0.3&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;64 bytes from 192.168.0.3: icmp_seq=1 ttl=63 time=96.8 ms&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;64 bytes from 192.168.0.3: icmp_seq=2 ttl=63 time=96.4 ms&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;64 bytes from 192.168.0.3: icmp_seq=3 ttl=63 time=96.2 ms&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;64 bytes from 192.168.0.3: icmp_seq=4 ttl=63 time=96.3 ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ping 10.137.6.139&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PING 10.137.6.139 (10.137.6.139) 56(84) bytes of data.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;64 bytes from 10.137.6.139: icmp_seq=1 ttl=126 time=96.6 ms&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;64 bytes from 10.137.6.139: icmp_seq=2 ttl=126 time=96.4 ms&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;64 bytes from 10.137.6.139: icmp_seq=3 ttl=126 time=96.5 ms&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;64 bytes from 10.137.6.139: icmp_seq=4 ttl=126 time=96.4 ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;And that&amp;rsquo;s it!&lt;/p&gt;&#xA;&#xA;&lt;p&gt;In case you were just experimenting and want to clean everything up:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;delete vpn ipsec&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;delete protocols bgp&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;delete interfaces vti vti0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;delete interfaces vti vti1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;delete firewall group address-group aws-s2s-vpn&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;delete firewall ipv4 input filter rule &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;delete firewall ipv4 input filter rule &lt;span class=&#34;m&#34;&gt;21&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;delete firewall ipv4 name AWS_S2S_LOCAL&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;delete firewall ipv4 name WAN_LOCAL rule &lt;span class=&#34;m&#34;&gt;30&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;div class=&#34;footnotes&#34;&gt;&#xA;&#xA;&lt;hr /&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&lt;p&gt;Don&amp;rsquo;t worry, all of the IP addresses and secrets shown here are either&#xA;fake or no longer in use by me.&lt;/p&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;/div&gt;&#xA;</description>
      <pubDate>Mon, 05 May 2025 00:00:00 +0000</pubDate>
    </item>
    <item>
      <title>Bypassing app lock in Ente Auth</title>
      <link>https://alexbakker.me/post/bypassing-app-lock-in-ente-auth.html</link>
      <description>&lt;p&gt;A couple of months ago I discovered three issues that allow one to bypass app&#xA;lock in Ente Auth. The issues I found aren&amp;rsquo;t technically interesting and don&amp;rsquo;t&#xA;really deserve a blog post, but since Ente appears to be hesitant to notify&#xA;their users about them, off we go.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Disclaimer: I&amp;rsquo;m one of the authors of &lt;a href=&#34;https://getaegis.app&#34;&gt;Aegis Authenticator&lt;/a&gt;.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Some background: Aegis&amp;rsquo; implementation of automatic lock has a somewhat annoying&#xA;side effect that makes the app vanish from the recent apps screen in Android. &lt;a href=&#34;https://github.com/beemdevelopment/Aegis/issues/714#issuecomment-2329763307&#34;&gt;A&#xA;user recently&#xA;commented&lt;/a&gt;&#xA;that Ente Auth does not have this issue and suggested that we take some&#xA;inspiration from them. I decided to take a look, but instead found myself&#xA;drafting an email to security@ente.io after 10 minutes of playing around with&#xA;the app.&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;the-issues&#34;&gt;The issues&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;These issues were discovered in Ente Auth 3.1.3 for Android, but may be present&#xA;on other platforms as well. I used the app without signing into an Ente account.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;We&amp;rsquo;re not going to dive into Ente Auth&amp;rsquo;s code to find the cause of these issues,&#xA;because I don&amp;rsquo;t think it would make for interesting reading in this blog post.&#xA;As you&amp;rsquo;ll realize while watching the demonstration videos below, the fact that&#xA;app lock can be bypassed in this fashion tells us that it was implemented as&#xA;essentially &lt;a href=&#34;https://github.com/ente-io/ente/blob/auth-v3.1.3/auth/lib/ui/settings/lock_screen/lock_screen_password.dart#L209&#34;&gt;a glorified &amp;ldquo;if&amp;rdquo;&#xA;statement&lt;/a&gt;&#xA;rather than actually requiring the configured credential to decrypt the secrets&#xA;used to generate OTP&amp;rsquo;s.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The security of this app lock implementation relies on the absence of bugs in&#xA;the UI logic. In this case, there are three.&lt;/p&gt;&#xA;&#xA;&lt;div class=&#34;portrait-video-group&#34;&gt;&#xA;  &lt;div class=&#34;portrait-video-section&#34;&gt;&#xA;    &lt;p&gt;&lt;b&gt;1.&lt;/b&gt; Bypassing app lock after the app was automatically locked from the app lock settings screen:&lt;/p&gt;&#xA;    &lt;div class=&#34;portrait-video-wrapper&#34;&gt;&#xA;      &lt;video controls&gt;&#xA;        &lt;source src=&#34;/video/ente-auth-issue1.webm&#34; type=&#34;video/webm&#34; /&gt;&#xA;      &lt;/video&gt;&#xA;    &lt;/div&gt;&#xA;  &lt;/div&gt;&#xA;  &lt;div class=&#34;portrait-video-section&#34;&gt;&#xA;    &lt;p&gt;&lt;b&gt;2.&lt;/b&gt; Downgrade from password app lock to device credential based app lock by entering the device PIN:&lt;/p&gt;&#xA;    &lt;div class=&#34;portrait-video-wrapper&#34;&gt;&#xA;      &lt;video controls&gt;&#xA;        &lt;source src=&#34;/video/ente-auth-issue2.webm&#34; type=&#34;video/webm&#34; /&gt;&#xA;      &lt;/video&gt;&#xA;    &lt;/div&gt;&#xA;  &lt;/div&gt;&#xA;  &lt;div class=&#34;portrait-video-section&#34;&gt;&#xA;    &lt;p&gt;&lt;b&gt;3.&lt;/b&gt; Bypassing device credential based app lock entirely:&lt;/p&gt;&#xA;    &lt;div class=&#34;portrait-video-wrapper&#34;&gt;&#xA;      &lt;video controls&gt;&#xA;        &lt;source src=&#34;/video/ente-auth-issue3.webm&#34; type=&#34;video/webm&#34; /&gt;&#xA;      &lt;/video&gt;&#xA;    &lt;/div&gt;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;p&gt;The second and third video contain a brief flash of blackness, because Android&#xA;blocks screen recording of the device credential prompt. The touch indicators&#xA;give a hint of what I&amp;rsquo;m doing. In video &lt;strong&gt;2&lt;/strong&gt; I&amp;rsquo;m entering the device PIN (not&#xA;the password configured in Ente) and in video &lt;strong&gt;3&lt;/strong&gt; I simply dismiss the prompt.&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;timeline&#34;&gt;Timeline&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The first two issues were fixed in 18 days. The third one was fixed in 76 days.&#xA;Here&amp;rsquo;s the timeline:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2024-09-04&lt;/strong&gt; Report submitted via email.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2024-09-05&lt;/strong&gt; Ente responds: Thank you for bringing these issues to our&#xA;attention. We&amp;rsquo;ll be fixing these problems in the next update.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2024-09-22&lt;/strong&gt; I notice that &lt;a href=&#34;https://github.com/ente-io/ente/releases/tag/auth-v4.0.0&#34;&gt;Ente Auth&#xA;4.0.0&lt;/a&gt; was released&#xA;which silently fixes the first two issues. I send an email where I:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Point out that device credential based app lock can still be bypassed.&lt;/li&gt;&#xA;&lt;li&gt;Express that I was a little surprised to see that there&amp;rsquo;s no announcement&#xA;urging users to update.&lt;/li&gt;&#xA;&lt;li&gt;Mention that I would have appreciated a brief mention crediting me for&#xA;reporting these issues.&lt;/li&gt;&#xA;&lt;/ul&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2024-09-25 - 2024-09-26&lt;/strong&gt; Some back and forth emails: The dev team is&#xA;looking into the remaining issue. They explain that they currently don&amp;rsquo;t have&#xA;&amp;ldquo;a credit system&amp;rdquo; for issues. I clarify that I&amp;rsquo;m not looking for a monetary&#xA;reward. They don&amp;rsquo;t respond to my comment about not announcing the issue to&#xA;their users.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2024-11-17&lt;/strong&gt; I send an email reminding them about this issue and that a&#xA;little over 2 weeks are left until the 90 day mark. I also share a draft of&#xA;the blog post I plan to publish on the 3rd of December.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2024-11-19&lt;/strong&gt; Ente Auth 4.1.0 is released with a fix for the third issue. It&#xA;looks like 4.1.0 was released as a pre-release on GitHub on the 5th of&#xA;November, but it had not been rolled out through all channels (such as Google&#xA;Play) yet.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2024-11-20&lt;/strong&gt; Vishnu from Ente reaches out via email. To summarize:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;em&gt;&amp;ldquo;The GitHub release did not get promoted due to human error, so the&#xA;release did not get pushed to some of our distribution channels. We&amp;rsquo;ve now&#xA;appointed a release manager to reduce the possibility of such errors.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;&#xA;&lt;li&gt;The changelogs on GitHub have been updated to mention the security issues:&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/ente-io/ente/releases/tag/auth-v4.0.0&#34;&gt;https://github.com/ente-io/ente/releases/tag/auth-v4.0.0&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/ente-io/ente/releases/tag/auth-v4.1.0&#34;&gt;https://github.com/ente-io/ente/releases/tag/auth-v4.1.0&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&lt;/li&gt;&#xA;&lt;li&gt;The help articles have been&#xA;&lt;a href=&#34;https://github.com/ente-io/ente/commit/3c5f6dd510a37b50f6c1697b81832fce3bed2546&#34;&gt;updated&lt;/a&gt;&#xA;to explain how app lock works in Ente Auth.&lt;/li&gt;&#xA;&lt;/ul&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2024-11-20&lt;/strong&gt; Since all issues have been fixed, this blog post was published&#xA;earlier than the 90 day mark.&lt;/p&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
      <pubDate>Wed, 20 Nov 2024 00:00:00 +0000</pubDate>
    </item>
    <item>
      <title>Parsing Google Authenticator export QR codes</title>
      <link>https://alexbakker.me/post/parsing-google-auth-export-qr-code.html</link>
      <description>&lt;p&gt;We recently &lt;a href=&#34;https://github.com/beemdevelopment/Aegis/pull/406&#34;&gt;added support&lt;/a&gt;&#xA;for scanning the new Google Authenticator export QR codes to Aegis&#xA;Authenticator. The single token URI format is&#xA;&lt;a href=&#34;https://github.com/google/google-authenticator/wiki/Key-Uri-Format&#34;&gt;well-documented&lt;/a&gt;,&#xA;but the format of the QR codes displayed in the new export feature of Google&#xA;Authenticator is not. It&amp;rsquo;s not immediately obvious how the format works without&#xA;doing some reverse engineering, so I figured I&amp;rsquo;d briefly explain it in a blog&#xA;post.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The QR codes contain a URI with the following format:&#xA;&lt;code&gt;otpauth-migration://offline?data=...&lt;/code&gt; The scheme is &lt;code&gt;otpauth-migration&lt;/code&gt;,&#xA;the host is &lt;code&gt;offline&lt;/code&gt; and there is a &lt;code&gt;data&lt;/code&gt; query parameter. The data&#xA;parameter is a base64 encoded Protobuf message with the following format:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;syntax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;proto3&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;MigrationPayload&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kd&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Algorithm&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;ALGORITHM_UNSPECIFIED&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;ALGORITHM_SHA1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;ALGORITHM_SHA256&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;ALGORITHM_SHA512&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;ALGORITHM_MD5&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kd&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;DigitCount&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;DIGIT_COUNT_UNSPECIFIED&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;DIGIT_COUNT_SIX&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;DIGIT_COUNT_EIGHT&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kd&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;OtpType&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;OTP_TYPE_UNSPECIFIED&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;OTP_TYPE_HOTP&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;OTP_TYPE_TOTP&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;OtpParameters&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;kt&#34;&gt;bytes&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;secret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;issuer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;Algorithm&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;algorithm&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;DigitCount&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;digits&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;OtpType&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;kt&#34;&gt;int64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;counter&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;repeated&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;OtpParameters&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;otp_parameters&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;int32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;int32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;batch_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;int32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;batch_index&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;int32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;batch_id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The Protobuf message contains a list of OtpParameters. If you&amp;rsquo;ve worked with&#xA;HOTP/TOTP before, the fields in OtpParameters should look familiar, so I won&amp;rsquo;t&#xA;explain them here. If there are more than a few entries to export from Google&#xA;Authenticator, they will be split up into multiple QR codes. The &lt;code&gt;batch_size&lt;/code&gt;&#xA;and &lt;code&gt;batch_index&lt;/code&gt; fields indicate the number of QR codes and the index of this&#xA;QR code, respectively. The &lt;code&gt;batch_id&lt;/code&gt; is a unique identifier for the export&#xA;attempt.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;I&amp;rsquo;m not 100% sure if the types of the fields are exactly correct, as I don&amp;rsquo;t&#xA;have access to the Protobuf message definition file of Google Authenticator, but&#xA;they seem to match up well enough.&lt;/p&gt;&#xA;</description>
      <pubDate>Sat, 23 May 2020 11:35:00 +0000</pubDate>
    </item>
    <item>
      <title>A mysterious bug in the firmware of Google&#39;s Titan M chip (CVE-2019-9465)</title>
      <link>https://alexbakker.me/post/mysterious-google-titan-m-bug-cve-2019-9465.html</link>
      <description>&lt;p&gt;Starting with the release of the Pixel 3, all of Google&amp;rsquo;s Pixel Android&#xA;smartphones come with the Titan M security chip on board. When I realized the&#xA;Pixel 3a XL I purchased also had it, I decided to try to take advantage of it in&#xA;an app I work on. It turned out that using the Titan M chip through the Android&#xA;Keystore API for AES-GCM in a specific way lead to predictable and bogus&#xA;ciphertext. This is the story of how I stumbled upon that bug, and why it&amp;rsquo;s a&#xA;bit mysterious.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;em&gt;Discussed on &lt;a href=&#34;https://news.ycombinator.com/item?id=22450374&#34;&gt;HN&lt;/a&gt; and &lt;a href=&#34;https://www.reddit.com/r/netsec/comments/fbfc97/a_mysterious_bug_in_the_firmware_of_googles_titan&#34;&gt;Reddit&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;the-android-keystore&#34;&gt;The Android Keystore&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Let&amp;rsquo;s start with a short high-level primer on the Android Keystore and StrongBox&#xA;before we jump into this. If you&amp;rsquo;re already familiar with these two concepts,&#xA;you can skip ahead to &lt;a href=&#34;#discovering-the-bug&#34;&gt;Discovering the bug&lt;/a&gt;.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The Android Keystore is a system service that allows apps to securely generate&#xA;and use cryptographic keys. While apps can use the keys they generated, they&#xA;cannot extract them, as they never enter the process of the app. The idea behind&#xA;this, is that even if the process of the app is compromised, the key is not.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The practical security of this system varies across devices, as the Android&#xA;Keystore can have various kinds of &amp;ldquo;backings&amp;rdquo;. Some devices simply keep the&#xA;whole system in Android itself, while other devices come with a TEE. Some even&#xA;come with an entirely separate chip to back the Android Keystore with. The&#xA;latter offers the best security, because even if an attacker is able to&#xA;compromise the operating system, they would still need a vulnerability in the&#xA;&lt;a href=&#34;https://developer.android.com/training/articles/keystore#HardwareSecurityModule&#34;&gt;HSM&lt;/a&gt;&#xA;to get to the keys in the Android Keystore. The fact that these chips are&#xA;shipping in more and more smartphones these days is a pretty exciting&#xA;development, if you ask me.&lt;/p&gt;&#xA;&#xA;&lt;h3 id=&#34;strongbox-and-the-titan-m-chip&#34;&gt;StrongBox and the Titan M chip&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;An Android Keystore implementation that falls under the latter category is&#xA;referred to as a StrongBox Keymaster, and the Titan M chip is one of them. To&#xA;take advantage of it in an Android app on Pixel devices, one has to indicate a&#xA;preference for StrongBox during key generation. By simply calling&#xA;&lt;code&gt;setIsStrongBoxBacked(true)&lt;/code&gt; on the KeyGenerator instance, apps that use the&#xA;Android Keystore get more secure storage for their cryptographic keys, with no&#xA;apparent downsides. That&amp;rsquo;s what I thought, anyway.&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;discovering-the-bug&#34;&gt;Discovering the bug&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;I work on a 2FA app for Android, &lt;a href=&#34;https://github.com/beemdevelopment/Aegis&#34;&gt;Aegis&#xA;Authenticator&lt;/a&gt;. The app stores the OTP&#xA;secrets in an encrypted file (referred to as the vault). The master key used to&#xA;encrypt/decrypt the vault is managed by a key slot system that&amp;rsquo;s very similar to&#xA;LUKS. You can learn more about it&#xA;&lt;a href=&#34;https://github.com/beemdevelopment/Aegis/blob/master/docs/vault.md&#34;&gt;here&lt;/a&gt;. In&#xA;short, Aegis has the concept of two types of key slots: for a password and for&#xA;biometric authentication. The biometric key slot encrypts the master key with a&#xA;key stored in the Android Keystore, so that the master key can be&#xA;decrypted after successful biometric authentication by the user.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Here&amp;rsquo;s what the key generation code for that looks like in Aegis. Excerpt from&#xA;&lt;a href=&#34;https://github.com/beemdevelopment/Aegis/blob/def7c676148f261c1adf28bf1fc3d9fc03a25985/app/src/main/java/com/beemdevelopment/aegis/crypto/KeyStoreHandle.java#L47-L67&#34;&gt;KeyStoreHandle.java&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;KeyGenerator&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;generator&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;KeyGenerator&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;getInstance&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;KeyProperties&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;KEY_ALGORITHM_AES&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;STORE_NAME&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;);&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;generator&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;init&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;KeyGenParameterSpec&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;Builder&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;KeyProperties&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;PURPOSE_ENCRYPT&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;KeyProperties&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;PURPOSE_DECRYPT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setBlockModes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;KeyProperties&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;BLOCK_MODE_GCM&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setEncryptionPaddings&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;KeyProperties&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;ENCRYPTION_PADDING_NONE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setUserAuthenticationRequired&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setRandomizedEncryptionRequired&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setKeySize&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CryptoUtils&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;CRYPTO_AEAD_KEY_SIZE&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;It generates a 256-bit key, to be used with AES in GCM mode, for encryption and&#xA;decryption. User authentication is required for this key, so that it can only be&#xA;used after biometric authentication by the user.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This works fine. Let&amp;rsquo;s switch this over to StrongBox.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gh&#34;&gt;diff --git a/app/src/main/java/com/beemdevelopment/aegis/crypto/KeyStoreHandle.java b/app/src/main/java/com/beemdevelopment/aegis/crypto/KeyStoreHandle.java&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gh&#34;&gt;index cfa1e57..00cae52 100644&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gh&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;--- a/app/src/main/java/com/beemdevelopment/aegis/crypto/KeyStoreHandle.java&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ b/app/src/main/java/com/beemdevelopment/aegis/crypto/KeyStoreHandle.java&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -57,6 +57,7 @@ public class KeyStoreHandle {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;                     .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                     .setUserAuthenticationRequired(true)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                     .setRandomizedEncryptionRequired(true)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gi&#34;&gt;+                    .setIsStrongBoxBacked(true)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;                     .setKeySize(CryptoUtils.CRYPTO_AEAD_KEY_SIZE * 8)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                     .build());&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;To test this change, I went through Aegis&amp;rsquo; setup process, set a password and&#xA;enabled biometric unlock. The main view opened and I could start adding tokens.&#xA;So far so good. However, when I closed the app, reopened it and tried to unlock&#xA;the vault with biometric authentication, the app showed an error dialog, caused&#xA;by the following chain of exceptions:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;com.beemdevelopment.aegis.db.slots.SlotIntegrityException: javax.crypto.AEADBadTagException&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    at com.beemdevelopment.aegis.db.slots.Slot.getKey(Slot.java:57)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Caused by: javax.crypto.AEADBadTagException&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:517)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    at javax.crypto.Cipher.doFinal(Cipher.java:2055)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Caused by: android.security.KeyStoreException: Signature/MAC verification failed&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    at android.security.KeyStore.getKeyStoreException(KeyStore.java:1292)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.doFinal(KeyStoreCryptoOperationChunkedStreamer.java:224)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    at android.security.keystore.AndroidKeyStoreAuthenticatedAESCipherSpi$BufferAllOutputUntilDoFinalStreamer.doFinal(AndroidKeyStoreAuthenticatedAESCipherSpi.java:373)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:506)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    at javax.crypto.Cipher.doFinal(Cipher.java:2055) &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Huh. Decryption of the key slot fails, because apparently verification of the&#xA;MAC failed. How could that be? We only added a single line to enable StrongBox&#xA;and left the rest of the code alone. I would have attached a debugger at this&#xA;point to see what&amp;rsquo;s going on, but that&amp;rsquo;s not very useful here, as we can&amp;rsquo;t see&#xA;what is going on in the HSM, where the cryptographic operation takes place.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;After a couple of more tries, it turned out that the kind of exception I was&#xA;getting was not consistent. If I waited a couple of seconds before&#xA;authenticating after the biometric prompt was shown, I got an entirely different&#xA;exception:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;java.security.InvalidKeyException: Keystore operation failed&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at com.beemdevelopment.aegis.crypto.KeyStoreHandle.isKeyPermanentlyInvalidated(KeyStoreHandle.java:104)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at com.beemdevelopment.aegis.crypto.KeyStoreHandle.getKey(KeyStoreHandle.java:83)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at com.beemdevelopment.aegis.ui.AuthActivity.onCreate(AuthActivity.java:83)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Caused by: java.security.InvalidKeyException: Keystore operation failed&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at android.security.KeyStore.getInvalidKeyException(KeyStore.java:1362)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at android.security.KeyStore.getInvalidKeyException(KeyStore.java:1402)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at android.security.keystore.KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit(KeyStoreCryptoOperationUtils.java:54)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at android.security.keystore.KeyStoreCryptoOperationUtils.getExceptionForCipherInit(KeyStoreCryptoOperationUtils.java:89)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at android.security.keystore.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:265)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineInit(AndroidKeyStoreCipherSpiBase.java:109)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at javax.crypto.Cipher.tryTransformWithProvider(Cipher.java:2984)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at javax.crypto.Cipher.tryCombinations(Cipher.java:2891)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at javax.crypto.Cipher$SpiAndProviderUpdater.updateAndGetSpiAndProvider(Cipher.java:2796)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at javax.crypto.Cipher.chooseProvider(Cipher.java:773)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at javax.crypto.Cipher.init(Cipher.java:1143)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at javax.crypto.Cipher.init(Cipher.java:1084)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at com.beemdevelopment.aegis.crypto.KeyStoreHandle.isKeyPermanentlyInvalidated(KeyStoreHandle.java:96)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Caused by: android.security.KeyStoreException: Invalid key blob&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  at android.security.KeyStore.getKeyStoreException(KeyStore.java:1292)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;digging-deeper&#34;&gt;Digging deeper&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;At this point, I decided this issue may be worth reporting to Google through the&#xA;&lt;a href=&#34;https://www.google.com/about/appsecurity/android-rewards/&#34;&gt;Android Security Rewards&#xA;Program&lt;/a&gt;. In an&#xA;attempt to get a better grasp on what the issue actually is, I wrote a small&#xA;configurable PoC app that demonstrates the issue to go along with the report. It&#xA;is open source and &lt;a href=&#34;https://github.com/alexbakker/CVE-2019-9465&#34;&gt;available on&#xA;GitHub&lt;/a&gt;. It has gone through a few&#xA;iterations since the initial report to Google. The screenshots below show the&#xA;latest version.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&#34;/img/Screenshot_20200222-122412.png&#34;&gt;&lt;img width=&#34;32%&#34; alt=&#34;Screenshot 1&#34;&#xA;src=&#34;/img/Screenshot_20200222-122412.png&#34;&gt;&lt;/a&gt;&#xA;&lt;a href=&#34;/img/Screenshot_20200222-122417.png&#34;&gt;&lt;img width=&#34;32%&#34; alt=&#34;Screenshot 2&#34;&#xA;src=&#34;/img/Screenshot_20200222-122417.png&#34;&gt;&lt;/a&gt;&#xA;&lt;a href=&#34;/img/Screenshot_20200222-122448.png&#34;&gt;&lt;img width=&#34;32%&#34; alt=&#34;Screenshot 3&#34;&#xA;src=&#34;/img/Screenshot_20200222-122448.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The app sits in a loop, repeatedly encrypts/decrypts some hard coded plaintext&#xA;and prints the results to the log. As shown in the screenshots above, user&#xA;authentication, the timeout between tries and some other things are configurable&#xA;in the options dialog. While we can&amp;rsquo;t see what going on inside the HSM, this&#xA;gives us a good look at the behavior we can see on the outside. Looking at the&#xA;log, it turns out that this bug causes cryptographic operations to produce&#xA;predictable and bogus ciphertext:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;plaintext: 746869732069732061207465737420737472696e67&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ciphertext: d62a2349d993632dddabc30a4a2c8ab7ba2608c5f2&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tag: fd6b38cba35ea579918f3b5ec1863e4b&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nonce: f102f60a0ef39e310c5f9c4c&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;decrypted: 746869732069732061207465737420737472696e67&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;plaintext: 746869732069732061207465737420737472696e67&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ciphertext: 0dd0adde0dd0adde0dd0adde0dd0adde585301005d&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tag: 995d100cc5d068a83e7ecf13c49e92eb&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nonce: cffb9148cb5154232c957ab7&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Note the ciphertext of the second iteration:&#xA;&lt;code&gt;0dd0adde0dd0adde0dd0adde0dd0adde585301005d&lt;/code&gt;. That doesn&amp;rsquo;t look as random as&#xA;one would expect. In fact, there&amp;rsquo;s even a sequence that repeats: &lt;code&gt;0dd0adde&lt;/code&gt;.&#xA;Let&amp;rsquo;s try that again.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;plaintext: 746869732069732061207465737420737472696e67&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ciphertext: 789ae5602a997f5ce7768b08fe5db2d1d7139fad30&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tag: 12e28ebf0f9492a76a453cd5d3bcf4ff&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nonce: e4921e4825ea1ad01881ad82&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;decrypted: 746869732069732061207465737420737472696e67&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;plaintext: 746869732069732061207465737420737472696e67&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ciphertext: 0dd0adde0dd0adde0dd0adde0dd0adde585301005d&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tag: 74eaa7be302f1dce6d53ae5a58dc2408&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nonce: a454451014a075e1883f4521&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;No matter how many times this is repeated, the resulting ciphertext is always&#xA;the same (while the nonce is always different, even). Now it&amp;rsquo;s obvious why&#xA;decryption failed in Aegis before. Trying to decrypt bogus ciphertext like that&#xA;will certainly result in a MAC verification failure and bogus plaintext. The&#xA;most dangerous thing about this, is the fact that it fails so spectacularly&#xA;without throwing an exception. This also completely defeats one of the most&#xA;important guarantees that symmetric ciphers provide: ciphertext that is&#xA;indistinguishable from random noise.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Playing around with the app some more, I concluded that waiting &amp;lsquo;too long&amp;rsquo;&#xA;(around 2 seconds) between cipher initialization and using it to encrypt/decrypt&#xA;something elicits this behavior. This appears to only be an issue with AES in&#xA;GCM mode. I also tested &lt;a href=&#34;https://developer.android.com/training/articles/keystore#HardwareSecurityModule&#34;&gt;the other supported ciphers and&#xA;modes&lt;/a&gt;,&#xA;but those seem to behave correctly.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Unfortunately, this is where my research grinded to a halt. To go further I&#xA;would need access to the firmware that is running on the Titan M chip, to see&#xA;what might be going wrong there. While Google &lt;a href=&#34;https://www.wired.com/story/google-titan-m-security-chip-pixel-3/&#34;&gt;has&#xA;promised&lt;/a&gt; to&#xA;open source the firmware, it has not delivered on that promise to this day. My&#xA;best guess would be that this is a memory corruption issue, but that&amp;rsquo;s about as&#xA;far as I&amp;rsquo;m going to get without more access. Google doesn&amp;rsquo;t seem to be willing&#xA;to discuss the details of the issue either, as you&amp;rsquo;ll notice while reading the&#xA;&lt;a href=&#34;#timeline&#34;&gt;Timeline&lt;/a&gt;.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;I also took a quick look at the Android source tree to see if I could find any&#xA;places where AES-GCM was used in combination with StrongBox &lt;em&gt;and&lt;/em&gt; the randomness&#xA;of ciphertext was being relied upon. The latter is the case with some CSPRNG&#xA;implementations, for example, though I can&amp;rsquo;t think of a reason why someone would&#xA;use GCM mode for that purpose. That&amp;rsquo;s the only attack vector I could come up&#xA;with, but perhaps someone more knowledgeable in Android&amp;rsquo;s internals can think of&#xA;something else.&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;timeline&#34;&gt;Timeline&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;In total, it took 6 months to get this fixed. Here&amp;rsquo;s the timeline:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-05-20&lt;/strong&gt; Report submitted.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-05-21&lt;/strong&gt; Google responds: We&amp;rsquo;re looking in to it.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-05-28&lt;/strong&gt; Google responds: Won&amp;rsquo;t Fix (Infeasible).&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The team tells me there are some errors in my implementation that cause the&#xA;exhibited behavior and that it&amp;rsquo;s not actually a bug in Android:&lt;/p&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;In the KeygenParameterSpec, setUserAuthenticationRequired(true) was set&#xA;up, but KeygenParameterSpec was not set on how to authenticate such as:&#xA;setUserAuthenticationValidityDurationSeconds(int) So the encryption was&#xA;never authorized.&lt;/li&gt;&#xA;&lt;li&gt;In addition, when instantiating the KeyGenParameterSpec,&#xA;KeyProperties.PURPOSE_DECRYPT was not added, so decryption failed.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;p&gt;Neither of these suggestions make sense. To be fair, I&amp;rsquo;ve always found the&#xA;Android Keystore key generation API to be a bit confusing, but it&amp;rsquo;s&#xA;interesting to see members of the Android Security team struggling with it&#xA;as well.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-05-28&lt;/strong&gt; I respond, suggesting that they take another look and actually&#xA;try to run the POC app, instead of trying to find flaws in my use of the API.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-06-06&lt;/strong&gt; I ask for a status update.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-06-11&lt;/strong&gt; Google responds: We have no update at this time.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-06-14&lt;/strong&gt; Google responds: High severity.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-07-05&lt;/strong&gt; I ask for a status update.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-07-08&lt;/strong&gt; Google responds: We&amp;rsquo;re still looking into it.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-08-26&lt;/strong&gt; I ask for a status update.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-08-26&lt;/strong&gt; Google responds: apologizing for the delay, saying that the&#xA;issue is taking longer to remediate than the usual 90 day window. Asks if I&#xA;intend to disclose, and if so, whether I&amp;rsquo;d be willing to participate in&#xA;coordinated disclosure.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-08-26&lt;/strong&gt; I respond, saying I don&amp;rsquo;t intend to disclose yet, as I don&amp;rsquo;t&#xA;have a patch/solution to go along with a disclosure.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-08-28&lt;/strong&gt; Google responds, thanking me for the clarification and assuring&#xA;me that they&amp;rsquo;ll keep me updated.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-10-08&lt;/strong&gt; I ask for a status update.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-10-14&lt;/strong&gt; Google responds: the issue has been fixed and they&amp;rsquo;re tracking&#xA;the fix for release in December. They&amp;rsquo;ll provide details soon regarding CVE&#xA;and reward eligibility. Also, the severity has been adjusted from High to&#xA;Critical.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-10-15&lt;/strong&gt; I respond, expressing that I&amp;rsquo;m glad it&amp;rsquo;s been fixed.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-11-20&lt;/strong&gt; I ask for a status update.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-11-25&lt;/strong&gt; Google responds: We&amp;rsquo;d like to acknowledge your contribution&#xA;publicly. CVE assigned: CVE-2020-0014.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-11-25&lt;/strong&gt; I respond: Thanks for the status update. I ask if the fix is&#xA;still on track for release in December and whether this report is eligible for&#xA;a reward. I tell them I plan on writing a blog post.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-11-26&lt;/strong&gt; Google responds: Thanks me for sharing my disclosure plans and&#xA;reassures me that the fix is still on track for release in December and that&#xA;the report is eligible for a reward.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-11-26&lt;/strong&gt; I respond: Thanks for the clarification and assuring them that&#xA;I&amp;rsquo;ll let them review this blog post first before I publish it.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-11-27&lt;/strong&gt; Google responds. The CVE number that was given previously is&#xA;incorrect. The correct one is: CVE-2019-9465.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-12-02&lt;/strong&gt; Google responds. The rewards committee decided to reward me for&#xA;reporting this security issue.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-12-02&lt;/strong&gt; I respond, thanking them for the reward. I also ask for more&#xA;details about the bug, as I have very little to go on the for the blog post I&#xA;plan to write.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-12-02&lt;/strong&gt; Google responds, confirming my suspicion that the bug was in&#xA;the Titan M firmware, but doesn&amp;rsquo;t provide any additional information.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-12-05&lt;/strong&gt; I respond, reporting my findings after installing the December&#xA;2019 security update: the bug is still present on my device.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2019-12-07 - 2019-12-24&lt;/strong&gt; Google responds, saying that they are unable to&#xA;reproduce the issue. After that, there was a lot of back and forth to try to&#xA;get logs from my device. It turned out that Android was not able to update the&#xA;firmware of the Titan M chip on my device, possibly due to a bad state I had&#xA;gotten it into while developing the PoC.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12-24 16:22:57.618  1087  1087 I init_citadel: Citadel version: 0.0.3/brick_v0.0.7574-5b47d37e 2019-06-25 19:20:19 gdk@chunky.cam.corp.google.com&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12-24 16:22:57.666  1108  1108 I init_citadel: Citadel is running a known older firmware so sending update&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12-24 16:22:57.778  1136  1136 I init_citadel: Citadel is C2-PVT, allowing RO updates&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12-24 16:23:11.812  2808  2808 I init_citadel: Citadel update loaded&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12-24 16:23:11.852  2810  2810 I init_citadel: Could not enable Citadel update: password required&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12-24 16:23:12.009  2812  2812 I init_citadel: Citadel rebooted&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12-24 16:24:19.263   584   584 I chatty  : uid=1064(hsm) /vendor/bin/hw/citadeld identical 5 lines&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12-24 16:24:20.357   806   806 E /vendor/bin/hw/android.hardware.authsecret@1.0-service.citadel: Incorrect Citadel update password&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12-24 16:24:29.466   825   825 I /vendor/bin/hw/android.hardware.oemlock@1.0-service.citadel: Running OemLock::setOemUnlockAllowedByCarrier: 1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12-24 16:24:29.473   584   584 I chatty  : uid=1064(hsm) /vendor/bin/hw/citadeld identical 1 line&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2020-02-02&lt;/strong&gt; I ask for a status update.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2020-02-07&lt;/strong&gt; Google responds, recommending me to factory reset my device to&#xA;resolve the state it is in, while they continue to investigate the issue.&lt;/p&gt;&lt;/li&gt;&#xA;&#xA;&lt;li&gt;&lt;p&gt;&lt;strong&gt;2020-02-23&lt;/strong&gt; I respond, saying I factory reset my device and that the&#xA;security issue is no longer present. I didn&amp;rsquo;t catch the update process itself,&#xA;but the firmware version does seem to be newer:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;02-23 16:38:11.981   921   921 I init_citadel: Checking citadel version&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;02-23 16:38:12.279  1027  1027 I init_citadel: Citadel version: 0.0.3/brick_v0.0.7580-2d3a8cfc 2019-09-16 20:42:26 gdk@chunky.cam.corp.google.com&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;02-23 16:38:12.333  1054  1054 I init_citadel: Citadel isn&amp;#39;t running a known older firmware so not updating&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h3 id=&#34;a-call-with-google&#34;&gt;A call with Google&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;After sharing the draft of this blog post with the team, I was asked if I would&#xA;be willing to join a short call, as they wanted to &amp;ldquo;provide some details/context&#xA;about the fix process for this issue prior to the publication&amp;rdquo; of my blog post.&#xA;I agreed.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;During the call they apologized for the long turnaround time and poor&#xA;communication. I appreciate that, as that was indeed the main disappointment I&#xA;had when submitting this as my first Android security issue report. I had to&#xA;keep asking for status updates and felt like I was being kept out of the loop,&#xA;while one would expect the team to share new information as it becomes&#xA;available. The initial draft of the blog post had a fairly snarky comment about&#xA;the fact that the severity rating changed from Won&amp;rsquo;t Fix, to High, to Critical.&#xA;They explained that their guidelines for severity ratings changed while in the&#xA;process of handling my report and they adjusted the severity rating based on&#xA;those new guidelines. Fair enough, I removed that comment.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The overall impression I got is that they genuinely care about handling Android&#xA;security reports well and regret that it didn&amp;rsquo;t go as well as they would have&#xA;liked this time around.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Naturally, I also used the opportunity to ask if they could provide some more&#xA;information about the nature of the actual bug and about the status of open&#xA;sourcing the Titan M firmware, but they couldn&amp;rsquo;t comment on that.&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;I ended up performing a factory reset on my device a few days ago, which seems&#xA;to have magically fixed the Titan M firmware update issue. The security issue&#xA;itself also appears to be resolved. I would have loved to try to dig deeper into&#xA;this, but as said, the source of the Titan M firmware is simply not available.&#xA;Google appears to have added &lt;a href=&#34;https://android.googlesource.com/platform/hardware/interfaces/+/8ddc1c700d63d03336d168703664ecf28ce12c15&#34;&gt;CTS&#xA;tests&lt;/a&gt;&#xA;for the exhibited behavior, but other than that, there is no trace of how this&#xA;bug was fixed.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;I also learned some important lessons. Upon initial disclosure to Google, I&#xA;should have firmly set the standard 90-day deadline, so that it&amp;rsquo;s clear for all&#xA;parties what the expectations are. Secondly, despite not setting a deadline&#xA;upfront, I should have disclosed this publicly much earlier than I ended up&#xA;doing. It just didn&amp;rsquo;t feel right to disclose a security issue that I didn&amp;rsquo;t have&#xA;a fix or workaround to offer for, but I&amp;rsquo;ve since come to the realization that&#xA;getting the information out there is more important.&lt;/p&gt;&#xA;</description>
      <pubDate>Sat, 29 Feb 2020 13:00:00 +0000</pubDate>
    </item>
    <item>
      <title>Notes on PCI Passthrough on NixOS using QEMU and VFIO</title>
      <link>https://alexbakker.me/post/nixos-pci-passthrough-qemu-vfio.html</link>
      <description>&lt;p&gt;With the release of the Ryzen 3000 series CPUs, I decided it was finally time to&#xA;upgrade from my good old Intel i5 2500K. It served me well for nearly 8 years,&#xA;but its age was starting to show. While doing the upgrade, I also wanted to&#xA;address the other two main pain points I had with my previous setup. Long story&#xA;short: I ended up installing NixOS and setting up PCI passthrough.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The Linux distribution I was using previously, Gentoo Linux, became too much of&#xA;a burden to maintain across multiple machines and I was looking for an&#xA;alternative that offers similar flexibility. The declarative configuration&#xA;system of NixOS appealed to me and I decided to give it a shot after playing&#xA;around with it for a bit.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The other annoyance I had, was the fact that I had to reboot into Windows to be&#xA;able to play games. However, with the combination of the IOMMU on modern&#xA;motherboards and the VFIO driver on Linux, it&amp;rsquo;s possible to directly and&#xA;securely access entire groups of PCIe devices from userspace. This allows one to&#xA;pass through a GPU to a Windows virtual machine, with minimal overhead in terms&#xA;of performance.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This blog post walks through my specific PCI passthrough setup, with some notes&#xA;on how to get it working on NixOS. If you&amp;rsquo;re new to PCI passthrough, this might&#xA;not be for you. The Arch Linux Wiki has &lt;a href=&#34;https://wiki.archlinux.org/index.php/PCI_passthrough_via_OVMF&#34;&gt;an excellent&#xA;article&lt;/a&gt; that you&#xA;can refer to if want to get up to speed. I relied on it heavily.&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;hardware&#34;&gt;Hardware&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The machine I ended up building has the following specifications:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;OS&lt;/strong&gt;: NixOS 19.09&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;CPU&lt;/strong&gt;: Ryzen 9 3900X&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Motherboard&lt;/strong&gt;: Gigabyte X570 Aorus Master (rev 1.0)&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;UEFI&lt;/strong&gt;: F7c (AGESA 1.0.0.3 ABBA)&lt;/li&gt;&#xA;&lt;/ul&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;RAM&lt;/strong&gt;: G.Skill DDR4 Ripjaws-V 2x16GB 3200MHz CL14&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;GPU 1&lt;/strong&gt;: Sapphire Nitro+ Radeon RX 580 4GD5&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;GPU 2&lt;/strong&gt;: Sapphire Nitro+ Radeon RX 590 8GD5&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;&lt;img src=&#34;/img/3900x-gigabyte-x570-aorus-master-rx590-rx580.jpg&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;You&amp;rsquo;ll want to do some research online before purchasing the hardware for your&#xA;machine to make sure that it has good IOMMU support. Perhaps someone has set up&#xA;PCI passthrough on the same hardware before and has posted the list of IOMMU&#xA;groups somewhere online.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Here&amp;rsquo;s the list of IOMMU groups on my system:&#xA;&lt;a href=&#34;/misc/iommu-groups.txt&#34;&gt;iommu-groups.txt&lt;/a&gt;.&lt;/p&gt;&#xA;&#xA;&lt;h3 id=&#34;uefi&#34;&gt;UEFI&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;To start things off, we need to make a couple of changes to the UEFI settings.&#xA;AMD SVM, IOMMU, ACS and AER support need to be enabled. We also need to make&#xA;sure to configure the initial display output GPU, so that the guest GPU remains&#xA;untouched during the boot process. On my setup, the RX 580 will be used by the&#xA;host and the RX 590 will be passed through to the guest. The setting defaults to&#xA;PCI slot 1, so I don&amp;rsquo;t have to make any changes there.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&#34;/img/190902095409.png&#34;&gt;&lt;img width=&#34;49%&#34; alt=&#34;UEFI Screenshot 1&#34;&#xA;src=&#34;/img/190902095409.png&#34;&gt;&lt;/a&gt; &lt;a href=&#34;/img/190902095500.png&#34;&gt;&lt;img width=&#34;49%&#34; alt=&#34;UEFI&#xA;Screenshot 2&#34; src=&#34;/img/190902095500.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&#34;/img/190928121527.png&#34;&gt;&lt;img width=&#34;49%&#34; alt=&#34;UEFI Screenshot 3&#34;&#xA;src=&#34;/img/190928121527.png&#34;&gt;&lt;/a&gt; &lt;a href=&#34;/img/190928121535.png&#34;&gt;&lt;img width=&#34;49%&#34; alt=&#34;UEFI&#xA;Screenshot 4&#34; src=&#34;/img/190928121535.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;vfio&#34;&gt;VFIO&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The next step is to identify the PCI slot numbers for the GPUs and the IOMMU&#xA;groups they&amp;rsquo;re in. Boot your OS and run the following script:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/usr/bin/env bash&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;shopt&lt;/span&gt; -s nullglob&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; d in /sys/kernel/iommu_groups/*/devices/*&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;d&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;#*/iommu_groups/*&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;%%/*&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;IOMMU Group %s &amp;#39;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    lspci -nns &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;d&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;##*/&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;You should see two VGA devices, each in a separate IOMMU group, along with an&#xA;audio device in the same group. Take note of the PCI slot number of the VGA and&#xA;audio device you want to pass through to the guest. In my case, that&amp;rsquo;d be&#xA;&lt;code&gt;0b:00.0&lt;/code&gt; and &lt;code&gt;0b:00.1&lt;/code&gt;&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 24 0a:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere [Radeon RX 470/480/570/570X/580/580X] [1002:67df] (rev e7)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 24 0a:00.1 Audio device [0403]: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere [Radeon RX 580] [1002:aaf0]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 25 0b:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere [Radeon RX 470/480/570/570X/580/580X] [1002:67df] (rev e1)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 25 0b:00.1 Audio device [0403]: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere [Radeon RX 580] [1002:aaf0]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Next, we&amp;rsquo;ll make some changes to the initrd to ensure that the &lt;code&gt;vfio-pci&lt;/code&gt;&#xA;driver is loaded for our guest GPU, instead of &lt;code&gt;amdgpu&lt;/code&gt;. To allow early kernel&#xA;modesetting to continue working with this setup, we load &lt;code&gt;vfio-pci&lt;/code&gt; for the&#xA;guest GPU in the &lt;code&gt;preDeviceCommand&lt;/code&gt; script block, which is executed before&#xA;udev is started.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;boot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;initrd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;availableKernelModules&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;amdgpu&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;vfio-pci&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;boot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;initrd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;preDeviceCommands&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;  DEVS=&amp;#34;0000:0b:00.0 0000:0b:00.1&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;  for DEV in $DEVS; do&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;    echo &amp;#34;vfio-pci&amp;#34; &amp;gt; /sys/bus/pci/devices/$DEV/driver_override&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;  done&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;  modprobe -i vfio-pci&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;We&amp;rsquo;ve already enabled virtualisation and IOMMU support in the UEFI, but we also&#xA;need pass a couple of parameters to the kernel command line (&lt;code&gt;intel_iommu=on&lt;/code&gt;&#xA;for Intel CPUs and &lt;code&gt;amd_iommu=on&lt;/code&gt; for AMD CPUs). We also need to load an extra&#xA;kernel module to be able to use KVM (&lt;code&gt;kvm-intel&lt;/code&gt; for Intel CPUs and&#xA;&lt;code&gt;kvm-amd&lt;/code&gt; for AMD CPUs).&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;boot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernelPackages&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;linuxPackages_latest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;boot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernelParams&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;amd_iommu=on&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;pcie_aspm=off&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;boot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernelModules&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;kvm-amd&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I had to add an extra parameter to turn off PCIe ASPM. Without it, the kernel&#xA;would start kicking out AER errors and the whole system would become unstable&#xA;shortly afterwards. On a side note: I usually use the latest kernel so that I&#xA;receive new features (and any VFIO-related bug fixes) quickly, but if you like&#xA;having a stable system, you might want to comment that part out.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Apply the configuration by running &lt;code&gt;nixos-rebuild switch&lt;/code&gt; and reboot.&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;qemu-and-libvirt&#34;&gt;QEMU and libvirt&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Next, we&amp;rsquo;ll set up libvirt. Libvirt is a tool that abstracts management of&#xA;virtual machines with support for multiple different hypervisors. This is not&#xA;strictly necessary, as we could also piece together a raw QEMU command&#xA;ourselves, but libvirt makes the whole thing a lot more manageable once you&#xA;start running multiple virtual machines. Add the following to your&#xA;&lt;code&gt;configuration.nix&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;environment&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;systemPackages&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;virtmanager&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;virtualisation&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libvirtd&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;enable&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;qemuOvmf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;qemuRunAsRoot&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;onBoot&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ignore&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;onShutdown&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;shutdown&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This will install libvirt along with OVMF and configure the libvirtd service to&#xA;be started on boot. I also set &lt;code&gt;onBoot&lt;/code&gt; to &lt;code&gt;ignore&lt;/code&gt; and &lt;code&gt;onShutdown&lt;/code&gt; to&#xA;&lt;code&gt;shutdown&lt;/code&gt;, so that the virtual machines are always shut down cleanly and&#xA;never automatically started when the host boots.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;From this point, you can install Windows in a virtual machine as you would on&#xA;any other Linux distribution. As said, I&amp;rsquo;m not going to go over the whole&#xA;process in this blog post, as the Arch Wiki already has &lt;a href=&#34;https://wiki.archlinux.org/index.php/PCI_passthrough_via_OVMF&#34;&gt;a comprehensive&#xA;article&lt;/a&gt; on it.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;And that’s it! You should now be able to create a PCI passthrough setup on&#xA;NixOS! My libvirt configuration file is available here for reference:&#xA;&lt;a href=&#34;/misc/libvirt-nt10.xml&#34;&gt;libvirt-nt10.xml&lt;/a&gt;.&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;bonus&#34;&gt;Bonus&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;There are some additional pieces of software that you can install to make the&#xA;whole experience a bit more pleasant.&lt;/p&gt;&#xA;&#xA;&lt;h3 id=&#34;looking-glass&#34;&gt;Looking Glass&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&#34;https://looking-glass.hostfission.com/&#34;&gt;Looking Glass&lt;/a&gt; is a piece of software&#xA;that can capture the video output of a GPU passed through to a virtual machine&#xA;and share it with the host by writing it to an Inter-VM shared memory device.&#xA;The Looking Glass client can read from that device and display the video output&#xA;on the host machine.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;It is available in the Nix package collection as&#xA;&lt;a href=&#34;https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/virtualization/looking-glass-client/default.nix&#34;&gt;looking-glass-client&lt;/a&gt;.&#xA;Once you&amp;rsquo;ve gone through &lt;a href=&#34;https://looking-glass.hostfission.com/quickstart/win/host&#34;&gt;the setup&#xA;process&lt;/a&gt; on Windows,&#xA;you&amp;rsquo;ll want to automatically create the SHM file on the NixOS side with some&#xA;help from systemd-tmpfiles.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;systemd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmpfiles&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rules&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s2&#34;&gt;&amp;#34;f /dev/shm/looking-glass 0660 alex qemu-libvirtd -&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;And add it to the configuration of your virtual machine.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;&amp;lt;shmem&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;name=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;looking-glass&amp;#39;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;model&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;ivshmem-plain&amp;#39;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;/&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;size&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;unit=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;32&lt;span class=&#34;nt&#34;&gt;&amp;lt;/size&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;address&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;pci&amp;#39;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;domain=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;0x0000&amp;#39;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;bus=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;0x0b&amp;#39;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;slot=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;0x01&amp;#39;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;function=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;0x0&amp;#39;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;/&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;&amp;lt;/shmem&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;You can then launch the client with &lt;code&gt;looking-glass-client -f&#xA;/dev/shm/looking-glass&lt;/code&gt;. Here&amp;rsquo;s a short clip of Looking Glass in action:&lt;/p&gt;&#xA;&#xA;&lt;video controls&gt;&#xA;  &lt;source src=&#34;https://alexbakker.me/u/pq82m89ing.webm&#34; type=&#34;video/mp4&#34;&gt;&#xA;&lt;/video&gt;&#xA;&#xA;&lt;p&gt;While the performance and latency is really impressive, I wouldn&amp;rsquo;t recommend&#xA;using this for very latency-sensitive games like first-person shooters, as the&#xA;latency Looking Glass adds will still be at least as bad or worse than having&#xA;Vsync enabled. It&amp;rsquo;s a great solution for nearly all other use cases, though.&lt;/p&gt;&#xA;&#xA;&lt;h3 id=&#34;scream&#34;&gt;Scream&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/duncanthrax/scream&#34;&gt;Scream&lt;/a&gt; is a virtual network sound card&#xA;for Windows. While it&amp;rsquo;s primary functionality is publishing the audio played&#xA;through the device on the local network, it also supports IVSHMEM, like Looking&#xA;Glass. This allows playing the guest audio on the host in a much better way than&#xA;some of the other solutions I&amp;rsquo;ve tried.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;It is available in the Nix package collection as&#xA;&lt;a href=&#34;https://github.com/NixOS/nixpkgs/blob/master/pkgs/misc/scream-receivers/default.nix&#34;&gt;scream-receivers&lt;/a&gt;.&#xA;Once you&amp;rsquo;ve &lt;a href=&#34;https://github.com/duncanthrax/scream#download-and-install&#34;&gt;set up the Scream&#xA;driver&lt;/a&gt; on Windows,&#xA;you&amp;rsquo;ll want to automatically create another SHM file like we did before and&#xA;define a systemd user service for the Scream client.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;systemd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmpfiles&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rules&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s2&#34;&gt;&amp;#34;f /dev/shm/scream 0660 alex qemu-libvirtd -&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;systemd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;services&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scream-ivshmem&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;enable&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Scream IVSHMEM&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;serviceConfig&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ExecStart&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scream-receivers&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/bin/scream-ivshmem-pulse /dev/shm/scream&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Restart&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;always&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;wantedBy&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;multi-user.target&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;pulseaudio.service&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;And add it to the configuration of your virtual machine:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;&amp;lt;shmem&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;name=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;scream&amp;#39;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;model&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;ivshmem-plain&amp;#39;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;/&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;size&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;unit=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;2&lt;span class=&#34;nt&#34;&gt;&amp;lt;/size&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;address&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;pci&amp;#39;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;domain=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;0x0000&amp;#39;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;bus=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;0x0b&amp;#39;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;slot=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;0x02&amp;#39;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;function=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;0x0&amp;#39;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;/&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;&amp;lt;/shmem&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;I hope this blog post gives you an idea of where to get started to get PCI&#xA;passthrough working on NixOS. Eventhough my setup is almost certainly not&#xA;exactly the same as yours, most of the NixOS-specific parts discussed will apply&#xA;for everyone. To summarize, the final &lt;code&gt;configuration.nix&lt;/code&gt; snippet looks like&#xA;this:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;environment&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;systemPackages&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;looking-glass-client&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;scream-receivers&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;virtmanager&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;virtualisation&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libvirtd&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;enable&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;qemuOvmf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;qemuRunAsRoot&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;onBoot&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ignore&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;onShutdown&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;shutdown&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;boot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernelPackages&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;linuxPackages_latest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;boot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernelParams&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;amd_iommu=on&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;pcie_aspm=off&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;boot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernelModules&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;kvm-amd&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;boot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;initrd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;availableKernelModules&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;amdgpu&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;vfio-pci&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;boot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;initrd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;preDeviceCommands&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;  DEVS=&amp;#34;0000:0b:00.0 0000:0b:00.1&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;  for DEV in $DEVS; do&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;    echo &amp;#34;vfio-pci&amp;#34; &amp;gt; /sys/bus/pci/devices/$DEV/driver_override&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;  done&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;  modprobe -i vfio-pci&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;systemd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmpfiles&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rules&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s2&#34;&gt;&amp;#34;f /dev/shm/scream 0660 alex qemu-libvirtd -&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s2&#34;&gt;&amp;#34;f /dev/shm/looking-glass 0660 alex qemu-libvirtd -&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;systemd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;services&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scream-ivshmem&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;enable&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Scream IVSHMEM&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;serviceConfig&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ExecStart&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pkgs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scream-receivers&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/bin/scream-ivshmem-pulse /dev/shm/scream&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Restart&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;always&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;wantedBy&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;multi-user.target&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;requires&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;pulseaudio.service&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <pubDate>Sat, 28 Sep 2019 22:30:00 +0000</pubDate>
    </item>
    <item>
      <title>Did cosmic rays break my Linux build?</title>
      <link>https://alexbakker.me/post/did-cosmic-rays-break-my-linux-build.html</link>
      <description>&lt;p&gt;I think I experienced a random bit flip while updating Linux on one of my&#xA;machines today. My laptop was humming along happily during compilation until GCC&#xA;suddenly aborted with an error: &lt;strong&gt;&lt;em&gt;invalid preprocessing directive #lefine; did&#xA;you mean #define?&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;img src=&#34;/img/random-bit-flip.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Huh, &lt;code&gt;#lefine&lt;/code&gt; instead of &lt;code&gt;#define&lt;/code&gt;?&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Now, GCC is known for its cryptic error messages, but this one left me baffled.&#xA;Things I tried to figure out what the issue could be:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;I first grepped the offending file, &lt;code&gt;drivers/gpu/drm/i915/i915_reg.h&lt;/code&gt;, for&#xA;&lt;code&gt;#lefine&lt;/code&gt; to see if a typo somehow slipped through the Linux 4.19.1 release,&#xA;but got 0 matches.&lt;/li&gt;&#xA;&lt;li&gt;When I resumed the build, it completed without errors. The kernel also&#xA;appeared to run fine upon reboot. I ended up recompiling it entirely multiple&#xA;times to see if I could reproduce the error, but I couldn&amp;rsquo;t.&lt;/li&gt;&#xA;&lt;li&gt;I ran a MemTest86 test for 24 hours, but it didn&amp;rsquo;t find any errors, so the RAM&#xA;is also unlikely to be the culprit.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;I thought I was losing my mind until it dawned on me that this could have been&#xA;caused by cosmic rays. Looking at ASCII table, we see that &amp;rsquo;d&amp;rsquo; and &amp;lsquo;l&amp;rsquo; are&#xA;indeed one bit flip away from each other:&lt;/p&gt;&#xA;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th align=&#34;left&#34;&gt;char&lt;/th&gt;&#xA;&lt;th align=&#34;left&#34;&gt;decimal&lt;/th&gt;&#xA;&lt;th align=&#34;left&#34;&gt;binary&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td align=&#34;left&#34;&gt;d&lt;/td&gt;&#xA;&lt;td align=&#34;left&#34;&gt;100&lt;/td&gt;&#xA;&lt;td align=&#34;left&#34;&gt;1100100&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&#xA;&lt;tr&gt;&#xA;&lt;td align=&#34;left&#34;&gt;l&lt;/td&gt;&#xA;&lt;td align=&#34;left&#34;&gt;108&lt;/td&gt;&#xA;&lt;td align=&#34;left&#34;&gt;1101100&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Could that be it? Isn&amp;rsquo;t that incredibly unlikely? There doesn&amp;rsquo;t appear to be a&#xA;consensus in existing literature &lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; &lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; on how often these errors&#xA;actually occur, but I did learn that this phenomenon is actually more common&#xA;than I thought. The chances of flipping a bit that would cause software to break&#xA;in this fashion, on the other hand, must be incredibly small.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;In the end, there&amp;rsquo;s just no way to prove that this was actually caused by cosmic&#xA;rays. It could also have been some other extremely rare hardware fluke. Either&#xA;way, this took me by surprise, to say the least.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Perhaps this is the cosmos&amp;rsquo; way of telling me to invest in ECC RAM.&lt;/p&gt;&#xA;&#xA;&lt;div class=&#34;footnotes&#34;&gt;&#xA;&#xA;&lt;hr /&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&lt;a href=&#34;http://www.cs.toronto.edu/~bianca/papers/sigmetrics09.pdf&#34;&gt;http://www.cs.toronto.edu/~bianca/papers/sigmetrics09.pdf&lt;/a&gt;&lt;/li&gt;&#xA;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&lt;a href=&#34;https://www.fiala.me/pubs/papers/sc12-redmpi.pdf&#34;&gt;https://www.fiala.me/pubs/papers/sc12-redmpi.pdf&lt;/a&gt;&lt;/li&gt;&#xA;&#xA;&lt;li id=&#34;fn:3&#34;&gt;&lt;a href=&#34;https://media.blackhat.com/bh-us-11/Dinaburg/BH_US_11_Dinaburg_Bitsquatting_WP.pdf&#34;&gt;https://media.blackhat.com/bh-us-11/Dinaburg/BH_US_11_Dinaburg_Bitsquatting_WP.pdf&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;/div&gt;&#xA;</description>
      <pubDate>Sun, 01 Sep 2019 00:00:00 +0000</pubDate>
    </item>
    <item>
      <title>Insecure seed generation in the Nano Android wallet</title>
      <link>https://alexbakker.me/post/insecure-seed-nano-android-wallet.html</link>
      <description>&lt;p&gt;On the 21th of June 2018, the release of the new wallet applications for Nano&#xA;was &lt;a href=&#34;https://www.reddit.com/r/nanocurrency/comments/8stuf0/nano_wallet_for_ios_android_mac_windows_and_linux/&#34;&gt;announced on&#xA;Reddit&lt;/a&gt;.&#xA;Shortly after that, &lt;a href=&#34;https://www.reddit.com/r/nanocurrency/comments/8svty4/attention_anyone_who_generated_a_seed_using_the/?sort=top&#34;&gt;another&#xA;announcement&lt;/a&gt;&#xA;was made telling users of the Android app to transfer their funds to a wallet&#xA;with a seed that was not generated by the app. I quickly looked up the source&#xA;code and found that the app was using a random number generator that is not&#xA;cryptographically secure. Let&amp;rsquo;s analyze how bad this really is. Spoiler: it&amp;rsquo;s&#xA;bad.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;em&gt;Discussed on&#xA;&lt;a href=&#34;https://www.reddit.com/r/nanocurrency/comments/8vjjt6/writeup_insecure_seed_generation_in_the_nano&#34;&gt;Reddit&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;the-code&#34;&gt;The code&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Let&amp;rsquo;s look at the vulnerable piece of&#xA;&lt;a href=&#34;https://github.com/nano-wallet-company/nano-wallet-android/blob/85b0de53db6a1876a66fa17c009275ed5ca5afc7/app/src/main/java/co/nano/nanowallet/NanoUtil.java#L26-L34&#34;&gt;code&lt;/a&gt;&#xA;first:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;java.util.Random&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;String&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;generateSeed&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;numchars&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;64&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Random&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;random&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Random&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;();&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;StringBuilder&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sb&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;StringBuilder&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;();&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;numchars&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;sb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Integer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toHexString&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;random&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;nextInt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;()));&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toString&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;substring&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;numchars&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toUpperCase&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;();&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;As you can see, it&amp;rsquo;s using java.util.Random to generate the seed. The algorithm&#xA;that Random uses to generate random numbers is &lt;strong&gt;not cryptographically secure&lt;/strong&gt;.&#xA;It&amp;rsquo;s seeded with a 64-bit integer (usually the current time in milliseconds by&#xA;default if no seed is specified) and given a number of outputs, the following&#xA;outputs can be predicted without knowing the seed.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Ok, so this sounds bad, but is it actually exploitable in practise?&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;difference-in-api-levels&#34;&gt;Difference in API levels&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;We first need to know what the implementation of java.util.Random looks like on&#xA;Android. The API of Random is the same across all API levels, but the&#xA;implementation differs. Not only the default seed is different, but the&#xA;algorithm to generate random numbers is also different. We&amp;rsquo;re only going to look&#xA;at how the default seed is calculated as the underlying algorithm doesn&amp;rsquo;t really&#xA;impact our ability to exploit this vulnerability.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The oldest Android API level the app supports is 16, so we&amp;rsquo;ll start there.&lt;/p&gt;&#xA;&#xA;&lt;h3 id=&#34;level-16-19&#34;&gt;Level 16 - 19&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;On API levels 16 - 19, the default seed of Random is calculated as follows&#xA;(&lt;a href=&#34;https://github.com/AndroidSDKSources/android-sdk-sources-for-api-level-19/blob/master/java/util/Random.java&#34;&gt;source&lt;/a&gt;):&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;Random&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Note: Using identityHashCode() to be hermetic wrt subclasses.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;setSeed&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;currentTimeMillis&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;identityHashCode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;));&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Older versions of Android use a common implementation of Random where the RNG is&#xA;seeded with the sum of the current time in milliseconds and the hashCode of the&#xA;Random object.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Time is obviously a bad source for secure randomness. If we wanted to iterate&#xA;over all timestamps of a particular day, we&amp;rsquo;d only have 86400000 of them to go&#xA;through (as that&amp;rsquo;s the amount of milliseconds a day has).&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The default hashCode implementation can differ across JVM implementations, but&#xA;it usually returns the memory address of the object. This is also the case on&#xA;Android. That makes it a little harder to guess, but it&amp;rsquo;s a 32-bit number and&#xA;therefore also trivially brute-forceable.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Let&amp;rsquo;s say we wanted to brute-force all seeds that could have been generated&#xA;during the beta period. The timespan of the beta period from the initial&#xA;announcement up until the announcement of the vulnerability is about 4 months&#xA;(10510000000 milliseconds). We need to account for the addition of the 32-bit&#xA;number, so we&amp;rsquo;ll subtract 2&lt;sup&gt;31&lt;/sup&gt; from the timestamp we start with and&#xA;add 2&lt;sup&gt;31&lt;/sup&gt; to the last timestamp. This gives us a total key space of&#xA;only 14804967296 (less than 2&lt;sup&gt;34&lt;/sup&gt;)!&lt;/p&gt;&#xA;&#xA;&lt;h3 id=&#34;level-20-23&#34;&gt;Level 20 - 23&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;On API levels 20 - 23, the default seed of Random is calculated as follows&#xA;(&lt;a href=&#34;https://github.com/AndroidSDKSources/android-sdk-sources-for-api-level-23/blob/master/java/util/Random.java&#34;&gt;source&lt;/a&gt;):&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;private&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;volatile&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;seedBase&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;Random&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Note: Don&amp;#39;t use identityHashCode(this) since that causes the monitor to&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// get inflated when we synchronize.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;setSeed&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;nanoTime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;seedBase&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;);&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;seedBase&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This implementation uses the sum of System.nanoTime and an offset to seed the&#xA;RNG.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Note that nanoTime does not represent the current time. The starting point is&#xA;unspecified. On Linux, this represents the elapsed time since startup in&#xA;nanoseconds, excluding the amount of time spent sleeping (CLOCK_MONOTONIC). This&#xA;is also the case on Android. I&amp;rsquo;d say this number is a bit harder to guess, but&#xA;it&amp;rsquo;s definitely a lot less than 64 bits of entropy.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Integer &amp;lsquo;seedBase&amp;rsquo; is incremented to make sure every instance of Random produces&#xA;a different output. That&amp;rsquo;s its only purpose, it doesn&amp;rsquo;t make things any more&#xA;secure.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;To be clear, even if nanoTime wasn&amp;rsquo;t predictable in any way, a key space of 64&#xA;bits is still way too small for comfort. There&amp;rsquo;s a reason why we only use key&#xA;sizes of at least 128 bits.&lt;/p&gt;&#xA;&#xA;&lt;h3 id=&#34;level-24-27&#34;&gt;Level 24 - 27&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;On API levels 24 - 27, the default seed of Random is calculated as follows&#xA;(&lt;a href=&#34;https://github.com/AndroidSDKSources/android-sdk-sources-for-api-level-23/blob/master/java/util/Random.java&#34;&gt;source&lt;/a&gt;):&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;Random&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;seedUniquifier&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;^&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;nanoTime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;());&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;private&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;seedUniquifier&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// L&amp;#39;Ecuyer, &amp;#34;Tables of Linear Congruential Generators of&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// Different Sizes and Good Lattice Structure&amp;#34;, 1999&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(;;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;seedUniquifier&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;();&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;next&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;181783497276652981L&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;seedUniquifier&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;compareAndSet&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;current&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;private&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;final&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AtomicLong&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;seedUniquifier&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AtomicLong&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8682522807148012L&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This looks a bit more complicated, but the principle is basically the same as&#xA;the previous implementation we looked at. It also uses nanoTime to seed the RNG&#xA;but it has a different mechanism to make sure all instances of Random produce&#xA;different output.&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;proof-of-concept-attack&#34;&gt;Proof of concept attack&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;To test if my analysis is correct, I decided to write a POC program that&#xA;generates all seeds that could have been generated during the entire beta period&#xA;of the app on Android devices with API level 19 or lower.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Here are the steps the program goes through:&lt;/p&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Generate the list of seeds, starting with the time of the beta announcement&#xA;minus 2&lt;sup&gt;31&lt;/sup&gt; and ending with the time of the vulnerability&#xA;announcement plus 2&lt;sup&gt;31&lt;/sup&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Derive Ed25519 keypairs from the generated seeds. This involves doing some&#xA;BLAKE2b hashing to derive a private key from the seed and an index number.&lt;/li&gt;&#xA;&lt;li&gt;Iterate over all public keys of the keypairs and check if any of them exist&#xA;in the frontier list.&lt;/li&gt;&#xA;&lt;li&gt;If there&amp;rsquo;s a match, we know we have found the seed for that particular public&#xA;key.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;p&gt;There are definitely more intelligent ways to do this attack. This is just a&#xA;proof of concept. For example, a way to improve the attack could be to reduce&#xA;the space of the 32-bit number we need to explore by taking memory alignment&#xA;into account.&lt;/p&gt;&#xA;&#xA;&lt;h3 id=&#34;results&#34;&gt;Results&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;After letting the program run for a couple of days, I found a total of &lt;strong&gt;84&#xA;existing addresses&lt;/strong&gt; that I was able to generate a seed for. The addresses held&#xA;a grand &lt;strong&gt;total of around 663 NANO&lt;/strong&gt;. To be absolutely clear, I&amp;rsquo;m not going to&#xA;steal any funds. I deleted the seeds right after the brute-force completed.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This is not a lot of money, but it&amp;rsquo;s not insignificant either. Keep in mind that&#xA;we only looked at a very small portion of affected users: the ones running&#xA;Android KitKat or older. According to &lt;a href=&#34;https://developer.android.com/about/dashboards/#Platform&#34;&gt;Google&amp;rsquo;s&#xA;statistics&lt;/a&gt;, this&#xA;amounts to 14.6% of their userbase. We did not look at more recent Android&#xA;versions, which amount to 84.7%. Surely, we would have found a lot more seeds&#xA;with existing addresses if we did do that. As far as I can tell that would&#xA;require quite a bit more computing power though.&lt;/p&gt;&#xA;&#xA;&lt;h3 id=&#34;warning-users&#34;&gt;Warning users&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Eventhough the Nano team repeatedly reached out through their social media&#xA;channels (Reddit, Twitter, Discord, Telegram and even Blockfolio) telling users&#xA;to change their seeds, the accounts I found still held a bunch of NANO. Of&#xA;course not every holder of NANO is active on social media or follows&#xA;cryptocurrency news, so I wanted to try a different way to warn users before&#xA;publishing this post.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;My first idea was to send transactions to all vulnerable addresses I found and&#xA;use &lt;a href=&#34;https://nanoo.tools/steganography&#34;&gt;steganography&lt;/a&gt; to encode a message into&#xA;the balance. While this is a cute way to send messages over the block lattice,&#xA;it&amp;rsquo;s very unlikely users will notice this. A friend came up with a much better&#xA;idea: send small amounts of NANO from 3 vanity addresses that spell out a&#xA;message:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&#xA;xrb_1&lt;b&gt;change&lt;/b&gt;c1b68rgyrhpbngthck1p3yekcu868chcxnm6zsm6u87u4bx1iw7wj&#xA;xrb_1&lt;b&gt;seed&lt;/b&gt;mpo9e63piyyo77db44i6hthedmou9chthe3qudswow75q8f7rzfhhrg&#xA;xrb_1&lt;b&gt;asap&lt;/b&gt;5ufpqzobb1rkdnjx3eieantny16b1dpequy3csrcrsixexa4517xh7y&#xA;&lt;/pre&gt;&#xA;&#xA;&lt;p&gt;I sent 0.000001 NANO from each of the above addresses to the vulnerable&#xA;addresses I found that had a balance of 0.001 or more. Unfortunately the&#xA;transactions didn&amp;rsquo;t always arrive in the correct order. Due to the way a block&#xA;lattice works, wallets have no way of knowing the order in which transactions&#xA;occurred if the transactions did not originate from a single account, so the&#xA;order ends up being arbitrary.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;But sure enough, one of the accounts responded by moving their funds elsewhere:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;img src=&#34;/img/nano-change-seed-asap.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Luckily, this happened to be the account that held the largest amount of NANO.&#xA;This resulted in a big reduction of the amount of NANO these addresses were&#xA;holding. The total is now around 131 NANO at the time of writing.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Update 2018-07-02&lt;/strong&gt;: After publishing this post another account appears to&#xA;have transferred its funds elsewhere:&#xA;&lt;a href=&#34;https://www.nanode.co/account/xrb_16dpz3fj8o3i8tizmyx9ataxmcus53bb3tgfy5eu6f86d4ozc5i8tuww7sdn&#34;&gt;xrb_16dpz3fj8o3i8tizmyx9ataxmcus53bb3tgfy5eu6f86d4ozc5i8tuww7sdn&lt;/a&gt;.&#xA;According to the transaction history, this account has received funds from the&#xA;address the funds were just sent to before, so we can be reasonably sure that&#xA;they were not stolen. This brings the total down to about 34 NANO.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Update 2018-07-06&lt;/strong&gt;: It looks like someone has reproduced the attack and stole&#xA;the remaining funds. Luckily the majority of the funds on the vulnerable&#xA;addresses I found were moved elsewhere as a result of my post, but he still got&#xA;away with 34 NANO. This is the address of the thief:&#xA;&lt;a href=&#34;https://www.nanode.co/account/xrb_3tsjtouqoae78e6pba1e1s1amod66fxsswrq4dzkg3ohh1fqgfrykr75xw6w&#34;&gt;xrb_3tsjtouqoae78e6pba1e1s1amod66fxsswrq4dzkg3ohh1fqgfrykr75xw6w&lt;/a&gt;.&lt;/p&gt;&#xA;&#xA;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;This is one of the worst mistakes one can make when using cryptography.&#xA;Unsurprisingly, this turns out to be very easy to exploit and it&amp;rsquo;s only a matter&#xA;of time before someone else exploits this vulnerability and starts stealing the&#xA;remaining funds. I was going to publish the POC code but decided not to because&#xA;I&amp;rsquo;m afraid I&amp;rsquo;ll receive the blame eventhough the attack I demonstrated is&#xA;trivial. To be honest, I was very surprised to see that no funds had been stolen&#xA;yet.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Before publishing this post, I gave the Nano team a chance to read it and to&#xA;provide feedback. I also kept them up to date on what I was doing and what the&#xA;results of the proof of concept attack were.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;It&amp;rsquo;s important to note that this vulnerability was patched almost immediately&#xA;after it was found. Seeds generated with the new version of the app are&#xA;generated using a CSPRNG and are therefore secure. I spoke with the Nano team&#xA;and was told that the vast majority of their users are now on version 1.0.2 or&#xA;newer of the app which means they were forced to migrate to a new seed. However,&#xA;users who exported their seed and uninstalled the app are still at risk.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;So please, if you used the Nano Android wallet, move your funds to an address&#xA;derived from a different seed if you haven&amp;rsquo;t done so already.&lt;/strong&gt;&lt;/p&gt;&#xA;</description>
      <pubDate>Mon, 02 Jul 2018 00:00:00 +0000</pubDate>
    </item>
  </channel>
</rss>