diff --git a/polling-station/src/main/java/meerkat/pollingstation/PollingStationMainController.java b/polling-station/src/main/java/meerkat/pollingstation/PollingStationMainController.java index 00088bf..06a165f 100644 --- a/polling-station/src/main/java/meerkat/pollingstation/PollingStationMainController.java +++ b/polling-station/src/main/java/meerkat/pollingstation/PollingStationMainController.java @@ -2,7 +2,6 @@ package meerkat.pollingstation; import com.google.common.util.concurrent.FutureCallback; import meerkat.pollingstation.controller.PollingStationControllerInterface; -import meerkat.pollingstation.controller.callbacks.ScanDataCallback; import meerkat.pollingstation.controller.commands.PollingStationCommand; import meerkat.pollingstation.controller.commands.ReceivedScanCommand; import meerkat.protobuf.PollingStation; @@ -26,7 +25,7 @@ public class PollingStationMainController implements PollingStationControllerInt } @Override - public void init(PollingStationScanner.Consumer server) { + public void init(PollingStationScanner.PollingStationServer server) { server.subscribe(new FutureCallback() { @Override public void onSuccess(PollingStation.ScannedData result) { diff --git a/polling-station/src/main/java/meerkat/pollingstation/PollingStationScannerWebApp.java b/polling-station/src/main/java/meerkat/pollingstation/PollingStationScannerWebApp.java index c454d4c..3208aad 100644 --- a/polling-station/src/main/java/meerkat/pollingstation/PollingStationScannerWebApp.java +++ b/polling-station/src/main/java/meerkat/pollingstation/PollingStationScannerWebApp.java @@ -6,7 +6,8 @@ package meerkat.pollingstation; import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.BoolValue; -import meerkat.protobuf.Crypto; +import meerkat.crypto.DigitalSignature; +import meerkat.crypto.concrete.ECDSASignature; import meerkat.protobuf.PollingStation; import javax.annotation.PostConstruct; @@ -16,24 +17,25 @@ import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; -import java.io.IOException; import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_CONNECT_PATH; -import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_ERROR_PATH; import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_SCAN_PATH; import static meerkat.rest.Constants.MEDIATYPE_PROTOBUF; /** - * Implements a Web-App interface for {@link meerkat.pollingstation.PollingStationScanner.Producer} + * Implements a Web-App interface for {@link PollingStationScanner.ScannerClient} * This class depends on {@link meerkat.pollingstation.PollingStationWebScanner} and works in conjunction with it */ @Path("/") -public class PollingStationScannerWebApp implements PollingStationScanner.Producer { - +public class PollingStationScannerWebApp implements PollingStationScanner.PollingStationWebAPI { @Context ServletContext servletContext; - Iterable> callbacks; + final static BoolValue trueValue = BoolValue.newBuilder().setValue(true).build(); + final static BoolValue falseValue = BoolValue.newBuilder().setValue(false).build(); + + PollingStationWebScanner.ScanRequestHandler requestHandler; + /** * This method is called by the Jetty engine when instantiating the servlet @@ -44,7 +46,7 @@ public class PollingStationScannerWebApp implements PollingStationScanner.Produc Object context = servletContext.getAttribute(PollingStationWebScanner.CALLBACKS_ATTRIBUTE_NAME); try { - callbacks = (Iterable>) context; + requestHandler = (PollingStationWebScanner.ScanRequestHandler) context; } catch (ClassCastException e) { throw e; } @@ -57,7 +59,7 @@ public class PollingStationScannerWebApp implements PollingStationScanner.Produc @Produces(MEDIATYPE_PROTOBUF) @Override public BoolValue connect(PollingStation.ConnectionClientData clientData) { - return null; + return requestHandler.handleConnection(clientData) ? trueValue : falseValue; } @POST @@ -65,22 +67,8 @@ public class PollingStationScannerWebApp implements PollingStationScanner.Produc @Consumes(MEDIATYPE_PROTOBUF) @Produces(MEDIATYPE_PROTOBUF) @Override - public BoolValue newScan(PollingStation.ScannedData scannedData) { - - boolean handled = false; - - // TODO: - for (FutureCallback callback : callbacks){ - - callback.onSuccess(scannedData); - handled = true; - - } - - return BoolValue.newBuilder() - .setValue(handled) - .build(); - + public BoolValue newScan(PollingStation.SignedScannedData scannerData) { + return requestHandler.handleRequest(scannerData) ? trueValue : falseValue; } } diff --git a/polling-station/src/main/java/meerkat/pollingstation/PollingStationToyRun.java b/polling-station/src/main/java/meerkat/pollingstation/PollingStationToyRun.java index 8d3e855..424f41a 100644 --- a/polling-station/src/main/java/meerkat/pollingstation/PollingStationToyRun.java +++ b/polling-station/src/main/java/meerkat/pollingstation/PollingStationToyRun.java @@ -10,7 +10,7 @@ import org.slf4j.LoggerFactory; public class PollingStationToyRun { final Logger logger = LoggerFactory.getLogger(getClass()); - private static PollingStationScanner.Consumer scanner; + private static PollingStationScanner.PollingStationServer scanner; private static final String CONTEXT_PATH = "/scan"; private static final int PORT = 8080; diff --git a/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java b/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java index c25a3fd..6eee87c 100644 --- a/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java +++ b/polling-station/src/main/java/meerkat/pollingstation/PollingStationWebScanner.java @@ -1,10 +1,16 @@ package meerkat.pollingstation; +import java.security.InvalidKeyException; import java.security.SecureRandom; +import java.security.SignatureException; +import java.security.cert.CertificateException; import java.util.List; import java.util.LinkedList; import com.google.common.util.concurrent.FutureCallback; +import com.google.protobuf.ByteString; +import meerkat.crypto.DigitalSignature; +import meerkat.crypto.concrete.ECDSASignature; import meerkat.protobuf.PollingStation; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.*; @@ -14,28 +20,128 @@ import org.glassfish.jersey.server.ResourceConfig; import meerkat.protobuf.PollingStation.ScannedData; import meerkat.rest.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Created by Arbel on 05/05/2016. */ -public class PollingStationWebScanner implements PollingStationScanner.Consumer { - +public class PollingStationWebScanner implements PollingStationScanner.PollingStationServer { public final static String CALLBACKS_ATTRIBUTE_NAME = "controller"; + final Logger logger = LoggerFactory.getLogger(getClass()); + + /** + * Expected serial number for next scan + */ + long expectedSerial; + + + /** + * Should a newly-connected scanner be verified using the nonce? + */ + boolean verifyNonce; + + /** + * Should every scan's signature be verified? + */ + boolean verifySignatures; + + + /** + * The nonce we use to verify a new scanner connection. + */ + long nonce; + + + /** + * + */ + DigitalSignature verifier; + private final Server server; + private final List> callbacks; - boolean verifyScanner; - byte nonce[]; + + public class ScanRequestHandler { + private ScanRequestHandler() { } + + boolean handleConnection(PollingStation.ConnectionClientData data) { + if (verifyNonce) { + if (data.getNonce() != nonce) { + + logger.warn("Received scanner connection with bad nonce!"); + return false; + } + } + + if (verifySignatures) { + try { + if (data.getIdCase() != PollingStation.ConnectionClientData.IdCase.SCANNERPK) + throw new CertificateException("Connection request doesn't include certificate!"); + + verifier.loadVerificationCertificate(data.getScannerPK()); + } catch (CertificateException e) { + logger.warn("Scanner connection with bad certificate: {}", e); + return false; + } + } + + return true; + } + + boolean handleRequest(PollingStation.SignedScannedData data) { + ScannedData scannedData = data.getData(); + if (verifySignatures) { + ByteString scannerID = scannedData.getScannerId(); + if (!scannerID.equals(verifier.getSignerID())) { + logger.warn("Scanner ID doesn't match connection public key"); + return false; + } + + try { + verifier.initVerify(data.getScannerSig()); + verifier.updateContent(scannedData); + if (!verifier.verify()) { + logger.warn("Bad Signature"); + return false; + } + + } catch (CertificateException e) { + logger.warn("Certificate Exception: {}", e); + return false; + } catch (InvalidKeyException e) { + logger.warn("InvalidKey Exception: {}", e); + return false; + } catch (SignatureException e) { + logger.warn("Signature Exception: {}", e); + return false; + } + } + + for (FutureCallback callback : callbacks) { + callback.onSuccess(scannedData); + } + + return true; + } + + } + + ScanRequestHandler scanRequestHandler; + public PollingStationWebScanner(int port, String contextPath) { + scanRequestHandler = new ScanRequestHandler(); callbacks = new LinkedList<>(); + verifier = new ECDSASignature(); server = new Server(port); ServletContextHandler servletContextHandler = new ServletContextHandler(server, contextPath); - servletContextHandler.setAttribute(CALLBACKS_ATTRIBUTE_NAME, (Iterable>) callbacks); + servletContextHandler.setAttribute(CALLBACKS_ATTRIBUTE_NAME, callbacks); ResourceConfig resourceConfig = new ResourceConfig(PollingStationScannerWebApp.class); resourceConfig.register(ProtobufMessageBodyReader.class); @@ -50,10 +156,8 @@ public class PollingStationWebScanner implements PollingStationScanner.Consumer @Override public PollingStation.ConnectionServerData start(boolean verifyScanner) throws Exception { - this.verifyScanner = verifyScanner; - nonce = new byte[32]; - new SecureRandom().nextBytes(nonce); - + this.verifyNonce = this.verifySignatures = verifyScanner; + nonce = new SecureRandom().nextLong(); server.start(); return null; diff --git a/polling-station/src/main/java/meerkat/pollingstation/ReceiverScanHandler.java b/polling-station/src/main/java/meerkat/pollingstation/ReceiverScanHandler.java index 500f2a3..3436eb6 100644 --- a/polling-station/src/main/java/meerkat/pollingstation/ReceiverScanHandler.java +++ b/polling-station/src/main/java/meerkat/pollingstation/ReceiverScanHandler.java @@ -15,8 +15,6 @@ import org.eclipse.jetty.servlet.ServletHolder; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.servlet.ServletContainer; -import java.nio.ByteBuffer; -import java.time.Instant; import java.util.LinkedList; import java.util.List; import java.util.concurrent.LinkedBlockingQueue; @@ -24,7 +22,7 @@ import java.util.concurrent.LinkedBlockingQueue; /** * Created by Laura on 3/20/2017. */ -public class ReceiverScanHandler implements PollingStationScanner.Consumer, Runnable { +public class ReceiverScanHandler implements PollingStationScanner.PollingStationServer, Runnable { public final static String CALLBACKS_ATTRIBUTE_NAME = "controller"; diff --git a/polling-station/src/main/java/meerkat/pollingstation/ReceiverWebAPI.java b/polling-station/src/main/java/meerkat/pollingstation/ReceiverWebAPI.java index 4e8d8b2..29a7487 100644 --- a/polling-station/src/main/java/meerkat/pollingstation/ReceiverWebAPI.java +++ b/polling-station/src/main/java/meerkat/pollingstation/ReceiverWebAPI.java @@ -1,6 +1,5 @@ package meerkat.pollingstation; -import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.BoolValue; import meerkat.pollingstation.controller.callbacks.ScanCallback; import meerkat.pollingstation.controller.callbacks.ScanDataCallback; @@ -23,11 +22,11 @@ import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB import static meerkat.rest.Constants.MEDIATYPE_PROTOBUF; /** - * Implements a Web-App interface for {@link meerkat.pollingstation.PollingStationScanner.Producer} + * Implements a Web-App interface for {@link PollingStationScanner.ScannerClient} * This class depends on {@link meerkat.pollingstation.ReceiverScanHandler} and works in conjunction with it */ @Path("/") -public class ReceiverWebAPI implements PollingStationScanner.Producer { +public class ReceiverWebAPI implements PollingStationScanner.ScannerClient { @Context ServletContext servletContext; diff --git a/polling-station/src/main/java/meerkat/pollingstation/controller/PollingStationControllerInterface.java b/polling-station/src/main/java/meerkat/pollingstation/controller/PollingStationControllerInterface.java index ef7f2ef..caf3530 100644 --- a/polling-station/src/main/java/meerkat/pollingstation/controller/PollingStationControllerInterface.java +++ b/polling-station/src/main/java/meerkat/pollingstation/controller/PollingStationControllerInterface.java @@ -11,7 +11,7 @@ public interface PollingStationControllerInterface extends Runnable { * (see VotingBoothController) */ // TODO: 4/16/2017 complete with proper arguments and exceptions - public void init(PollingStationScanner.Consumer server); + public void init(PollingStationScanner.PollingStationServer server); /** * an asynchronous call from Admin Console (If there is such one implemented) to shut down the system diff --git a/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java b/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java index 6e88baa..39c9ff0 100644 --- a/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java +++ b/polling-station/src/test/java/meerkat/pollingstation/PollingStationWebScannerTest.java @@ -27,7 +27,7 @@ import static org.hamcrest.MatcherAssert.assertThat; */ public class PollingStationWebScannerTest { - private PollingStationScanner.Consumer scanner; + private PollingStationScanner.PollingStationServer scanner; private static final String ADDRESS = "http://localhost"; private static final String SUB_ADDRESS = ""; private static final int PORT = 8080; diff --git a/polling-station/src/test/java/meerkat/pollingstation/ReceiverTest.java b/polling-station/src/test/java/meerkat/pollingstation/ReceiverTest.java index de2fc70..a5b138b 100644 --- a/polling-station/src/test/java/meerkat/pollingstation/ReceiverTest.java +++ b/polling-station/src/test/java/meerkat/pollingstation/ReceiverTest.java @@ -27,7 +27,7 @@ import static org.hamcrest.MatcherAssert.assertThat; */ public class ReceiverTest { - private PollingStationScanner.Consumer scanner; + private PollingStationScanner.PollingStationServer scanner; private static final String ADDRESS = "http://localhost"; private static final String SUB_ADDRESS = ""; private static final int PORT = 8080; diff --git a/polling-station/src/test/java/meerkat/pollingstation/Receiver_ClientTest.java b/polling-station/src/test/java/meerkat/pollingstation/Receiver_ClientTest.java index 368bd80..762784c 100644 --- a/polling-station/src/test/java/meerkat/pollingstation/Receiver_ClientTest.java +++ b/polling-station/src/test/java/meerkat/pollingstation/Receiver_ClientTest.java @@ -5,20 +5,12 @@ import com.google.protobuf.ByteString; import meerkat.protobuf.PollingStation; import meerkat.protobuf.PollingStation.ErrorMsg; import meerkat.protobuf.PollingStation.ScannedData; -import meerkat.rest.Constants; -import meerkat.rest.ProtobufMessageBodyReader; -import meerkat.rest.ProtobufMessageBodyWriter; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.Response; import java.util.concurrent.Semaphore; import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_ERROR_PATH; @@ -28,7 +20,7 @@ import static org.hamcrest.MatcherAssert.assertThat; public class Receiver_ClientTest { final Logger logger = LoggerFactory.getLogger(getClass()); - private PollingStationScanner.Consumer scanner; + private PollingStationScanner.PollingStationServer scanner; private static final String CONTEXT_PATH = "/scan"; private Semaphore semaphore; @@ -94,7 +86,7 @@ public class Receiver_ClientTest { scanner.subscribe(new ScanHandler(scannedData)); - PollingStationScanner.Producer scannerClient = new ScannerClientAPI() + PollingStationScanner.ScannerClient scannerClient = new ScannerClientAPI() ScannerClientAPI(PSC_URL + POLLING_STATION_WEB_SCANNER_SCAN_PATH); scannerClient.newScan(scannedData, null); diff --git a/scanner-api-common/src/main/java/meerkat/pollingstation/PollingStationScanner.java b/scanner-api-common/src/main/java/meerkat/pollingstation/PollingStationScanner.java index bc4c71d..dd62388 100644 --- a/scanner-api-common/src/main/java/meerkat/pollingstation/PollingStationScanner.java +++ b/scanner-api-common/src/main/java/meerkat/pollingstation/PollingStationScanner.java @@ -15,7 +15,7 @@ public interface PollingStationScanner { /** * An interface for processing scans (Polling Station side) */ - public interface Consumer { + public interface PollingStationServer { /** * Sets up the connection to the scanner and begins receiving scans. @@ -40,10 +40,11 @@ public interface PollingStationScanner { public void subscribe(FutureCallback scanCallback); } + /** - * An interface for submitting scanned data (scanner side) + * An interface for handling the WebAPI (on the polling-station side) */ - public interface Producer { + public interface PollingStationWebAPI { /** * Connect to the polling station server. @@ -54,11 +55,43 @@ public interface PollingStationScanner { /** * Sends a scan to all subscribers - * @param scannedData contains the scanned data - * @return a BoolValue containing TRUE iff the scanned data has been sent to at least one subscriber + * @param scannedData contains the scanned data. + * This can be either a ScannedBallot or a ScanError; + * On the client side, this method can be called without setting + * the signature field. + * @return true iff the scanned data has been sent to at least one subscriber */ - public BoolValue newScan(ScannedData scannedData); - + public BoolValue newScan(SignedScannedData scannedData); } + + /** + * An interface for submitting scanned data (scanner side) + */ + public interface ScannerClient { + + /** + * Connect to the polling station server. + * The client data contains the scanner ID and optional verification data. + * @return + */ + public boolean connect(ConnectionServerData serverData); + + /** + * Sends a scan to all subscribers + * @param scannedBallot contains the scanned data. + * This can be either a ScannedBallot or a ScanError; + * @return true iff the scanned data has been sent to at least one subscriber + */ + public boolean newScan(ScannedBallot scannedBallot); + + /** + * Report a scan error to all subscribers + * @param scanError + * @return + */ + public boolean reportError(ScanError scanError); + } + + } \ No newline at end of file diff --git a/scanner-api-common/src/main/java/meerkat/pollingstation/ScannerClientAPI.java b/scanner-api-common/src/main/java/meerkat/pollingstation/ScannerClientAPI.java index e8331d4..e39317e 100644 --- a/scanner-api-common/src/main/java/meerkat/pollingstation/ScannerClientAPI.java +++ b/scanner-api-common/src/main/java/meerkat/pollingstation/ScannerClientAPI.java @@ -1,64 +1,137 @@ package meerkat.pollingstation; import com.google.protobuf.BoolValue; -import meerkat.protobuf.Crypto; +import com.google.protobuf.ByteString; +import meerkat.crypto.DigitalSignatureGenerator; import meerkat.protobuf.PollingStation; import meerkat.rest.Constants; import meerkat.rest.ProtobufMessageBodyReader; import meerkat.rest.ProtobufMessageBodyWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; +import java.security.SignatureException; /** * Created by Laura on 3/20/2017. */ -public class ScannerClientAPI implements PollingStationScanner.Producer { - private Client client; - private WebTarget webTarget; - - public ScannerClientAPI(String url) { - client = ClientBuilder.newClient(); - client.register(ProtobufMessageBodyReader.class); - client.register(ProtobufMessageBodyWriter.class); - webTarget = client.target(url); - } +public class ScannerClientAPI implements PollingStationScanner.ScannerClient { + final Logger logger = LoggerFactory.getLogger(getClass()); + DigitalSignatureGenerator signer; + ByteString scannerID; + Client client; + WebTarget webTarget; /** - * Sends the scanned data to the polling station server - * @param scannedData - * @return boolean value: true if the data was sent successfully, false otherwise + * Serial number of request (zeroed on new connection to server) */ - @Override - public BoolValue newScan(PollingStation.ScannedData scannedData) { + long serial; - Response response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(scannedData, Constants.MEDIATYPE_PROTOBUF), - ); - BoolValue res = response.readEntity(BoolValue.class); - response.close(); - return res.getValue(); + + protected ScannerClientAPI() { + this.signer = null; + this.scannerID = null; + this.client = ClientBuilder.newClient(); + this.client.register(ProtobufMessageBodyReader.class); + this.client.register(ProtobufMessageBodyWriter.class); + } + + /** + * Constructor for client that doesn't use signatures. + * @param scannerId + */ + public ScannerClientAPI(byte[] scannerId) { + this(); + ByteString.copyFrom(scannerId); + } + + /** + * Constructor for client that signs messages. + * @param signer + */ + public ScannerClientAPI(DigitalSignatureGenerator signer) { + this(); + assert (signer != null && signer.getSignerID() != null); // Use the default constructor instead + + this.signer = signer; + this.scannerID = signer.getSignerID(); } public void close() { client.close(); - } @Override - public BoolValue connect(PollingStation.ConnectionClientData clientData) { - return null; + public boolean connect(PollingStation.ConnectionServerData serverData) { + serial = 0; + webTarget = client.target(serverData.getServerUrl()); + PollingStation.ConnectionClientData.Builder clientData = PollingStation.ConnectionClientData.newBuilder() + .setNonce(serverData.getNonce()); + + if (signer != null) { + clientData.setScannerPK(signer.getSignerPublicKey()); + } else { + clientData.setScannerId(scannerID); + } + + Response response = webTarget.request(Constants.MEDIATYPE_PROTOBUF) + .post(Entity.entity(clientData.build(), Constants.MEDIATYPE_PROTOBUF)); + BoolValue res = response.readEntity(BoolValue.class); + response.close(); + return res.getValue(); } - return null; + boolean sendScannedData(PollingStation.ScannedData.Builder scannedData) { + + scannedData.setSerial(serial++) + .setScannerId(scannerID); + + PollingStation.SignedScannedData.Builder signedDataBuilder = PollingStation.SignedScannedData.newBuilder() + .setData(scannedData); + + if (signer != null) { + try { + signer.updateContent(scannedData.build()); + + signedDataBuilder.setScannerSig(signer.sign()); + } catch (SignatureException e) { + throw new RuntimeException(e); + } + } + + Response response = webTarget.request(Constants.MEDIATYPE_PROTOBUF) + .post(Entity.entity(signedDataBuilder.build(), Constants.MEDIATYPE_PROTOBUF)); + BoolValue res = response.readEntity(BoolValue.class); + response.close(); + return res.getValue(); + } + + /** + * Sends the scanned data to the polling station server + * @param scannedBallot + * @return boolean value: true if the data was sent successfully, false otherwise + */ + @Override + public boolean newScan(PollingStation.ScannedBallot scannedBallot) { + PollingStation.ScannedData.Builder scannedData = PollingStation.ScannedData.newBuilder() + .setBallot(scannedBallot); + + return sendScannedData(scannedData); } @Override - public BoolValue reportScanError(PollingStation.ErrorMsg errorMsg, Crypto.Signature errorMsgSignature) { - return null; + public boolean reportError(PollingStation.ScanError scanError) { + PollingStation.ScannedData.Builder scannedData = PollingStation.ScannedData.newBuilder() + .setError(scanError); + + return sendScannedData(scannedData); } + } diff --git a/scanner-api-common/src/main/proto/meerkat/PollingStation.proto b/scanner-api-common/src/main/proto/meerkat/PollingStation.proto index 6fcf2bc..2186241 100644 --- a/scanner-api-common/src/main/proto/meerkat/PollingStation.proto +++ b/scanner-api-common/src/main/proto/meerkat/PollingStation.proto @@ -8,27 +8,32 @@ import "meerkat/crypto.proto"; import "meerkat/voting.proto"; - - // Data sent (out-of-band) by the server that the client will require to set up a connection message ConnectionServerData { // Web-API URL for the server string server_url = 1; // random nonce used for verification of the client. - bytes nonce = 2; + uint64 nonce = 2; } // Data sent by the client in order to set up a connection message ConnectionClientData { - // Key used to identify the client - SignatureVerificationKey scannerPK = 1; + + oneof id { + // Unique ID of the scanner (if not using signatures) + bytes scannerId = 1; + + // Public Key used to sign future reports + // If this is set, the ID is the certificate fingerprint. + SignatureVerificationKey scannerPK = 2; + } // Nonce sent by connection-server - bytes nonce = 2; + // (used to verify pairing) + uint64 nonce = 3; } - message ScannedBallot { bytes channel = 1; @@ -41,6 +46,7 @@ message ScanError { string msg = 1; } + // Container for scanned data message ScannedData { oneof data { @@ -49,6 +55,10 @@ message ScannedData { } uint64 serial = 4; // Serial number of the message bytes scannerId = 5; // hash of the scannerPK - Signature scannerSig = 6; // signature on the serialzed form of data. +} + +message SignedScannedData { + ScannedData data = 1; + Signature scannerSig = 2; // signature on the serialzed form of data. } diff --git a/voting-booth-gui/src/main/java/meerkat/voting/gui/PollingStationServerToyRun.java b/voting-booth-gui/src/main/java/meerkat/voting/gui/PollingStationServerToyRun.java index 7dc37f0..4f45faa 100644 --- a/voting-booth-gui/src/main/java/meerkat/voting/gui/PollingStationServerToyRun.java +++ b/voting-booth-gui/src/main/java/meerkat/voting/gui/PollingStationServerToyRun.java @@ -12,7 +12,7 @@ import java.util.concurrent.Semaphore; */ public class PollingStationServerToyRun { - private PollingStationScanner.Consumer scanner; + private PollingStationScanner.PollingStationServer scanner; private static final String ADDRESS = "http://localhost"; private static final String SUB_ADDRESS = ""; private static final int PORT = 8080; diff --git a/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java b/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java index ce2c9be..4a467ac 100644 --- a/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java +++ b/voting-booth/src/test/java/meerkat/voting/NetworkVirtualPrinterTest.java @@ -32,7 +32,7 @@ import static org.hamcrest.MatcherAssert.assertThat; public class NetworkVirtualPrinterTest { - private PollingStationScanner.Consumer scanner; + private PollingStationScanner.PollingStationServer scanner; private static final String ADDRESS = "http://localhost"; private static final String SUB_ADDRESS = ""; private static final int PORT = 8080;