[I was torn between posting here or security.stackexchange.com. In the end, I felt that this was more of a design question, rather than an implementation question and so chose this forum.]
My question is: How do I assure myself that the results data submitted to me was generated by my official build of an open source program?
I'm developing an open source program. The program essentially collects data, performs some calculations, and sends back the data and results to me. The program is for all intents and purposes offline. More often than not, I'll get the results data back via a single HTTP post of XML data if I'm lucky, or more likely an emailed XML file, or a USB key with the XML for pure SneakerNet mode.
I will be releasing official builds of the program with the appropriate Authenticode signatures. (My target platform is Windows.) The Authenticode signing will prevent tampering of the program. Presumably, the program will be digitally signing the results data to prevent tampering of the data as well as establish the chain of evidence that the data was generated by this particular build. But how do I go from these "hand-waving" concept to actual implementation?
Since the program is open source, anybody else can also build the program, examine how it works, and potentially modify the program to perform some "cheating" or the results data that sent, as well as bypass any self-integrity checks I may embed in the code.
Here is what I've thought through so far:
Obviously, I'll be the only one holding on to the code signing keys. First layer of defense would be for the program to do a self-check for a valid Authenticode signature on all binaries. As as next layer, assuming it's doable, is verify that all binaries were signed using the same signing keys. I don't want to hardcode any attribute of the signing keys just in case somebody else wants to build their own official builds and verify that they are getting results from their official builds.
Although, the program integrity seems to be good, since it's open source somebody can always edit the code and make a build that doesn't do any self-integrity checks. :-(
The next bit of the puzzle is putting some characteristics of the running program binaries into the results XML. This could be simply a hash of all the running binaries. My server that accepts all the data can check the hash for a known good value. A malicious build can't bypass putting in a hash if the results data to be considered valid by the server, but it can just go ahead and compute the hash of all the official binaries and put it in the results XML. Essentially a replay attack. :-(
The next bit of the puzzle is how to digitally sign the results XML. This is a biggie. To do XML digital signatures, I'll need both the public and private keys. How do I embed these two keys into the program? Obviously checking them into source control is a really bad idea. :-(
I can hold the keys private the same way I held the code signing keys private and only at build time insert the keys as resources into the program. But I'm essentially publishing those keys once I release an official build. Anybody who looks at the source will discover that the keys are held in the resources and can get the keys themselves. :-(
Is there a public key system where I can generate my own private/public key pairs using characteristics of the official binaries? But this still suffers from the issue as above where a malicious build can just pick up those same characteristics from the official build. :-(
Any help or guidance on where to look for possible approaches to solve this problem would be most helpful.
Update: Think of this problem as building an open source voting machine. The Commission of Elections would like to build its own machines and distribute these for the elections, but it wants the source open to the world so that there are no rumors of impropriety. The commission doesn't care if the local Rotary club also makes their own voting machine for their board, but that machine should not be used to submit votes for the US Senate.