Skip to content
Benedikt Kristinsson edited this page Feb 14, 2015 · 1 revision

The problem with trusting a VPN provider (or anyone at that) is that you have to trust that they are actually doing what they say they are are doing.

Open source is only a half-measure in this, as they could be lying and running something entierly different. They may say that they do not log, and their code shows that, but in reality they may be running software that logs.

I want to know if there is a way to prevent this. I want to try to make a system that can prove to any user that it is indeed running the open source code. I dont know if this is possible, but I have some ideas I want to explore.

Goals

I will be focusing on the domain of a RESTful api and the dynamic languge Python, because that is what lokun-record is and it's easy to work with this idea within those paramters. A dynamic language that isn't compiled makes for a simpler reasonsing, I think.

The end goal is a HTTP GET resource, with a challenge that returns a response that can be verified with a local clone of the code. This should prove the following things

  1. The service provider has the public copies of the source files
  2. These files are correctly describing the services and programs that are running

But I suspect that this is impossible. In that case, I want to come up with a reasoning for why this is impossible that satisfies me.

Ideas that do not work

So far, I've only had bad ideas.

Idea 1

Calculate a hash of all files and a challenge.

  1. The API call GET /proof inputs a parameter challenge.
  2. Concat the contents of all .py files in the source tree.
  3. Aggregate the hash of all of those files and the challange and return it to the user

This doesn't work, as it doesn't proove that the files are actually running, you just need to keep the files on the server and modify your /proof call to use them.

Idea 2

Modify the file to contain the challenge.

As we saw in the example before, if the contents of the files are known beforehand, the server can just keep a copy of the "good" files and modify the proof-call to be evil. This means that the entire contents of the files cannot be known beforehand, which means that the challenge has to be written to the .py file. We would have to add userdata to our source code files. On runtime. Yikes.

This brings forth a whole plethora of potential issues. From a security perspective this soulds like a horrible idea. And what about multithreading?

Handling user input is usually bad enough, but I'm proposing adding user data to a source file. How can we do this safely? I have some ideas that might (or might not) work:

  1. The actual proof would have to be let up to a file/class that only does this. Lets call it proover.py
  2. The file prover.py would contain references to the other files that are part of the hash. That way the user knows what files are included in the hash. Drawback: The user doesn't know that these are the files being run.
  3. The challenge will have to follow a certain format, otherwise it should be denied. For example, maybe it has to be 512-bit long bytestring, Base64 or hex encoded.
  4. The challenge will be added to the bottom of proover.py as a comment.

That means that the algorithm has to work something like this.

  1. The API call GET /proof inputs a parameter challenge.
  2. The challenge is then added to prover.py.
  3. Then prover.py opens all .py files in it's list of files and concats them together.
  4. The hash is calculated and returned to the user.

This satisfies the following requirements:

  1. The response containst the challenge and is verifyable
  2. The response contains the hash of prover.py with the user-supplied challenge.

This does not work because it doesn't proove that prover.py was actually being run. The provider could still keep a "good" copy of the file around, edit that one and calculate a "good" hash, while still running a evil version of it's own software.

Idea 3

What if we:

  1. Insert the challange to the proof seed (prover.py)
  2. Make the seed reference ALL source files in the project and config files.
    • For a RESTlike API written in Python this could include configuration files showing a nginx config listening on tcp/80 or tcp/443 on a specific ip address and uwsgi config running the .py files listed in prover.py.
    • The trust guarantee of this depends on how well made the configuration files are done and will require manual verification (unless you write a tool for each specific service, or a specification for tests like this).

Does that mean that we can proove this?:

  1. The file prover.py has not been modified from the source
    • Because it has the challenge injected into itself, the expected hash is not known to it and thus can't be faked
  2. The good and public version of prover.py is actually being called.
    • Same reasoning as point 1.
  3. None of the files that prover.py references have been modified from the source.
    • If one of the references in prover.py to a verifyble file is altered, the hash of prover.py will be incorrect.
  4. All of the files that prover.py references are the files actually in use
    • The configuration files for the services can be manually checked that they are listening on the expected ip/port and that they are running the same source files as the proven prover.py is referencing.

What if you?:

  1. Shut down the nginx server
  2. Start a new http server manually
  3. Have it run an evil version of the rest api
  4. Use the good files to calculate the hashes

So, this doesn't work because nothing proves that the correct processes are actually running.

Idea 4

What if we add this to the list of things hasehed

  1. Hash of all referenced python modules: module.__package.__hash()
    • Requires the same environment to verify
  2. Output from ps showing services being run with the correct flag
    • To prevent config overriding

Summary

  1. Proving that the config files match the public records isn't enough, because the service can be shut down and then started after manually overriding the configs.

Clone this wiki locally