Disclaimer: This library has not been audited by a professional cryptographer. There may be mistakes that can make it vulnerable. Do not use this in production without auditing it.

Go recently got a new plugin standard library package that allows code to be loaded at runtime. This is a great feature, but there is no way to defend against fake plugins. To help me learn about code signing schemes, I created a library, signedplugins, to verify signatures of Go plugins.

Want to cut to the chase? The full source code for this is available on Github.

Why would I need a digital signature?

A digital signature provides cryptographic proof that the holder of a private key endorsed a file. It does not guarantee that the file is not malicious, but it prevents forgery.

Not that kind of signature.

A useful example is the signing of mobile apps by developers. When you update the Facebook app from the Play Store, Android verifies that the signature of the update APK is from the same key that signed the installed Facebook app APK. This prevents a malicious app from masquerading as the Facebook app. The signature is the hash digest of the APK, signed with the app developer’s private key.

To learn more about Android app signing, see the APK verification document.

The digital signature scheme

Since elliptic-curve cryptography is the new hotness, powering Bitcoin and other cryptocurrencies, I decided to use it to sign the plugins. The scheme can be summarized as:

Take the SHA3–256 hash of the plugin Take the ECDSA signature of the SHA3–256 hash Take the ECDSA public key of the author Verify that the hash of the file matches the hash signed by the author If the file hash matches, load the plugin, otherwise reject it

Implementation

The algorithm described above will verify files, but it is vulnerable to race conditions. Our implementation must prevent an attacker from replacing the plugin after the hash check, but before loading the plugin from disk. Since Go’s plugin API only supports loading plugins from a file, an OS-level file lock is needed. The flock library by theckman provides an easy to use API for OS-level file locking.

To summarize, the implementation must:

Lock the plugin file Hash it with SHA3-256 Verify that the signature matches the file hash If the hash matches, load the plugin Unlock the plugin file

The signature verification code is pretty straightforward. It takes the SHA3–256 hash of a byte slice of data passed to it, and ensures that the hash is signed with the given public key.

The final piece is a simple wrapper around Go’s plugin.Open function. It locks the plugin to prevent other processes from interfering with it and reads its contents into memory. It then verifies the contents against the signature given to the function. If everything checks out, it will load the plugin from disk and release the lock.

More detailed documentation of the library is available on GoDoc.

Example

A library is useless without examples. For demonstration purposes, here is a simple plugin that prints “Hello, world” to the console.

Since this is a demo, everything can be done in memory, but a real program would read the signature and public key from disk or the internet.

As seen above, plugins will only be loaded if the signature verifies. To see this in action, first build the plugin.

go build -buildmode=plugin exampleplugin.go

Next, run the example code and look at the output.

go run loadandverify.go

Report issues

I am a not a professional cryptographer, and the code may contain mistakes. If you notice anything, please feel free to leave an issue on the Github.

Liked this post and want to leave a tip?

BTC: 3AubYUbbzEZ1ETnFWVjBHzXio47cdVERSj

ETH: 0x2D687E2234c2e9A7cC9Ef3CCD1eD4AC249EA6aCd