We think that our software is complete and do not expect any substantial additions to it, but we hope that developers keep all potential users and other developers in mind when they find issues and develop extensions.
We welcome suggestions, questions, and cooperation with us or between developers and hope that developers are open with what they are planning to avoid redundant work by other developers.
A system that is verifiable solely by inspecting the artifacts and information it produces, and not by inspecting any software, is said to be software independent, the idea being that anybody can write software in any language or on any platform and perform the verification. Given how hard it is to truly verify the behavior of software, this is a great idea and of course closely related to zero knowledge proofs of correctness.
It does however not eliminate the need for auditing code since several security properties are not guaranteed by verifying correctness of an execution. Assuming a trusted party, one could in principle verify privacy using a verifiable PRG (or PRF), but this is not practical today. The only practical way to verify that a complex protocol handles randomness correctly is by auditing the code.
Robustness is normally a functional property, but faults, restarting, etc, must be thought of as part of the protocol in security critical applications since they provide additional avenues of attacking the system to the adversary. In the future it may be possible to model complex protocols with sufficient granularity to not audit code for this reason, but this is not the case today.
People make mistakes. A bug in a desktop application is a nuisance, but a corresponding bug in a security critical application can have immediate and serious consequences. Thus, it is of utmost importance that the software is relatively transparent and modular to allow auditing changes and committing them relatively quickly.
There are magical "features" in every programming language. It is a bad idea to use these features in general, but in code that may be audited it is a particularly bad idea, since some of the auditors may be experts in security and only have working knowledge in programming in any particular language. Stick to basic general paradigm and idioms, and avoid "advanced patterns".
We have spent a considerable amount of time on validation of inputs, e.g., configuration parameters for our mix-net is validated both at a syntactical level with regexps directly in the XML parser and at the semantic level.
We have also provided conservative default values for all configuration parameters, so for normal usage the user does not have to specify any parameters at all that requires a deep understanding of cryptography.
Please follow our example and make sure that if you introduce additional configuration options, then you also validate them and provide sensible default values.
We appreciate if you follow our code standard, since otherwise we have to reformat any code you write that is adopted into future official versions after we have audited it. We mostly follow: SUN's (now Oracle's) original code standard for Java, and the GNU code standard for C. We always break all lines at 80 characters, since all editors then work well.
We have deliberately used generic programming paradigms as much as possible instead of specific features of particular languages. Inner classes, anonymous classes, lambdas, maps over arrays, templates, etc are only used if there is a clear advantage and not only to save a couple of lines of code. This makes the code easier to read for people that only have working knowledge in any given language.
We systematically check our Java code with FindBug, PMD, and CheckStyle. These tools give false positives, so it is necessary to filter out special cases or cases where the tools simply behave incorrectly on a case-by-case basis. Please follow this approach. We generate API documentation with JavaDoc and this is a good tool to verify that all the code has been documented as well. Please make sure that JavaDoc does not give any warnings.
Similarly, we use the most stringent compiler flags and derive them from those used by GMP for our C code. Please use this approach for your own code when feasible.
Our code is thoroughly commented. In fact, we expect some developers to think that there are too many comments. Our view is that it is better to comment everything instead of arguing what to comment or not. Comments can be folded in every editor, so those that prefer the raw code "because they read code better than comments" can do that, but we hope that they are willing to write comments for those of us that are not as apt at this.
Our goal is that our software is portable over all major UNIX and Linux platforms, i.e., in a loose sense we expect it to be POSIX compliant although this has not been verified systematically. We hope that developers report any problems to us and if possible provide solutions or workarounds. We expect that developers see the value in this goal.
That said, we welcome efforts to make our software run on other platforms such as Windows, but we focus on UNIX and Linux.
Developers who lack a deep understanding of the underlying principles or are novice programmers make more mistakes; even if they have good intentions. In many cases multiple developers that write independent parts of a system mean more security risks with reduced understanding of the system as a whole. Do not involve more developers than you absolutely need and make sure that you know who your developers are and what their technical backgrounds are.
Loosely formed groups of developers without any admission rules other than contributing code that works are easily infiltrated. This is one of the reasons security aware projects such as OpenBSD are developed by a small group of knowledgeable people. It is naive to think that secret services have not infiltrated all the large open source projects deemed worthwhile in a cost-benefit analysis. Do not involve anybody that you do not trust and be willing to pay the price in terms of development time for declining offers to help.
A good rule of thumb is that you should be able to name all developers off the top of your head and know who they are, their background, and explain why they were involved.
Most programmers are used to dependencies being a problem in terms of portability both in terms of missing packages or libraries, and conflicts between multiple versions.
Portability is important, but the main problem with dependencies in security critical software is that it drastically degrades real world security. Everybody who commits code to any dependency is now a developer of your system and must be treated as such. Even worse they are the kind of developers that may commit code to your code base without asking for permission, informing you in advance, or checking that it does not create vulnerabilities in other parts of the system. Furthermore, more dependencies makes it more difficult to harden a server in a production environment.
We have gone to great lengths to minimize the number of dependencies in our software and would appreciate if you do this as well. Needless to say, real world security is rarely binary. We use compilers, building tools, operating systems, and hardware, but our dependencies are all necessary.
Although we do not expect to find any serious bugs in our software, this can not be excluded. If somebody discovers a vulnerability in our software, or in modified software, during the preparation of an election, then that could be fixed without any serious repercussions for that particular user.
The problem is that there may be other users that are just about to open polling stations and online voting and the disclosure of a vulnerability, e.g., in a blog post, could cause serious damage. Thus, we suggest that developers and users behave responsibly and contact us to let us make best effort to resolve problems in a controlled way. We also encourage developers to inform us in advance when they release software for actual use.
To make this approach as effective as possible, we strongly suggest that users of modified software also inform us well in advance to allow us to make a best effort attempt to organize the disclosure of the vulnerability privately before the discoverer makes it public and gets the credit.
Real world security is not black and white. An adversary can not be expected to contact us if they would find a vulnerability, but we think that we should at least attempt to set up an infrastructure and know how to contact everybody who uses the software. Thus, we hope that developers and users assign security officers that are responsible for the communication about security issues.
We have done our best to trade various security, cost, and practicality properties against each other.
For example: we have chosen to use the standard GNU build system despite that this is not particularly convenient for Java development. Although this may look like a novice mistake to a generic Java developer, this is a deliberate well-informed decision due to using multiple languages, maturity, portability, and security.
A third example is our binary byte tree format. One of the most common questions about our mix-net is why we use this format and not X509, XML, JSON, etc. We use this simple format for many reasons and only give a few here: (1) it is exceptionally simple to parse and generate, so there is no need for external libraries to parse it, (2) we need an unambiguous format to specify exactly what is input to hash functions, (3) it allows us to use the same format internally and for communication without any performance penalty, and (4) it is compact, which is important to reduce communication complexity.
Numerous such design decisions were taken during the development of the software and they may not be obvious to somebody who has not gone through the process and experimented with the alternatives. Furthermore, parts of the code can not be changed without also updating manuals and documentation that have been refined for years.
Thus, we strongly suggest that you consult us before you jump to any conclusions, and we strongly suggest that you do not make any drastic or cosmetic changes in the structure of the code, APIs, data formats, etc.
That said, we have of course made mistakes as far as software engineering goes and we welcome a constructive dialogue with people that are more experienced than we are. If something can be improved with reasonable effort, then we will of course do that and otherwise we are always curious to learn what we could have done in a better way.