Tyler Nichols

Application Security Engineer

If you’re reading this tutorial, I’m going to assume you have a very specific goal in mind: get OpenVPN running on a Raspberry Pi behind an Ubuntu Server router using iptables as your firewall.

Other than firewall rules, the OpenVPN documentation is relatively comprehensive and you should look there for specific configuration options and general OpenVPN setup. It’s not particularly difficult to get OpenVPN installed with easy-rsa and configured with sane options following that guide.

This tutorial emphasizes the routing rules required on both the OpenVPN server and the Ubuntu Server router in order to make the VPN server reachable from the public internet so you can connect to it remotely, have your VPN -> LAN traffic routed properly, and have your LAN -> VPN traffic routed properly.

Think of this as a guide to the configuration required outside of OpenVPN itself to get it working behind your router, e.g. when it’s not installed directly on your router.

I’m currently running Raspbian Jessie on my Pis and for the sake of simplicity, you should run Jessie or later as well. Versions of Raspbian earlier than Jessie don’t include OpenVPN in the repositories so it ends up requiring some jankiness like adding backports from the Jessie repositories. It’s just not very clean.

You can find my comprehensive OpenVPN server and client configuration files in this repository.

In this tutorial, we’re going to walk through the simplest possible loadable Linux kernel module and discuss every last component of it. The source is entirely functional and was written on Ubuntu Server 16.04 LTS (kernel version 4.4.0) so please feel free to clone it, modify it, and try your hand at kernel coding. The repo comes complete with instructions on how to compile, load, unload, and watch for log entries from our module in addition to the module source itself.

The Linux kernel maintains a table of pointers that reference various functions made available to user space as a way of invoking privileged kernel functionality from unprivileged user space applications. These functions are collectively known as system calls.

Any legitimate software looking to hook kernel space functions should first consider using existing infrastructure designed for such uses like the Linux kernel tracepoints framework or the Linux security module framework. Rootkits are about the only reasonable application of these techniques, for some value of reasonable.

This code is an unintentional by-product of a project I was on at work. Considering the pedagogical value of such an endeavor, I decided to strip out all the code responsible for hooking the syscall table, distill it down into a single loadable kernel module that can be easily understood on its own, and write it up.

Cryptographic Building Blocks

Any piece of software that performs cryptographic operations or implements complex cryptographic protocols like TLS relies on cryptographic primitives. Cryptographic primitives are, from the perspective of a software developer, atomic cryptographic operations.

Hashing functions (MD5, SHA-1, SHA-256, SHA-512, etc.) are one the most widely known cryptographic primitives. Other examples include symmetric encryption schemes like AES, asymmetric crypto schemes like public key systems, and digital signatures like HMACs.

An effective cryptosystem must ensure three things: confidentiality, integrity, and authenticity. Confidentiality means no one but the intended recipient(s) can make any sense of the data. Integrity means that no one has tampered with the data since it was encrypted. Authenticity means the parties communicating with each other can verify each others’ identity.

A while back, I coded up an example of how to use the libgcrypt C library. Given an input file, an output file, and a passphrase, the application can encrypt or decrypt the input file.

This application is not suitable for production use. It loads the entire file into memory prior to encryption/decryption. A much more efficient implementation would process pieces of the data iteratively.

The source code is pretty well commented but I want to walk through it in this tutorial.