Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
The foundation of our system integrity solution is the TPM (described in greater detail under Private Key Storage).
Our design for system integrity maps closely to that of ChromeOS:
The hard drive is partitioned such that executable code lives on read-only partitions, and only /var
and /home
are mounted read/write for configuration, logs, and working data like scanned ballot images.
The read-only partitions are verified by dm-verity, which generates a hash tree of all the raw partition blocks, culminating in a single hash root for the entire read-only filesystem.
The kernel boot command line includes the dm-verity hash root as an argument, ensuring that Linux halts if the read-only partitions are not successfully verified against this hash root.
The BIOS is configured to only boot a properly signed bootloader+kernel+command-line, with public keys managed by VotingWorks and configured in the BIOS as secure boot keys. The bootloader+kernel+command-line that we want is set up as the default boot option in UEFI.
The private key described previously in Access Control is generated in the TPM and bound to Platform Configuration Registers (PCRs) that include the BIOS, the secure boot public keys, and the bootloader+kernel+command-line. Thus, this private key is only usable if the machine boots appropriately sanctioned source code with a hard drive whose read-only partitions are unmodified.
As a diagram:
The integrity of the overall system is ensured because:
Any change in the executable portion of the hard drive will be detected when dm-verity checks the hard drive blocks against its stored hashes.
Any change in the hashes stored on disk will be detected against the mismatched root hash, present in the kernel boot command line.
Any live changes to the hard drive, even while the machine is already booted up, will be detected the moment Linux tries to read those modified blocks, as all disk reads are live-checked against the hashes.
Any change in the kernel boot command line will be detected in two ways:
First, the TPM won’t unseal secrets since a change in the command line changes one of the PCR values, which means that the TPM’s policy check will fail.
Second, the system won’t even boot at all because the changed command line invalidates the signature on the bootloader+kernel+command-line, and UEFI will refuse to execute the now-improperly signed bootloader+kernel+command-line.
Thus, if the system boots, it means that the hard drive corresponds, by hashing, to the expected value that we baked into the bootloader+kernel+command-line and signed.
Our system is configured so that all partitions other than /var
, /tmp
, and /home
are mounted as read-only. This requires writing logs and other runtime-generated VotingWorks data, e.g. scanned ballot images, to /var
. Variable system configuration, e.g. timezone information, also needs to be redirected to /var
. A USB mount point is pre-created at /media/vx/usb-drive
.
With secure boot, UEFI passes control to the bootloader only if the bootloader is appropriately signed. Then, the bootloader passes control to the kernel. We choose to bundle the bootloader, kernel, and command line that is used to run the kernel all as one, and to present that to the UEFI as the single executable whose signature should be verified before running. The three are combined into a single object file, along with the dm-verity root hash. This single object file is signed by VotingWorks secure boot private keys.
Every VotingWorks machine’s BIOS is configured with VotingWorks secure boot public keys, and the BIOS is configured to require secure boot. Thus, only a properly signed object file can serve as bootloader.
When mounting USB drives, VxSuite always mounts them using standard Linux mount configuration options that makes files on the USB drive NOT executable. This further protects from any unauthorized software running, even in a transient fashion.
The VVSG 2.0 Test Assertions state that:
TA1.2-H 1: The voting system MUST prevent the loss of voting data in the event of a data input failure without relying on re-casting ballots. TA1.2-H 2: The voting system MUST prevent the loss of voting data in the event of a storage device failure without relying on re-casting ballots.
To meet these assertions, our precinct scanners export cast vote records (CVRs) to USB drive continuously, as ballots are cast. Continuous export also allows for a speedy polls close, as cast vote records need not be exported all at once on polls close.
To perform continuous export while also keeping signatures, i.e. authenticity information, up-to-date, we have to be able to write both CVRs and authenticity information incrementally. (It isn’t enough to just hash and sign new data. We need an up-to-date root hash/signature.) We can use a structure to accomplish this efficiently.
Assuming every CVR has a random UUID, e.g. 4d6a9dad-e6d6-4a29-89bc-9ab915012b73, we can specifically use the following structure:
We don’t actually have to 1) use a nested directory structure on the USB or 2) store all intermediate hashes on the USB. We can store the structure and intermediate hashes on the machine in a database table, e.g.
Then on the USB, we can use a flat structure that’s much easier to reason about and iterate over:
In the above examples, we’ve listed a root-hash.txt file and have signed that. In practice, we use a JSON file capable of storing other metadata and sign that:
Sample metadata.json:
Whenever a machine imports a CVR directory, it authenticates the CVRs by 1) verifying the signature on the metadata.json file and 2) recomputing the “castVoteRecordRootHash” in metadata.json from scratch to ensure that it’s correct.
Refer to the following codebase links for more detail on CVR hashing:
Beyond the application-level protections and system integrity assurances built to ensure that unauthorized access is thwarted and unauthorized software cannot be executed, VxSuite is also designed with defense-in-depth and least-privilege principles. This ensures that a failure of some defenses, due to unforeseen bugs or novel attacks, can be limited in its impact.
VxSuite runs a modern, stripped down Linux installation with the minimum number of packages to reduce the attack surface of any unexpected partial penetration. The set of packages is manually curated by our team and specified in our installation manifests when building a base Linux image.
Once a VxSuite image is built, access for the root user is shut down and that shutdown is locked in via secure-boot verification of the root partition.
When a VxSuite function requires superuser access, that access is captured as a minimal shell script, and the appropriate VxSuite Linux user is granted sudo permissions on that shell script alone. For example, on a VxSuite production machine, no user has the ability to call the mount
command. Instead, when mounting USB drives, we have crafted a shell program that is only capable of mounting and unmounting USB drives at the /media/usb-drive
mount point, and the vx-services
user is granted superuser privileges when calling that script only. The full script for this example is available at
VxSuite runs a minimal window manager, Openbox, which is built to have very few capabilities. In addition, we configure Openbox so as to turn off all keyboard shortcuts and contextual menus. Even if an attacker were able to plug in a mouse or a keyboard, they would be unable to get very far.
All processes that a user can directly interact with in VxSuite run as user vx-ui
. The processes that access the smartcard reader or perform data processing services run as user vx-services
.
The vx-services
Linux user has a set of permissions allowing it to access the scanner, printer, and smart card reader. It is configured, like the root user, to not have a password, so no interactive user can log in as vx-services
and utilize those privileges for nefarious purposes. The services that run under the vx-services
user account offer their services over local HTTP, with well-formed semantics as to what actions they allow. The authentication status is checked on the backend, by vx-services
, so actions can only be taken if a valid authentication session is open.
Meanwhile, if a user were to break out of the constraints we've placed on the window manager and obtain a shell, that shell would run as vx-ui
, which as the ability to call into services run as vx-services
, but does not itself have the direct privileges of vx-services
. Thus, an attacker that penetrates the first line of defense would remain severely thwarted in what they can do next.
The database table makes recomputing hashes easy, as retrieval of all hashes for a given ID prefix becomes a simple SQL query. This approach also decreases the chance that we accidentally depend on data written to USB when computing hashes, protecting against .
— CVR hashing logic, including the Merkle tree implementation
-
-
-
Root hash
4
-
-
4 hash
4
4d
-
4d hash
4
4d
4d6a9dad-e6d6-4a29-89bc-9ab915012b73
4d6a9dad-e6d6-4a29-89bc-9ab915012b73 hash
…
On VxSuite machines, there are no passwords for election administrators to use – only smart cards as described above. The smart cards all use 256-bit elliptic-curve digital signatures, which makes them cryptographically strong. In addition, the PINs that gate usage of those cards follow the NIST recommendations for authentication – 6 digits long, randomly generated (as opposed to chosen by the user who might use a birthdate), and never a weak PIN like 000000.
This section describe the overall system security architecture of VxSuite and the measures taken to thwart attacks on the proper operation of elections on VxSuite.
Requirement 14.1-C.1 – the use of cryptography to secure VxSuite – is covered by
the certificates and signatures used by smartcards, see Access Control / Smartcard Keys and Certificates.
digital signatures applied to all files exchanged between system components, see Artifact Authentication.
hard-drive partition hashes, as well as kernel and bootloader signature, used as part of secure-boot, see System Integrity.
additional details on encryption vs. authentication and the type and size of cryptographic keys we use is provided in Cryptography
Requirement 14.1-C.2 – the use of malware protection to secure VxSuite – is covered by the secure boot and safe mounting of external drives covered in System Integrity.
Requirement 14.1-C.3 – the use of a firewall to secure VxSuite – is covered in Networking.
Requirement 14.1-C.4 – the use of system configurations to secure VxSuite – is covered by:
aspects of secure-boot as described in System Integrity.
Requirement 11.4-A – on least privilege – is covered by Defense in Depth and Least Privilege.
Requirements 13.3-A, 13.3-C, 13.3-D are covered by Cryptography
All VxSuite components are blocked from connecting to any network. Thus, there is no network in a VxSuite implementation. Our network design is secure by virtue of it being completely absent.
We ensure that VxSuite components cannot connect to a network, either wifi, bluetooth, or ethernet. This is achieved through a few layers of defense:
Networking manager is turned off and removed in the setup process. See vxsuite-complete-system/setup-machine.sh
Secure boot ensures that the hard drive is not modified, thus preventing software that isn’t part of the approved VotingWorks bundle from running.
The BIOS is configured to disallow network connections.
Wifi/bluetooth hardware is not present on the machines.
When a VxSuite machine exports data to a USB for another VxSuite machine to import, the first machine digitally signs that data so that the second machine can verify its authenticity. We use this mechanism in two places in particular:
To authenticate “ballot packages” — These configuration bundles are exported by VxAdmin and used to configure VxCentralScan and VxScan.
To authenticate cast vote records — These are exported by VxCentralScan and VxScan and imported by VxAdmin for tabulation.
The exporting machine digitally signs the following message using its TPM private key (as configured in Access Control):
MESSAGE_FORMAT_VERSION + “//” + ARTIFACT_TYPE + “//” + ARTIFACT_CONTENTS
It then outputs the following to a .vxsig file:
SIGNATURE_LENGTH + SIGNATURE + SIGNING_MACHINE_CERTIFICATE
The importing machine parses the above, extracts the exporting/signing machine’s public key from its certificate as provided in the .vxsig file, reconstructs the message, and then verifies the signature. The importing machine also importantly verifies that the signing machine certificate in the .vxsig file is a valid certificate that is 1) signed by VotingWorks and 2) for the expected machine given the artifact type, e.g. VxAdmin if the artifact is a ballot package. We verify 1 using the VotingWorks CA certificate installed on every machine.
If signature verification fails on the importing machine, the importing machine will refuse to import the artifact. This provides protection against data tampering and/or corruption as data is transferred from one machine to another via USB.
Refer to the following codebase links for more detail on VxSuite artfiact authentication:
https://github.com/votingworks/vxsuite/tree/main/libs/auth — VxSuite authentication lib, a good starting point for all things authentication
https://github.com/votingworks/vxsuite/blob/main/libs/auth/src/artifact_authenticator.ts — Artifact authentication logic
https://github.com/votingworks/vxsuite/blob/main/libs/auth/src/cryptography.ts — OpenSSL commands underlying various authentication and signing operations
There is a tension between the requirement that (a) voter privacy should be strongly protected, and (b) Cast Vote Records should be continuously exported in order to ensure that they can be immediately available in the case of hardware failure. For example, if each scanned ballot naively results in the creation of a new CVR file on the USB stick with a timestamp, the order of CVRs is obviously preserved on the USB stick, as the file creation and modification timestamps reveal the order in which those CVRs were stored.
To meet both requirements, VxScan performs some amount of "shuffling" every time a CVR is saved to the USB drive. Every time a ballot is cast and its CVR is saved to the disk, VxScan picks one or two CVRs already stored on the USB drive, and updates their creation and modification time on the USB drive. This is the digital equivalent of taking one or two random ballots from a pile, and bringing them to the top of the pile. Thus, if an attacker were to view the CVRs on the USB drive, they would not be able to determine the order in which those ballots were cast, because of this constant shuffling.
The exact procedure used by VxScan, rather than just a mv
operation, is three steps. This is done to ensure that all metadata for a given CVR is updated, including file creation time. Recall from Hashing of Continuously Exported Cast Vote Records that a single CVR is structured, on disk, as a directory that contains the JSON data of the CVR and the ballot images for that CVR. Thus, the operations VxScan performs to move a single CVR "up to the top of the pile" is made up of three parts:
first, rename the directory corresponding to the CVR to a new name that indicates it is being copied, specifically by appending -old:
mv 4d6a9dad-e6d6-4a29-89bc-9ab915012b73/ 4d6a9dad-e6d6-4a29-89bc-9ab915012b73-old/
then, copy this renamed directory back to the original name:
cp -r 4d6a9dad-e6d6-4a29-89bc-9ab915012b73-old/ 4d6a9dad-e6d6-4a29-89bc-9ab915012b73/
finally, delete the -old directory:
rm -r 4d6a9dad-e6d6-4a29-89bc-9ab915012b73-old/
This three-step operation ensures that
all metadata for that CVR is updated, leaving no trace as to when that CVR was first saved to disk
if a failure occurs at any point, it is possible to recover completely without losing any data.
VxSuite is composed of individual machines, namely VxAdmin, VxCentralScan, and VxScan, as well as smartcards for authentication. Each machine and each smartcard has a unique 256-bit ECC private key (or keys in the case of smart cards) stored in tamper-resistant hardware, plus one or more X.509 certificates for the corresponding public key (or keys) with relevant attributes bound.
This means that every VxSuite component can prove its authenticity, notably to any other VxSuite component. For example, a smartcard can prove to a VxAdmin that it is a valid election administrator card for a particular election, or a VxScan can export digitally signed cast vote records, which a VxAdmin can then verify are authentic before importing.
Certification relationships work as follows:
VotingWorks directly certifies the type of every component, i.e. VxAdmin machine, VxCentralScan machine, VxScan machine, or smartcard. This makes it such that only components that are “blessed” by VotingWorks can successfully communicate with each other. This is also important for defense-in-depth as one VotingWorks component type cannot act like another, e.g. a VxScan cannot sign an election configuration package like a VxAdmin can.
VotingWorks further certifies every VxAdmin as bound to a particular jurisdiction, e.g. Warren County, Mississippi. This is important because VxAdmins program smartcards and should not be able to program cards for other jurisdictions.
Every smartcard, in addition to being certified directly by VotingWorks, is certified by a VxAdmin during card programming. A card’s VxAdmin-issued certificate indicates 1) the jurisdiction that the card is bound to, 2) which user role the card has been programmed for, i.e. system administrator card, election manager card, or poll worker card, and 3) in the case of election manager and poll worker cards, the specific election that the card is bound to.
As a diagram:
VxCentralScan and VxScan, unlike VxAdmin, aren’t bound to a jurisdiction by VotingWorks. They’re bound and unbound to jurisdictions as they’re configured and unconfigured by election managers. When an Election Manager configures a VxCentralScan or VxScan for an election, the machine persists in its datastore the jurisdiction of the Election Manager card used to unlock it and then only accepts cards from that jurisdiction. When the machine is unconfigured for that election, the machine returns to a jurisdiction-agnostic state.
As described above, programmed smartcards have two certificates, one issued by VotingWorks and one issued by VxAdmin. We generate two key pairs on the card, one for each certificate—we don’t certify the same card public key twice. Smart cards also have PINs (with the exception of poll worker cards, unless an election official chooses to enable poll worker card PINs). These interface as follows:
The private key slot associated with the card’s VotingWorks-issued certificate is not PIN-gated, so anyone can verify that a card is a VotingWorks-certified card.
The private key slot associated with the card’s VxAdmin-issued certificate is PIN-gated, so authentication requires PIN entry.
The card’s VxAdmin-issued certificate, on the other hand, is not PIN-gated, so it’s possible for a VotingWorks machine to know the card’s type and which election it’s bound to even before a PIN is entered. This allows the machine to display error messages like “election mismatch” immediately after card insertion and before PIN entry.
This does mean that an attacker could load a fake certificate onto a card such that the machine, at worst, displays an incorrect error message, but nothing more. Authentication would still fail as the public key in the certificate would not match the private key on the card. We take care not to fully trust the information in this certificate until we complete authentication.
We’ve taken inspiration from the NIST Personal Identity Verification (PIV) standard but haven’t strictly adhered to it. Our use case differs from the PIV standard in a number of ways, most notably in that cards are certified by two entities (VotingWorks and VxSuite), rather than just one. We also don’t need VxSuite smartcards to be interoperable with other PIV systems.
We store our root VotingWorks certificate authority (CA) private key encrypted in a password vault, usable only by a few authorized engineers.
VxAdmin, VxCentralScan, and VxScan are all built on devices with a Trusted Platform Module (TPM) 2.0, a chip that ships standard on modern Intel and AMD hardware. The TPM can keep cryptographic material secret inside its tamper-resistant boundary until a certain set of system conditions are met. Only once the TPM determines that the system meets a set of appropriate conditions—correct bootloader, kernel, kernel command line, etc.—does the TPM allow an application to ask it to perform signing operations with its contained secret key.
Our smart cards are Java Cards, version 3.0.4. These Java Cards can generate 256-bit ECC key pairs such that the private key never leaves the card, while the public key is exported. The cards are capable of self-destructing if someone attempts to extract the private key at the hardware level.
System administrator cards and election manager cards always have PINs. Poll worker cards do not have PINs by default but can if the system administrator enables them.
PINs are auto-generated random 6-digit numbers, guaranteed not to be weak (e.g. not 11111, 123456, 121212).
After 5 incorrect PIN attempts, users have to wait 15 seconds before they can try again. For every incorrect PIN attempt after that, the wait time doubles (15 seconds → 30 seconds → 60 seconds and so on). After 15 incorrect PIN attempts, the card is completely locked and has to be reprogrammed. System administrators can adjust the number of incorrect PIN attempts allowed without lockout as well as the starting lockout duration. The number of incorrect PIN attempts is stored on the card in a tamper-resistant location (as opposed to on the machine), meaning that taking a card to another machine to gain extra attempts will not work. Removing and reinserting a card restarts the lockout timer.
The certificates that we use are effectively vouchers—a certificate authority (CA) vouches that a public key has certain properties, for example that it is the public key of an election manager card for a particular election. This vouching is done by signing data containing the public key and those properties. We use X.509 certificates as they are broadly used and well supported.
While we could use existing X.509 fields like Organization, Organizational Unit, and Serial Number, and wedge our data into those types, overloading existing fields that don’t quite match isn’t ideal and could lead to security issues from type confusion.
Instead, we use our own fields. We’ve registered with IANA to have a VotingWorks enterprise object identifier (OID), which is effectively a prefix for OIDs of the form 1.3.6.1.4.1.32473.123, where 1.3.6.1.4.1.32473 is the enterprise OID for an example organization, and 123 is the 123rd field defined by that organization.
Our IANA-assigned Private Enterprise Number (PEN) is 59817, which means that the enterprise OID, fully-prefixed, is 1.3.6.1.4.1.59817. See https://www.iana.org/assignments/enterprise-numbers/?q=59817.
Our custom fields are:
1.3.6.1.4.1.59817.1 — Component = admin, central-scan, scan, or card (the first three referring to machines)
1.3.6.1.4.1.59817.2 — Jurisdiction = {state-2-letter-abbreviation}.{county-or-town} (e.g. ms.warren or ca.los-angeles)
1.3.6.1.4.1.59817.3 — Card type = system-administrator, election-manager, poll-worker, or poll-worker-with-pin (system administrator and election manager cards always have PINs)
1.3.6.1.4.1.59817.4 — Election hash = The SHA-256 hash of the election definition
X.509 certificates eventually expire. We use the following expiry times:
Certificates directly issued by VotingWorks: 100 years
VxAdmin-issued system administrator card certificates: 5 years
VxAdmin-issued election manager and poll worker card certificates: 6 months
This means that a system administrator card will automatically expire after 5 years, and election manager and poll worker cards will automatically expire after 6 months.
Configuration of VxSuite components begins at a secure VotingWorks facility. At this facility is a VotingWorks certification terminal, VxCertifier. VxCertifier is a fully offline air-gapped terminal with access to the root VotingWorks private key.
Using VxCertifier, VotingWorks prepares and certifies smart cards for use with VotingWorks machines:
VotingWorks installs the appropriate security module code on the card.
VotingWorks instructs the smart card to generate a key pair and export the public key.
The root VotingWorks CA certifies the card public key and saves the resulting certificate onto the card.
The card is now VotingWorks-certified but “blank” from the perspective of VotingWorks machines.
VotingWorks also certifies its machines at this facility. After a machine has been imaged with our latest software release, the machine boots into a configuration wizard. The software image includes the root VotingWorks CA certificate, so no extra work is required beyond imaging to “install” that certificate. Using the configuration wizard and VxCertifier, VotingWorks certifies machines:
VotingWorks machine code instructs the machine’s TPM to generate a key pair and export the public key.
VotingWorks machine code generates a certificate signing request (CSR) for that public key and writes the CSR to a USB.
On VxAdmin, VotingWorks additionally specifies a jurisdiction. That jurisdiction is included in the CSR.
The USB is plugged into VxCertifier. Through VxCertifier, the root VotingWorks CA certifies the machine public key and saves the resulting certificate onto the USB.
VxAdmin certificates are themselves CA certificates capable of creating additional certificates (necessary for smart card programming).
The USB is plugged back into the machine to be certified. The machine loads the certificate from the USB and saves it onto its hard drive.
On VxAdmin, the configuration wizard also surfaces a prompt to program a first system administrator card to bootstrap the jurisdiction as, from here on out, the machine will need to be unlocked by a system administrator card in order to program any other cards.
Machines, a first system administrator card, and “blank” cards are shipped to jurisdictions.
In the field, election officials use their VxAdmin and their first system administrator card to program additional smart cards. Smart card programming involves the following steps:
VxAdmin retrieves the card’s VotingWorks-issued certificate and verifies that it was signed by VotingWorks using the VotingWorks CA certificate installed on every machine.
VxAdmin resets the card PIN, which further causes the card to clear all of its PIN-gated key slots, essentially unprogramming it if it was previously programmed.
VxAdmin instructs the card to generate a key pair and export the public key. This key pair is distinct from the key pair that VotingWorks generated.
The VxAdmin CA certifies the card public key, assigning relevant attributes like the jurisdiction, card type, and election if applicable, and saves the resulting certificate to the card.
VxAdmin also saves its own CA certificate onto the card (more on how this is used under Authentication).
Smart card authentication involves the following steps:
The machine retrieves the card’s VotingWorks-issued certificate and verifies that it was signed by VotingWorks using the VotingWorks CA certificate installed on every machine.
The machine retrieves 1) the card’s VxAdmin-issued certificate and 2) the certificate of the VxAdmin that programmed the card, which as noted in Smart Card Programming is also loaded onto the card. The machine verifies that the former (1) was signed by the latter (2). The machine also verifies that the latter is a valid VxAdmin certificate signed by VotingWorks using the VotingWorks CA certificate, establishing a chain of trust all the way up to a trusted root.
The machine verifies that the card has a private key that corresponds to the public key in the card’s VotingWorks-issued certificate by asking the card to sign a challenge with its private key and attempting to verify it with the public key.
The machine verifies that the card has a private key that corresponds to the public key in the card’s VxAdmin-issued certificate by asking the card to sign a challenge with its private key and attempting to verify it with the public key.
If the card has a PIN, the card will only proceed with this signature if provided the appropriate PIN. The VotingWorks machine thus asks the user for their PIN to perform this operation.
Throughout this process, the machine verifies that certificate fields are valid and consistent. It also verifies that the card jurisdiction and election match the machine jurisdiction and election, where relevant.
Machines automatically lock after they’ve been left idle for 30 minutes and also automatically lock after 12 hours, even if the user has been active. The user is given appropriate heads up. System administrators can select shorter time limits.
These time limits do not apply to unauthenticated screens like the “Insert Your Ballot” screen on VxScan.
Refer to the following codebase links for more detail on VxSuite access control:
https://github.com/votingworks/vxsuite/tree/main/libs/auth — VxSuite authentication lib, a good starting point for all things authentication
https://github.com/votingworks/vxsuite/blob/main/libs/auth/src/dipped_smart_card_auth.ts — High-level authentication state management for VxAdmin and VxCentralScan
https://github.com/votingworks/vxsuite/blob/main/libs/auth/src/inserted_smart_card_auth.ts — High-level authentication state management for VxScan
https://github.com/votingworks/vxsuite/blob/main/libs/auth/src/java_card.ts — Java Card implementation
https://github.com/votingworks/vxsuite/blob/main/libs/auth/src/certs.ts — Certificate configuration
https://github.com/votingworks/vxsuite/blob/main/libs/auth/src/cryptography.ts — OpenSSL commands underlying various authentication and signing operations
https://github.com/votingworks/vxsuite-complete-system/blob/main/config/admin-functions/basic-configuration.sh — The production machine configuration wizard
https://github.com/votingworks/vxsuite/tree/main/libs/auth#scripts — A summary of the scripts in https://github.com/votingworks/vxsuite/tree/main/libs/auth/scripts, many of which are used for production configuration
https://github.com/votingworks/openfips201 — The applet that we’re installing onto our Java Cards
VxSuite v3.1 contains four distinct cryptographic modules:
Smartcards
VxScan TPM
VxAdmin / VxCentralScan TPM (they run on the same hardware)
OpenSSL software
VxSuite v3.1 uses NXP JCOP 3 smartcards, specifically this model:
These cards are FIPS140-2 certified:
A future version of VxSuite will support JCOP4 cards from NXP, which have a more recent FIPS compliance record:
The applet we run on the card, , is an implementation of the NIST 201 PIV protocol, which sits on top of FIPS140 cryptography. In the applet, all cryptographic operations are handled by the JavaCard operating system, implemented by the NXP JCOP card, which is FIPS140 compliant.
Asus uses a TPM2.0 chip by Nuvoton:
This chip is FIPS-compliant:
That CMVP requires Debian 11.5 (released September 2022). VxSuite v3.1 uses Debian 12 (released June 2023), in order to ensure a maximally patched operating system. OpenSSL on Debian12 does not yet have a FIPS-compliant certificate. That said, we use only FIPS-compliant algorithms (ECDSA), and we use OpenSSL in this software mode only for verification operations that do not require secret-key access.
VxSuite does not use encryption to secure data (CVRs, election definitions), because that data does not need to be confidential – and in fact trust in a voting system is better achieved by transparency of this data. In particular, CVRs stored on USB sticks are not encrypted, so they can be viewed using any computer. This is by design.
All digital signatures used to authenticate election definitions and CVRs are ECC 256-bit keys, specifically using the standard NIST P256 curve.
All hashes – used to generate election IDs and in the Merkle-tree hash of CVRs on the USB – are performed using the NIST standard SHA256.
System integrity on the drive, using dm-verity, is done using SHA256 hashes, and the code signing is done using RSA-4096 bit keys.
Lenovo uses a TPM 2.0 chip by Nuvoton, the NTC 75x series, covered by the same CMVP for FIPS compliance:
We use OpenSSL v3 with the hardware module, which outsources all cryptographic operations performed with secret keys to the underlying TPM 2.0 chip, which, as specified above, are FIPS compliant. See for calling OpenSSL with the appropriate hardware module.
For verification of signatures, we use OpenSSL in software mode. This does have a CMVP:
On the other hand, VxSuite strongly authenticates all data, which is critical. Thus, CVRs and election definitions are in plaintext on the USB drives that transfer them, accompanied by strong digital signatures, rooted in signing keys stored in hardware TPMs, as described in .