Skip navigation

Duo Security is now a part of Cisco

About Cisco

Android Emulator Custom DNS/TLS

Nick Mooney March 6th, 2019 (Last Updated: March 6th, 2019)

01. Context

I talked a bit ago about using mkcert to generate locally-trusted HTTPS certs. This continues to work great! This past week, I was hoping to use those same certs in the Android emulator. You will need to do a couple things in order to get your Android app talking to and trusting your development setup.

02. Setup

DNS

In this example, I am running a local instance of a service, and I would like the hostname duotest.service to resolve to 192.168.125.10 (my local machine). Note that I’m using my Wi-Fi IP here instead of localhost, since I need both the Android emulator and my laptop to be able to connect to it. There is some fancy split horizon stuff you could do here to only route locally, but it’s far more complicated than this setup.

dnsmasq

I’m going to use dnsmasq as a caching DNS resolver that also respects entries in my /etc/hosts. To set this up:

  1. Edit /etc/hosts on my development machine to include the line duotest.service 192.168.125.10 (change this when your IP changes)
  2. Install dnsmasq: brew install dnsmasq
  3. Edit /usr/local/etc/dnsmasq.conf (see below)
  4. Start dnsmasq: sudo brew services start dnsmasq

I want dnsmasq to listen on my Wi-Fi IP, but not localhost (since dnscrypt-proxy is already listening there). Here are the options I used in dnsmasq.conf:

interface=en0
except-interface=lo0 # don't listen on localhost
no-dhcp-interface=en0 # don't support DHCP
bind-interfaces # don't bind to all interfaces

After starting the service, you should be able to resolve things from your /etc/hosts:

nmooney-22210:~ nmooney$ dig +short @192.168.125.10 duotest.service A
192.168.125.10

When you edit your hosts file, restart dnsmasq with sudo brew services restart dnsmasq.

Starting the Android emulator with custom DNS

I have an AVD named “Nexus 5X”. You can no longer specify custom DNS servers or command line options from within Android Studio, but you can use the command line emulator tool to start an Android emulator with custom DNS servers:

nmooney-22210:~ nmooney$ ~/Library/Android/sdk/tools/emulator -avd Nexus_5X -dns-server 192.168.125.10

Note that spaces are replaced with underscores on the command line.

Once you’ve done this and the emulator has booted, you should be able to verify that Android is using your resolver. To test this in my case, I navigated to https://duotest.service in the Chrome browser within Android. I got a certificate error since I haven’t added my CA yet, but I was able to see that I was being served the mkcert-generated certificate, which means resolution is succeeding.

SSL Certificates

First, you’ll need to install your local CA on the emulated Android device. If you’ve followed the mkcert steps, you should be able to run the following to find the location of your cert files:

nmooney-22210:~ nmooney$ mkcert -CAROOT
/Users/nmooney/Library/Application Support/mkcert
nmooney-22210:~ nmooney$ ls "$(mkcert -CAROOT)"
rootCA-key.pem  rootCA.pem

The rootCA.pem file is what you’ll need to give to the Android emulator.

Installing the CA PEM on Android

  1. Push the CA file to the device: adb push rootCA.pem /sdcard/Download/
  2. On the device, navigate to Settings -> Network & internet -> Wi-Fi -> Wi-Fi preferences -> Advanced -> Install certificates
  3. Choose the Downloads folder and click on rootCA.pem
  4. Enter the device PIN, give your CA a name, and hit “OK”

The device now trusts your mkcert CA, and you should be able to confirm this in Chrome by navigating to an HTTPS cite with a mkcert certificate attached to it. At this point in my testing, I was able to visit https://duotest.service/ in Chrome successfully.

Configuring your app to use user CAs

Duo Mobile already has this enabled by default, but in case you’re working on something else, you’ll need to add a <certificate> entry to res/xml/network_security_config.xml. A minimal example can be found in Duo Mobile:


<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
	<debug-overrides>
		<trust-anchors>
			<certificates src="user" />
		</trust-anchors>
	</debug-overrides>
</network-security-config>

This will trust user CAs in debug mode only. You will also need to reference this in your app’s AndroidManifest.xml:


<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
	<application android:networkSecurityConfig="@xml/network_security_config"
		... >
		...
	</application>
</manifest>

03. Sources