1
0
Fork 1
mirror of https://github.com/NixOS/nixpkgs.git synced 2024-12-25 03:17:13 +00:00
nixpkgs/nixos/tests/curl-impersonate.nix

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

203 lines
6.1 KiB
Nix
Raw Normal View History

2023-07-21 19:37:48 +01:00
/*
Test suite for curl-impersonate
Abstract:
Uses the test suite from the curl-impersonate source repo which:
1. Performs requests with libcurl and captures the TLS client-hello
packets with tcpdump to compare against known-good signatures
2. Spins up an nghttpd2 server to test client HTTP/2 headers against
known-good headers
See https://github.com/lwthiker/curl-impersonate/tree/main/tests/signatures
for details.
Notes:
- We need to have our own web server running because the tests expect to be able
to hit domains like wikipedia.org and the sandbox has no internet
- We need to be able to do (verifying) TLS handshakes without internet access.
We do that by creating a trusted CA and issuing a cert that includes
all of the test domains as subject-alternative names and then spoofs the
hostnames in /etc/hosts.
*/
import ./make-test-python.nix (
{ pkgs, lib, ... }:
let
# Update with domains in TestImpersonate.TEST_URLS if needed from:
# https://github.com/lwthiker/curl-impersonate/blob/main/tests/test_impersonate.py
domains = [
"www.wikimedia.org"
"www.wikipedia.org"
"www.mozilla.org"
"www.apache.org"
"www.kernel.org"
"git-scm.com"
];
2023-07-21 19:37:48 +01:00
tls-certs =
let
# Configure CA with X.509 v3 extensions that would be trusted by curl
ca-cert-conf = pkgs.writeText "curl-impersonate-ca.cnf" ''
basicConstraints = critical, CA:TRUE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
keyUsage = critical, cRLSign, digitalSignature, keyCertSign
'';
2023-07-21 19:37:48 +01:00
# Configure leaf certificate with X.509 v3 extensions that would be trusted
# by curl and set subject-alternative names for test domains
tls-cert-conf = pkgs.writeText "curl-impersonate-tls.cnf" ''
basicConstraints = critical, CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment, keyAgreement
extendedKeyUsage = critical, serverAuth
subjectAltName = @alt_names
2023-07-21 19:37:48 +01:00
[alt_names]
${lib.concatStringsSep "\n" (lib.imap0 (idx: domain: "DNS.${toString idx} = ${domain}") domains)}
'';
in
pkgs.runCommand "curl-impersonate-test-certs"
{
nativeBuildInputs = [ pkgs.openssl ];
}
''
# create CA certificate and key
openssl req -newkey rsa:4096 -keyout ca-key.pem -out ca-csr.pem -nodes -subj '/CN=curl-impersonate-ca.nixos.test'
openssl x509 -req -sha512 -in ca-csr.pem -key ca-key.pem -out ca.pem -extfile ${ca-cert-conf} -days 36500
openssl x509 -in ca.pem -text
2023-07-21 19:37:48 +01:00
# create server certificate and key
openssl req -newkey rsa:4096 -keyout key.pem -out csr.pem -nodes -subj '/CN=curl-impersonate.nixos.test'
openssl x509 -req -sha512 -in csr.pem -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile ${tls-cert-conf} -days 36500
openssl x509 -in cert.pem -text
2023-07-21 19:37:48 +01:00
# output CA cert and server cert and key
mkdir -p $out
cp key.pem cert.pem ca.pem $out
'';
2023-07-21 19:37:48 +01:00
# Test script
curl-impersonate-test =
let
# Build miniature libcurl client used by test driver
minicurl =
pkgs.runCommandCC "minicurl"
{
buildInputs = [ pkgs.curl ];
}
''
mkdir -p $out/bin
$CC -Wall -Werror -o $out/bin/minicurl ${pkgs.curl-impersonate.src}/tests/minicurl.c `curl-config --libs`
'';
in
pkgs.writeShellScript "curl-impersonate-test" ''
set -euxo pipefail
2023-07-21 19:37:48 +01:00
# Test driver requirements
export PATH="${
with pkgs;
lib.makeBinPath [
bash
2023-07-21 19:37:48 +01:00
coreutils
python3Packages.pytest
nghttp2
2024-08-05 07:06:05 +01:00
tcpdump
2023-07-21 19:37:48 +01:00
]
}"
export PYTHONPATH="${
with pkgs.python3Packages;
makePythonPath [
pyyaml
2023-07-21 19:37:48 +01:00
pytest-asyncio
dpkt
2023-07-21 19:37:48 +01:00
ts1-signatures
]
}"
2023-07-21 19:37:48 +01:00
# Prepare test root prefix
mkdir -p usr/{bin,lib}
cp -rs ${pkgs.curl-impersonate}/* ${minicurl}/* usr/
2023-07-21 19:37:48 +01:00
cp -r ${pkgs.curl-impersonate.src}/tests ./
2023-07-21 19:37:48 +01:00
# Run tests
cd tests
2023-07-21 19:37:48 +01:00
pytest . --install-dir ../usr --capture-interface eth1
'';
in
2023-07-21 19:37:48 +01:00
{
name = "curl-impersonate";
2023-07-21 19:37:48 +01:00
meta = with lib.maintainers; {
maintainers = [ ];
};
nodes = {
web =
2023-07-21 19:37:48 +01:00
{
nodes,
pkgs,
lib,
config,
...
}:
{
2023-07-21 19:37:48 +01:00
networking.firewall.allowedTCPPorts = [
80
443
2023-07-21 19:37:48 +01:00
];
2023-07-21 19:37:48 +01:00
services = {
nginx = {
enable = true;
virtualHosts."curl-impersonate.nixos.test" = {
default = true;
addSSL = true;
sslCertificate = "${tls-certs}/cert.pem";
sslCertificateKey = "${tls-certs}/key.pem";
};
};
};
};
2023-07-21 19:37:48 +01:00
curl =
{
nodes,
pkgs,
lib,
config,
...
}:
{
2023-07-21 19:37:48 +01:00
networking.extraHosts = lib.concatStringsSep "\n" (
map (domain: "${nodes.web.networking.primaryIPAddress} ${domain}") domains
);
2023-07-21 19:37:48 +01:00
security.pki.certificateFiles = [ "${tls-certs}/ca.pem" ];
};
2023-07-21 19:37:48 +01:00
};
testScript =
{ nodes, ... }:
''
2023-07-21 19:37:48 +01:00
start_all()
2023-07-21 19:37:48 +01:00
with subtest("Wait for network"):
web.systemctl("start network-online.target")
curl.systemctl("start network-online.target")
2023-07-21 19:37:48 +01:00
web.wait_for_unit("network-online.target")
curl.wait_for_unit("network-online.target")
2023-07-21 19:37:48 +01:00
with subtest("Wait for web server"):
web.wait_for_unit("nginx.service")
web.wait_for_open_port(443)
2023-07-21 19:37:48 +01:00
with subtest("Run curl-impersonate tests"):
curl.succeed("${curl-impersonate-test}")
'';
}
)