the Chromium logo

The Chromium Projects

Playing with QUIC

Build the QUIC client and server

A sample server and client implementation are provided in Chromium, and several more are provided as part of QUICHE. To use these you should first have checked out the Chromium source, and then build the binaries:

ninja -C out/Debug quic_server quic_client

Binary targets include:

Prep test data from www.example.org

The server implementations support serving data cached on disk. The data is in the format written by wget -p --save-headers.

To download a copy of www.example.org:

mkdir /tmp/quic-data
cd /tmp/quic-data
wget -p --save-headers https://www.example.org

Manually edit index.html and adjust the headers:

Generate certificates

In order to run the server, you will need a valid certificate, and a private key in pkcs8 format. If you don't have one, there are scripts you can use to generate them:

cd net/tools/quic/certs
./generate-certs.sh
cd -

These generate a certificate and key for www.example.org in net/tools/quic/certs/out, good for only three days.

In addition to the server's certificate and public key, this script will also generate a CA certificate (net/tools/quic/certs/out/2048-sha256-root.pem) which you will need to add to your OS's root certificate store in order for it to be trusted during certificate validation. For doing this on Linux, please see these instructions. This will allow quic_client to verify the certificate correctly.

Note that Chrome/Chromium (the browser) does not allow custom CAs for QUIC, so in addition to adding the root certificate to the certificate store, you'll need to pass in --ignore-certificate-errors-spki-list=.. with the certificate's SPKI to allow Chrome/Chromium to accept your custom certificate as valid.

You can generate the SPKI with:

openssl x509 -noout -pubkey < net/tools/quic/certs/out/leaf_cert.pem | \
    openssl rsa -pubin -outform der | \
    openssl dgst -sha256 -binary | \
    openssl enc -base64

Run the QUIC server and client with cached data

Run the quic_server, pointing to the cached www.example.org content and cert/key generated above:

./out/Debug/quic_server \
  --quic_response_cache_dir=/tmp/quic-data/www.example.org \
  --certificate_file=net/tools/quic/certs/out/leaf_cert.pem \
  --key_file=net/tools/quic/certs/out/leaf_cert.pkcs8

And you should be able to successfully request the file over QUIC using quic_client:

./out/Debug/quic_client --host=127.0.0.1 --port=6121 https://www.example.org/

Note that if you let the server's port default to 6121, you must specify the client port because it defaults to 80.

Moreover, if your local machine has multiple loopback addresses (as it would if using both IPv4 and IPv6), you have to pick a specific address.

It remains to be determined whether the latter shortcoming is a bug.

If the server you are connecting to does not have a trusted certificate, use the --disable_certificate_verification flag on the client to disable certificate verification. If the server's certificate is trusted but chains to a user installed CA (e.g. a CA generated by the script mentioned above), use the --allow_unknown_root_cert flag on the client to allow connections where the cert chains to a user installed CA.

note: both the client and server are meant mainly for integration testing: neither is performant at scale!

To test the same download using chrome,

chrome \
  --user-data-dir=/tmp/chrome-profile \
  --no-proxy-server \
  --enable-quic \
  --origin-to-force-quic-on=www.example.org:443 \
  --host-resolver-rules='MAP www.example.org:443 127.0.0.1:6121' \
  https://www.example.org

Note that the server's certificate must be trusted by a default CA for Chrome/Chromium to accept it for QUIC. If you are using a self-signed certificate or a certificate that is signed by a custom CA, you need to use the --ignore-certificate-errors-spki-list command line flag to trust an individual certificate based on its SPKI. It is not possible to trust a custom CA using this flag. If you wish to deploy a MITM proxy that intercepts traffic, you need to block QUIC entirely and intercept TLS instead.

Proxying Requests

To set up proxying with CONNECT:

./out/Default/epoll_quic_server \
    --mode=proxy \
    --connect_proxy_destinations=google.com:443 \
    --certificate_file=net/tools/quic/certs/out/leaf_cert.pem \
    --key_file=net/tools/quic/certs/out/leaf_cert.pkcs8

and, ensuring you've added the root cert to the cert store and put the leaf cert's SPKI in $SPKI,

out/Default/chrome \
    --user-data-dir=/tmp/chrome-profile \
    --host-resolver-rules='MAP www.example.org 127.0.0.1' \
    --proxy-server=quic://www.example.org:6121 \
    --origin-to-force-quic-on=www.example.org:6121 \
    --ignore-certificate-errors \
    --ignore-certificate-errors-spki-list="${SPKI}"

Note that all of --ignore-cerificate-errors, --ignore-certificate-errors-spki-list, and --origin-to-force-quic-on are required, along with the root cert in the cert store, to avoid certificate validation errors.

Troubleshooting

If you run into troubles, try running the server or client with --v=1. It will increase the logging verbosity and the additional logs will often help expose the underlying problem.