Kushal Das

FOSS and life. Kushal Das talks here.

kushal76uaid62oup5774umh654scnu5dwzh4u2534qxhcbi4wbab3ad.onion

Updates from Johnnycanencrypt development in last few weeks

In July this year, I wrote a very initial Python module in Rust for OpenPGP, Johnnycanencrypt aka jce. It had very basic encryption, decryption, signing, verification, creation of new keys available. It uses https://sequoia-pgp.org library for the actual implementation.

I wanted to see if I can use such a Python module (which does not call out to the gpg2 executable) in the SecureDrop codebase.

First try (2 weeks ago)

Two weeks ago on the Friday, when I sat down to see if I can start using the module, within a few minutes, I understood it was not possible. The module was missing basic key management, more more refined control over creation, or expiration dates.

On that weekend, I wrote a KeyStore using file-based keys as backend and added most of the required functions to try again.

The last Friday

I sat down again; this time, I had a few friends (including Saptak, Nabarun) on video along with me, and together we tried to plug the jce inside SecureDrop container for Focal. After around 4 hours, we had around 5 failing tests (from 32) in the crypto-related tests. Most of the basic functionality was working, but we are stuck for the last few tests. As I was using the file system to store the keys (in simple .sec or .pub files), it was difficult to figure out the existing keys when multiple processes were creating/deleting keys in the same KeyStore.

Next try via a SQLite based KeyStore

Next, I replaced the KeyStore with an SQLite based backend. Now multiple processes can access the keys properly. With a few other updates, now I have only 1 failing test (where I have to modify the test properly) in that SecureDrop Focal patch.

While doing this experiment, I again found the benefits of writing the documentation of the library as I developed. Most of the time, I had to double-check against it to make sure that I am doing the right calls. I also added one example where one can verify the latest (10.0) Tor Browser download via Python.

In case you already use OpenPGP encryption in your tool/application, or you want to try it, please give jce a try. Works on Python3.7+. I tested on Linux and macOS, and it should work on Windows too. I have an issue open on that, and if you know how to do that, please feel free to submit a PR.

Using Stem and PySocks to access network over Tor

I previously wrote about using the standard SOCKS proxy provided by the Tor Project on your system using Python, in particular using the requests module.

But, what about if you want to start a Tor SOCKS proxy only for your project (while the code is running), and use some existing code/module to do network calls (using sockets) over it?

Stem module to control the tor process

We can use Stem module to control the tor process in the system. In our example below, we will use PySocks module along with so that we can use urllib module to fetch some data. The code is based on one of the tutorial at the stem project. You will also notice that we are asking to use any exitnode from the Russia while creating the tor process.

Starting the tor process with a given SOCKS proxy port is super simple. And then we replace socket.socket with socks.socksocket (after the right configuration), and socket.getaddrinfo with our own implementation to make sure that we don't leak DNS information.

import io
import socket
import urllib.request

import socks
import stem.process
from stem.util import term

SOCKS_PORT = 7000


def query(url):
    """
    Uses urllib to fetch a site using the proxy on the SOCKS_PORT.
    """
    return urllib.request.urlopen(url).read()


def print_bootstrap_lines(line):
    if "Bootstrapped " in line:
        print(term.format(line, term.Color.BLUE))


def getaddrinfo(*args):
    "Let us do the actual DNS resolution in the SOCKS5 proxy"
    return [(socket.AF_INET, socket.SOCK_STREAM, 6, "", (args[0], args[1]))]


def main():
    # Start an instance of Tor configured to only exit through Russia. This prints
    # Tor's bootstrap information as it starts. Note that this likely will not
    # work if you have another Tor instance running.
    print(term.format("Starting Tor:\n", term.Attr.BOLD))

    tor_process = stem.process.launch_tor_with_config(
        config={
            "SocksPort": str(SOCKS_PORT),
            "ExitNodes": "{ru}",
        },
        init_msg_handler=print_bootstrap_lines,
    )

    print(term.format("\nChecking our endpoint:\n", term.Attr.BOLD))
    socks.set_default_proxy(
        socks.PROXY_TYPE_SOCKS5, "localhost", 7000, True, None, None
    )
    socket.socket = socks.socksocket
    socket.getaddrinfo = getaddrinfo
    try:
        print(term.format(query("https://icanhazip.com"), term.Color.BLUE))
    finally:
        tor_process.kill()  # stops tor


if __name__ == "__main__":
    main()

demo code running

If you are surprised about the getaddrinfo function above, it is just returning the same domain name it received (instead of an IP address). The actual DNS resolution happens over Tor at the proxy level.

Securedrop Worktstation and how can you help

Snowden tweet

A few weeks ago on August 12 Freedom of the Press had one event where we talked with Paul Lewis from The Gurdian about their use of SecureDrop project, and how it helps in doing the investigative journalism work. My dear friend Harlo was the host for the evening. You can watch the event on Youtube.

The second half of the event was a live demo of the new SecureDrop Workstation project.

SecureDrop is an open source whistleblower submission system that media organizations and NGOs can install to securely accept documents from anonymous sources. It was originally created by the late Aaron Swartz and is now managed by Freedom of the Press Foundation. SecureDrop is available in 20 languages.

The current SecureDrop is dependent heavily on air-gapped Tails systems. This means increased security but also means a lot of time in accessing the submissions by the journalists. SecureDrop Workstation is the next generation system coming up to help in reducing this and also provide much smoother user experience without giving up the security.

In simple words, it is a system built on top of the QubesOS, where journalists can access the submissions via a desktop application and can communicate with sources with much ease.

Login window

And the view for the journalists.

journalist view

You can read in detail about the idea and reasoning behind this project in this whitepaper.

At the beginning of this year, we also published the news on the first (for alpha release) security audit. You can directly jump into the full audit report too.

If you follow DEF CON, you may remember the last panel in 2019 where the usage of SecureDrop and the security audit was discussed.

You can also watch the talk at USENIX Enigma 2020 by Jennifer Helsby.

Technologies used, and how can you help?

SecureDrop is a Free Software project built with similar technologies that you all see and use every day. The main server side is written in Python, with a lot of Ansible, and molecule to test. The web application is written in Flask and contains tests written in Pytest. The documentation is written in Sphinx and maintained via ReadTheDocs. Development setup can be created using Docker, and full-scale production vms (for testing) can be created using the Vagrant.

The translations are maintained in the Weblate by the amazing community at Localization Lab.

The SecureDrop Workstation client is written in PyQt. There are many related Python modules in our Github. The packages are reproducible builds, except the RPMS.

The sources and journalists access SecureDrop via Tor Project. In Qubes OS we use both Fedora and Debian VMs.

There are many issues opened in all of these project’s repositories, and by using/testing them, you most probably will be able to find more things to be fixed. There are problems which can be solved with people from different experiences.

We do daily standup at 16:00UTC in this meeting link. Please feel free to join in and say hi.

PrivChat with Tor: 2020-08-28

Tomorrow at 17:00UTC, Tor Project is hosting the next session of PrivChat, titled "The Good, the Bad, and the Ugly of Censorship Circumvention". You can watch it live on Youtube.

PrivChat tomorrow 17:00UTC on youtube

This 2nd edition of PrivChat is about the Good, the Bad and the Ugly that is happening in the front lines of censorship circumvention. Cory Doctorow will be the host for the evening, and the following people will be participating:

  • Felicia Anthonio (Access Now),
  • Vrinda Bhandari (Internet Freedom Foundation ),
  • Cecylia Bocovich (Tor Project ),
  • Arturo Filastò (OONI )

Don't miss your chance to listen to them. You can ask questions via the Youtube chat.

Introducing pyage-rust, a Python module for age encryption

age is a simple, modern and secure file encryption tool, it was designed by @Benjojo12 and @FiloSottile.

An alternative interoperable Rust implementation is available at github.com/str4d/rage

pyage-rust is a Python module for age, this is built on top of the Rust crate. I am not a cryptographer, and I prefer to keep this important thing to the specialists :)

pyage-rust demo

Installation

I have prebuilt wheels for both Linux and Mac, Python 3.7 and Python 3.8.

python3 -m pip install pyage-rust==0.1.0

Please have a look at the API documentation to learn how to use the API.

Building pyage-rust

You will need the nightly rust toolchain (via https://rustup.rs).

python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install requirements-dev.txt
maturin develop && maturin build

Missing items in the current implementation

I am yet to add ways to use ssh keys or alias features, but those will come slowly in the future releases.

Setting up a personal DoH server

DoH is a hot discussion point in both the privacy and DNS people. There are many criticisms, including encryption support of the clients or still trusting a third party. There is an excellent talk from Bert Hubert on this topic.

In this post, we will learn how to set up our own personal DoH server. I am not posting any tips on the IPTABLES rules, you should be able to add those based on what all services you run on the server.

We will use unbound as the recursive DNS server in our setup. In the server, we can easily install it via the OS package management (apt/dnf).

Getting the root name servers' details

We should get a fresh copy of the root name servers' details, and then you can have a cron job every six months to get a fresh copy.

curl --output /etc/unbound/root.hints https://www.internic.net/domain/named.cache

Setting up unbound

I am using the following configuration

# Unbound configuration file for Debian.
#
# See the unbound.conf(5) man page.
#
# See /usr/share/doc/unbound/examples/unbound.conf for a commented
# reference config file.
#
# The following line includes additional configuration files from the
# /etc/unbound/unbound.conf.d directory.
include: "/etc/unbound/unbound.conf.d/*.conf"
server:
        root-hints: "/etc/unbound/root.hints"
        interface: 127.0.0.1
        access-control: 0.0.0.0/0 allow
        use-syslog: yes

Then you can get the configuration checked via the unbound-checkconf command.

# unbound-checkconf
unbound-checkconf: no errors in /etc/unbound/unbound.conf
systemctl enable unbound
systemctl start unbound  

Setup Nginx along with certbot

Setup Nginx and use the certbot tool to get the SSL certificate. Here is the configuration I am using, the main point to notice the upstream section.

upstream dns-backend {
    server 127.0.0.1:8053;
    keepalive 30;
}
server {
    listen 80;
    listen [::]:80;

    location /.well-known/acme-challenge {
        alias /var/www/leftover;
    }
    root /var/www/html;

    server_name yourdomain;
    return 301 https://$host;
}

server {
    listen 443 ssl http2;

    # if you wish, you can use the below line for listen instead
    # which enables HTTP/2
    # requires nginx version >= 1.9.5
    # listen 443 ssl http2;

    server_name yourdomain;
    index index.html;

    ssl_certificate /etc/letsencrypt/live/yourdomain/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain/privkey.pem;

    # Turn on OCSP stapling as recommended at
    # https://community.letsencrypt.org/t/integration-guide/13123
    # requires nginx version >= 1.3.7
    ssl_stapling on;
    ssl_stapling_verify on;

    # modern configuration. tweak to your needs.
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
    ssl_prefer_server_ciphers on;


    # Uncomment this line only after testing in browsers,
    # as it commits you to continuing to serve your site over HTTPS
    # in future
    # add_header Strict-Transport-Security "max-age=31536000";

    rewrite ^(.*).php https://www.youtube.com/watch?v=dQw4w9WgXcQ last;
    # maintain the .well-known directory alias for renewals
    location /.well-known {

        alias /var/www/yourdomain/.well-known;
    }

        location / {
            root   /var/www/html;
            index  index.html;
        }
    location /dns-query {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_set_header Connection "";
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_redirect off;
        proxy_set_header        X-Forwarded-Proto $scheme;
        proxy_read_timeout 86400;
        proxy_pass http://dns-backend/dns-query;
    }

}

Then start the Nginx server.

Setting up the DoH server

You will have to setup golang as we will have to compile the project. First step is always the git clone :)

git clone https://github.com/m13253/dns-over-https.git
cd dns-over-https
make
make install 

As next step we will modify the configuration file of the dns-over-https tool at /etc/dns-over-https/doh-server.conf. Now, there are many different configuration options available, I am using only a small part of it. Check the github repo for an uptodate commented configuration example.

listen = [
    "127.0.0.1:8053",
    "[::1]:8053"
]
local_addr = ""
cert = ""
key = ""
path = "/dns-query"
upstream = [
        "udp:127.0.0.1:53"
]
timeout = 10
tries = 3
verbose = false
log_guessed_client_ip = false

We are asking the tool to talk to the unbound running on the same server. Next, we can start and enable the service. Remember to check the logs for any errors due to typos.

systemctl restart doh-server
systemctl enable doh-server

Testing the setup

You can test the setup by making a call using curl command and using Python's json module to give you a readable output.

curl -s "https://yourdomain/dns-query?name=dgplug.org.org&type=A" | python3 -m json.tool

You can now use the server in the General -> Network Settings section of Firefox.

setting up firefox

Access Riseup email over Onion service

Email service (📧) is another excellent example that can be accessed safely over Tor Onion services. This is in particular useful in places where people in power do not like their citizens accessing privacy-focused email providers. I know, you must be thinking about your own country, but no worries, we all are in the same place :)

In this post, I will explain how one can access their emails via IMAP, and send using SMTP over onion services. I am taking Riseup as an example because they provide this option to the users, and also because I personally use their service. This document assumes that you already have tor service running on your system.

Riseup Tor Onion services address

Riseup and Tor

Riseup has a page listing all the Onion service addresses they provide. You can also verify the signed address from the signed file in the same page. For the rest of this post, we will use 5gdvpfoh6kb2iqbizb37lzk2ddzrwa47m6rpdueg2m656fovmbhoptqd.onion as the address for both IMAP and SMTP services. In the normal Internet, those are imap.riseup.net and smtp.riseup.net.

Getting the SSL certificate for the service for verification

Riseup uses Let's Encrypt for the SSL certificates. We have to pin them for the above-mentioned onion address so that we can use them in our system.

mkdir -p ~/.cert
torify openssl s_client -connect 5gdvpfoh6kb2iqbizb37lzk2ddzrwa47m6rpdueg2m656fovmbhoptqd.onion:993 -showcerts 2>&1 < /dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sed -ne '1,/-END CERTIFICATE-/p' > ~/.cert/riseuponion.pem

openssl x509 -in .cert/riseuponion.pem -noout -sha256 -fingerprint
SHA256 Fingerprint=C6:BB:7B:04:97:54:05:65:76:81:4D:56:22:CE:50:6C:91:53:D3:3E:27:95:CC:C9:B8:B7:19:A5:E9:31:7D:15

The first command fetches the SSL certification from the given onion addresses, and stores it in the ~/.cert/riseuponion.pem file. The second command gives us the fingerprint for the same. You can verify these values by running the command against imap.riseup.net:993 and comparing the values.

By the way, remember that these values will change every 3 months (like any other Let's Encrypt certificate).

Setting up mbsync for IMAP access of the emails

I prefer to use the mbsync command from the imap package. The following the configuration for the same.

IMAPAccount riseup
# Address to connect to
Host 5gdvpfoh6kb2iqbizb37lzk2ddzrwa47m6rpdueg2m656fovmbhoptqd.onion
Port 993
User <my full email address without angle brakets>
PassCmd "/usr/bin/pass riseup"
# Use SSL
AuthMechs PLAIN
SSLType IMAPS
SSLVersions TLSv1 TLSv1.1 TLSv1.2
CertificateFile /home/kdas/.cert/riseuponion.pem

IMAPStore riseup-remote
Account riseup

MaildirStore riseup-local
# The trailing "/" is important
Path ~/.imap-mail/riseup/
Inbox ~/.imap-mail/riseup/Inbox

Channel riseup
Master :riseup-remote:
Slave :riseup-local:
# Exclude certain things
# Or include everything
Patterns *
# Automatically create missing mailboxes, both locally and on the server
Create Both
# Save the synchronization state files in the relevant directory
SyncState *

You can notice that I am using the CertificateFile key to point to the certificate we downloaded previously.

Now, I can sync the emails using the torify along with the regular mbsync command.

torify mbsync -a riseup 

Setting up msmtp to send emails

The following is my msmtp configuration

# riseup
account riseup
host 5gdvpfoh6kb2iqbizb37lzk2ddzrwa47m6rpdueg2m656fovmbhoptqd.onion
port 587
auth on
proxy_host 127.0.0.1
proxy_port 9050
tls on
tls_fingerprint C6:BB:7B:04:97:54:05:65:76:81:4D:56:22:CE:50:6C:91:53:D3:3E:27:95:CC:C9:B8:B7:19:A5:E9:31:7D:15
user <my full email address without angle brakets>
passwordeval "/usr/bin/pass riseup"
maildomain riseup.net
from <my full email address without angle brakets>

One thing to notice that msmtp actually allows us to directly mention the tor socks proxy details in the configuration file. And then in my mutt configuration, I mentioned

set sendmail="/usr/bin/msmtp -a riseup"

Onion service v2 deprecation timeline

On Monday June 15, the developers of the Tor Project announced the initial plan for the deprecation of Onion services v2. You can identify v2 addresses easily as they are only 16 character long, where as the v3 addresses are 56 character long.

Why?

The v2 services used RSA1024, where as v3 uses ed25519, means better cryptography. We can also have offline keys for the onion service. You can read all other benefits in the v3 spec.

Timeline

According to the email to the list, the following the current timeline:

  • On 2020-09-15 with 0.4.4.x release Tor will start informing v2 onion service operators that v2 is deprecated.
  • On 2021-07-15 with 0.4.6.x release Tor will stop supporting v2 onion addresses, and all related source code will be removed.
  • On 2021-10-15 there will be a new stable version release which will disable using v2 onion services on the Tor network.

How can you prepare as an Onion service provider?

If you are using/providing any v2 onion service, you should enable v3 service for the same service. This will help you to test your v3 configuration while keeping the v2 on, and then you can retire your v2 address. If you need help in setting authenticated v3 service, you can follow this blog post. I wrote another post which explains how can you generate the keys using Python cryptography module.

Read the full announcement in the list archive.

Curious case of image based email signatures and Kmail

We already talk about why HTML emails are bad, but that is the default in most of the email service providers. HTML emails means some code is getting executed and rendered on your system. Maybe on a browser, or on a desktop email client.

Many people do not use any HTML tag in their emails, but then they have fancy email signatures. A lot of time they have fancy image generated on a website and they use the generated image URL as signature. This means every time someone opened the email (with HTML rendering on) the third party company will be able to track those usages. We don't know what happens next to all of these tracking information.

Last week I was trying out various desktop email clients available on Fedora 32, and noticed a strange thing on Kmail/Kontact, the email client of KDE. I run my Unoon tool to monitor all processes for any network connection on system. And, suddenly it popped a notification about Kmail connecting to mysignatures.io. I was surprised for a second, as Kmail also disables loading of any remote resource (say images) and does not render HTML email by default.

Screenshot of Unoon

Then I figured that if I click on reply button (the compose window), it fetches the image from the signature (or any <img> tag). This means the HTML is getting rendered somehow, even if it is not showing to the user. After I filed a bug upstream, I also pinged my friend ADE. He helped to reproduce it and also find more details on the same. Now, we are waiting for a fix. I hope this does not involve JS execution during that internal rendering.

I also checked for same behavior in Thunderbid, and it does not render in similar way.

Onion location and Onion names in Tor Browser 9.5

Yesterday the Tor Browser 9.5 was released. I am excited about this release for some user-focused updates.

Onion-Location header

If your webserver provides this one extra header Onion-Location, the Tor Browser will ask the user if they want to visit the onion site itself. The user can even mark to visit every such onion site by default. See it in action here.

To enable this, in Apache, you need a configuration line like below for your website’s configuration.

Onion location demo

Header set Onion-Location "http://your-onion-address.onion%{REQUEST_URI}s"

Remember to enable rewrite module.

For nginx, add the following in your server configuration.

add_header Onion-Location http://<your-onion-address>.onion$request_uri;

URL which we can remember aka onion names

This is the first proof of concept built along with Freedom of the Press Foundation (yes, my team) and HTTPS Everywhere to help people to use simple names for onion addresses. For example, below, you can see that I typed theintercept.securedrop.tor.onion on the browser, and that took us to The Intercept’s SecureDrop address.

Onion name