Due: Fri, Mar 28, 11:59pm
In this project, you will implement a simplified version of Oblivious DNS over HTTPS (ODoH), which Cloudflare proposed in a PETS '21 paper, and which is currently an experimental RFC.
The motivation for ODoH is that, while DNS-over-HTTPS (DoH) ensures the confidentiality of a DNS request from an eavesdropper, the DNS resolver still learns that a given client IP address is looking up a specific domainname. Although this is a normal expectation, it becomes a privacy concern in a world where clients increasingly rely on a small number of open resolvers; such resolvers are in a position to track the activities of a huge number of Internet users.
In order to ensure that a DNS server does not learn both a client's IP address and the client's query, ODoH relies on two servers: a proxy and a target. Clients end-to-end encrypt their DNS communication with the target, who in turn resolves the query. However, the client sends this query to the proxy, who then forwards it to the target. In this way, the proxy learns the IP address, the target learns the DNS request, but neither learns both.
For this project, you will implement three executables:
The communication between the client and proxy is over HTTPS. Likewise, the communication between the proxy and target is over HTTPS. The client issues its DNS request to a URL of the form:
https://PROXY/dns-query?targethost=TARGET&targetpath=/dns-query
For instance, if the PROXY is at 127.0.0.1:8053 and the TARGET is at 127.0.0.1:8054, the URL would be:
https://127.0.0.1:8053/dns-query?targethost=127.0.0.1:8054&targetpath=/dns-query
In turn, the proxy forwards the query to the URL:
https://TARGET/dns-query
For example:
https://127.0.0.1:8054/dns-query
In our SODoH protocol, the only DNS request that we will support is a combined A/AAAA query -- that is, a query to resolve a domainname to a list of IPv4 and IPv6 addresses. Additionally, we will use JSON as the data exchange format for all queries and replies.
A DNS query has the JSON form:
{
qname: <string>
}
A successful DNS reply has the JSON form:
{
rcode: <int>,
answers: [
<string>
...
]
}
A DNS error reply has the JSON form:
{
rcode: <int>
}
The client hybrid encrypts the DNS query using a randomly generated 256-bit AES key and the target's public RSA key. Specifically, the client sends to the proxy (and the proxy forwards to the target), the following JSON blob:
{
wrappedKey: <The Base64 encoding of the RSA-OAEP encryption of the random AES-256 key>
ciphertext: <The Base64 encoding of the AES256-GCM encryption of the JSON DNS query>
}
In turn, the target uses its RSA private key to unwrap the AES-256 key, and uses this AES key to decrypt the DNS query. The target performs the DNS resolution, forms the DNS reply, and encrypts the DNS reply with the same AES-256 key. Specifically, the target returns the following JSON reply to the proxy, which then forwards it to the client:
{
ciphertext: <The Base64 encoding of the AES256-GCM encryption of the JSON DNS reply>
}
If the target receives a well-formed query, the DNS reply can have one of the following rcodes:
The proxy and target return the following HTTP status codes. Note that if the proxy successfully makes an HTTPS request to the target, then the proxy copies the status code of the target's response for its own response to the client.
client - send a simplified Oblivious DNS (ODoH) request.
client [options] QNAME
The query name (domainname) to resolve.
The certificate file for the CA that signed the TLS certificate for the proxy.
Default: ca.crt
The certificate file for the target. The client uses the certificate's public key to hybrid encrypt the DNS request.
Default: target.crt
The proxy host. This has the form host[:port], where host can be either a domainname or an IP address.
Default: 127.0.0.1:8053
The target host. This has the form host[:port], where host can be either a domainname or an IP address.
Default: 127.0.0.1:8054
Display this usage statement and exit.
./client -ca-cert assets/ca.crt -target-cert assets/target.crt www.cs.wm.edu
proxy - proxy server for Oblivious DNS (ODoH)
proxy [options] [HOST]:PORT
A "host:port" address that the proxy listens on for HTTPS requests.
The TLS certificate file for the proxy.
Default: proxy.crt
The TLS private key for the proxy.
Default: proxy.key
The certificate file for the CA that signed the TLS certificate for the target.
Default: ca.crt
Display this usage statement and exit.
./proxy -ca-cert assets/ca.crt -cert assets/proxy.crt -key assets/proxy.key 127.0.0.1:8053
target - target server for Oblivious DNS (ODoH)
target [options] [HOST]:PORT
A "host:port" address that the target listens on for HTTPS requests.
The TLS certificate file for the target.
Default: target.crt
The TLS private key for the target.
Default: target.key
Display this usage statement and exit.
./target -cert assets/target.crt -key assets/target.key 127.0.0.1:8054
To help get started, please use the following sodoh.zip skeleton module.
Submit your project as a zip file via gradescope. Your project must include a Makefile that builds three executables: client, proxy, and target. Please refer to the instructions for submitting an assignment for details on how to login to gradescope and properly zip your project.
./instructor/target -cert assets/target.crt -key assets/target.key 127.0.0.1:8054
./instructor/proxy -ca-cert assets/ca.crt -cert assets/proxy.crt -key assets/proxy.key 127.0.0.1:8053
./client -ca-cert assets/ca.crt -target-cert assets/target.crt www.cs.wm.edu
(out)128.239.2.143
echo $?
(out)0
./instructor/target -cert assets/target.crt -key assets/target.key 127.0.0.1:8054
./instructor/proxy -ca-cert assets/ca.crt -cert assets/proxy.crt -key assets/proxy.key 127.0.0.1:8053
./client -ca-cert assets/ca.crt -target-cert assets/target.crt zzz.cs.wm.edu
(out)Non-Existent Domain
echo $?
(out)1
The client needs to output to stdout a single line that contains either Non-Existent Domain or NXDOMAIN. The error message may contain other text, if you'd like. The character case does not matter. The client should also exit with a non-zero exit status.
./instructor/target -cert assets/target.crt -key assets/target.key 127.0.0.1:8054
./proxy -ca-cert assets/ca.crt -cert assets/proxy.crt -key assets/proxy.key 127.0.0.1:8053
./instructor/client -ca-cert assets/ca.crt -target-cert assets/target.crt www.wm.edu
(out)108.138.64.11
(out)108.138.64.88
(out)108.138.64.78
(out)108.138.64.106
echo $?
(out)0
Note: It's OK if the list of IP addresses is slightly different (e.g., includes IPv6 addresses).
./instructor/target -cert assets/target.crt -key assets/target.key 127.0.0.1:8064
./proxy -ca-cert assets/ca.crt -cert assets/proxy.crt -key assets/proxy.key 127.0.0.1:8063
./instructor/client -ca-cert assets/ca.crt -target-cert assets/target.crt -proxy 127.0.0.1:8063 -target 127.0.0.1:8064 www.wm.edu
(out)108.138.64.11
(out)108.138.64.88
(out)108.138.64.78
(out)108.138.64.106
echo $?
(out)0
Note: It's OK if the list of IP addresses is slightly different (e.g., includes IPv6 addresses).
./instructor/target -cert assets/target.crt -key assets/target.key 127.0.0.1:8054
./proxy -ca-cert assets/ca.crt -cert assets/proxy.crt -key assets/proxy.key 127.0.0.1:8053
./instructor/client -ca-cert assets/ca.crt -target-cert assets/target.crt -target 127.0.0.1:8067 www.wm.edu
(out)HTTP status error: 502
./target -cert assets/target.crt -key assets/target.key 127.0.0.1:8054
./instructor/proxy -ca-cert assets/ca.crt -cert assets/proxy.crt -key assets/proxy.key 127.0.0.1:8053
./instructor/client -ca-cert assets/ca.crt -target-cert assets/target.crt www.wm.edu
(out)108.138.64.11
(out)108.138.64.88
(out)108.138.64.78
(out)108.138.64.106
echo $?
(out)0
./target -cert assets/target.crt -key assets/target.key 127.0.0.1:8054
./instructor/proxy -ca-cert assets/ca.crt -cert assets/proxy.crt -key assets/proxy.key 127.0.0.1:8053
./instructor/client -ca-cert assets/ca.crt -target-cert assets/target.crt www.wm.edux
(out)DNS returned rcode 1 (Non-Existent Domain)
echo $?
(out)1