diff --git a/articles/2024-08-21-OpenVPN-and-MirageVPN.md b/articles/2024-08-21-OpenVPN-and-MirageVPN.md index 2888d71..0952511 100644 --- a/articles/2024-08-21-OpenVPN-and-MirageVPN.md +++ b/articles/2024-08-21-OpenVPN-and-MirageVPN.md @@ -236,7 +236,7 @@ This work was funded by [the EU NGI Assure Fund through NLnet](https://nlnet.nl/ In my opinion, this shows that funding one open source project can have a positive impact on other open source projects, too. [robur]: https://robur.coop/ -[miragevpn-server]: https://blog.robur.coop/articles/miragevpn-server.html +[miragevpn-server]: miragevpn-server.html [contact]: https://reyn.ir/contact.html [^openvpn-tls]: This is not always the case. It is possible to use static shared secret keys, but it is mostly considered deprecated. diff --git a/articles/miragevpn-testing.md b/articles/miragevpn-testing.md new file mode 100644 index 0000000..4aeff30 --- /dev/null +++ b/articles/miragevpn-testing.md @@ -0,0 +1,54 @@ +--- +date: 2024-06-26 +title: Testing MirageVPN against OpenVPN™ +description: Some notes about how we test MirageVPN against OpenVPN™ +tags: + - OCaml + - MirageOS + - cryptography + - security + - testing + - vpn +author: + name: Reynir Björnsson + email: reynir@reynir.dk + link: https://reyn.ir/ +--- + +As our last milestone for the [EU NGI Assure](https://www.assure.ngi.eu/) funded MirageVPN project (for now) we have been working on testing MirageVPN, our OpenVPN™-compatible VPN implementation against the upstream OpenVPN™. +During the development we have conducted many manual tests. +However, this scales poorly and it is easy to forget testing certain cases. +Therefore, we designed and implemented interoperability testing, driving the C implementation on the one side, and our OCaml implementation on the other side. The input for such a test is a configuration file that both implementations can use. +Thus we test establishment of the tunnel as well as the tunnel itself. + +While conducting the tests, our instrumented binaries expose code coverage information. We use that to guide ourselves which other configurations are worth testing. Our goal is to achieve a high code coverage rate while using a small amount of different configurations. These interoperability tests are running fast enough, so they are executed on each commit by CI. + +A nice property of this test setup is that it runs with an unmodified OpenVPN binary. +This means we can use an off-the-shelf OpenVPN binary from the package repository and does not entail further maintenance of an OpenVPN fork. +Testing against a future version of OpenVPN becomes trivial. +We do not just test a single part of our implementation but achieve an end-to-end test. +The same configuration files are used for both our implementation and the C implementation, and each configuration is used twice, once our implementation acts as the client, once as the server. + +We added a flag to our client and our [recently finished server](miragevpn-server) applications, `--test`, which make them to exit once a tunnel is established and an ICMP echo request from the client has been replied to by the server. +Our client and server can be run without a tun device which otherwise would require elevated privileges. +Unfortunately, OpenVPN requires privileges to at least configure a tun device. +Our MirageVPN implementation does IP packet parsing in userspace. +We test our protocol implementation, not the entire unikernel - but the unikernel code is a tiny layer on top of the purely functional protocol implementation. + +We explored unit testing the packet decoding and decryption with our implementation and the C implementation. +Specifically, we encountered a packet whose message authentication code (MAC) was deemed invalid by the C implementation. +It helped us discover the MAC computation was correct but the packet encoding was truncated - both implementations agreed that the MAC was bad. +The test was very tedious to write and would not easily scale to cover a large portion of the code. +If of interest, take a look into our [modifications to OpenVPN](https://github.com/reynir/openvpn/tree/badmac-test) and [modifications to MirageVPN](https://github.com/robur-coop/miragevpn/tree/badmac-test). + +The end-to-end testing is in addition to our unit tests and fuzz testing; and to our [benchmarking](miragevpn-performance.html) binary. + +Our results are that with 4 configurations we achieve above 75% code coverage in MirageVPN. +While investigating the code coverage results, we found various pieces of code that were never executed, and we were able to remove them. +Code that does not exist is bug-free :D +With these tests in place future maintenance is less daunting as they will help us guard us from breaking the code. + +At the moment we do not exercise the error paths very well in the code. +This is much less straightforward to test in this manner, and is important future work. +We plan to develop a client and server that injects faults at various stages of the protocol to test these error paths. +OpenVPN built with debugging enabled also comes with a `--gremlin` mode that injects faults, and would be interesting to investigate.