summaryrefslogtreecommitdiff
path: root/wrappers/java/src
diff options
context:
space:
mode:
authorStevenWdV <stevenwdv@gmail.com>2021-11-29 00:12:42 +0100
committerStevenWdV <stevenwdv@gmail.com>2021-11-29 00:12:42 +0100
commitf463d4c1a550c4b3dfc0be362f0b0a723a88122d (patch)
tree9b85337f1d9eda3d7070cd57d952712cfe2ae6cc /wrappers/java/src
parent60658378f68cc7c67cbea2758c6aef455c115c05 (diff)
Improve Java wrapper: add all tests, link correct libraries, use Maven, add Makefile & GitHub workflow. Fix make clean targets.
Diffstat (limited to 'wrappers/java/src')
-rw-r--r--wrappers/java/src/main/java/nl/eduvpn/common/Discovery.java66
-rw-r--r--wrappers/java/src/main/java/nl/eduvpn/common/VerifyException.java9
-rw-r--r--wrappers/java/src/test/java/nl/eduvpn/common/VerifyTests.java78
3 files changed, 153 insertions, 0 deletions
diff --git a/wrappers/java/src/main/java/nl/eduvpn/common/Discovery.java b/wrappers/java/src/main/java/nl/eduvpn/common/Discovery.java
new file mode 100644
index 0000000..d73a3d2
--- /dev/null
+++ b/wrappers/java/src/main/java/nl/eduvpn/common/Discovery.java
@@ -0,0 +1,66 @@
+package nl.eduvpn.common;
+
+import com.sun.jna.*;
+
+import java.nio.charset.StandardCharsets;
+import java.time.Instant;
+
+public class Discovery {
+ private static final NativeApi discovery = Native.load("eduvpn_verify", NativeApi.class);
+
+ /**
+ * Verifies the signature on the JSON server_list.json/organization_list.json file.
+ * If the function returns the signature is valid for the given file type.
+ *
+ * @param signature .minisig signature file contents.
+ * @param signedJson Signed .json file contents.
+ * @param expectedFileName The file type to be verified, one of {@code "server_list.json"} or {@code "organization_list.json"}.
+ * @param minSignTime Minimum time for signature. Should be set to at least the time in a previously retrieved file.
+ * @throws IllegalArgumentException If {@code expectedFileName} is not one of the allowed values or one of the parameters is empty.
+ * @throws VerifyException If signature verification fails.
+ */
+ public static void verify(byte[] signature, byte[] signedJson, String expectedFileName, Instant minSignTime) throws VerifyException {
+ long err = discovery.Verify(NativeApi.GoSlice.make(signature), NativeApi.GoSlice.make(signedJson),
+ NativeApi.GoSlice.make(expectedFileName.getBytes(StandardCharsets.UTF_8)),
+ minSignTime.getEpochSecond());
+ if (err != 0) {
+ if (err == 1) throw new IllegalArgumentException("Unknown excpectedFileName");
+ throw new VerifyException(err);
+ }
+ }
+
+ /**
+ * Use for testing only, see Go documentation.
+ */
+ // package-private
+ static void insecureTestingSetExtraKey(String keyString) {
+ discovery.InsecureTestingSetExtraKey(NativeApi.GoSlice.make(keyString.getBytes(StandardCharsets.UTF_8)));
+ }
+
+ private interface NativeApi extends Library {
+ @Structure.FieldOrder({"data", "len", "cap"})
+ class GoSlice extends Structure implements Structure.ByValue {
+ public Pointer data;
+ public long len, cap;
+
+ public GoSlice(Pointer data, long len, long cap) {
+ this.data = data;
+ this.len = len;
+ this.cap = cap;
+ }
+
+ public static GoSlice make(byte[] bytes) {
+ Memory memory = new Memory(bytes.length);
+ memory.write(0, bytes, 0, bytes.length);
+ return new GoSlice(memory, bytes.length, bytes.length);
+ }
+ }
+
+ long Verify(GoSlice signatureFileContent, GoSlice signedJson, GoSlice expectedFileName, long minSignTime);
+
+ void InsecureTestingSetExtraKey(GoSlice keyString);
+ }
+
+ private Discovery() {
+ }
+}
diff --git a/wrappers/java/src/main/java/nl/eduvpn/common/VerifyException.java b/wrappers/java/src/main/java/nl/eduvpn/common/VerifyException.java
new file mode 100644
index 0000000..83dffb1
--- /dev/null
+++ b/wrappers/java/src/main/java/nl/eduvpn/common/VerifyException.java
@@ -0,0 +1,9 @@
+package nl.eduvpn.common;
+
+public class VerifyException extends Exception {
+ public final long code; //TODO not use plain long
+
+ public VerifyException(long code) {
+ this.code = code;
+ }
+} \ No newline at end of file
diff --git a/wrappers/java/src/test/java/nl/eduvpn/common/VerifyTests.java b/wrappers/java/src/test/java/nl/eduvpn/common/VerifyTests.java
new file mode 100644
index 0000000..b4767a5
--- /dev/null
+++ b/wrappers/java/src/test/java/nl/eduvpn/common/VerifyTests.java
@@ -0,0 +1,78 @@
+package nl.eduvpn.common;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.Instant;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class VerifyTests {
+ private static final Path testDataDir = Paths.get("../../test_data");
+
+ @SuppressWarnings("OptionalGetWithoutIsPresent")
+ @BeforeAll
+ static void oneTimeSetup() throws IOException {
+ Discovery.insecureTestingSetExtraKey(Files.lines(testDataDir.resolve("dummy/public.key")).reduce((a, b) -> b).get());
+ }
+
+ @Test
+ void testValid() {
+ assertDoesNotThrow(() ->
+ Discovery.verify(
+ Files.readAllBytes(testDataDir.resolve("dummy/server_list.json.minisig")),
+ Files.readAllBytes(testDataDir.resolve("dummy/server_list.json")),
+ "server_list.json",
+ Instant.EPOCH
+ ));
+ }
+
+ @Test
+ void testInvalidSignature() {
+ Assertions.assertEquals(2, assertThrows(VerifyException.class, () ->
+ Discovery.verify(
+ Files.readAllBytes(testDataDir.resolve("dummy/random.txt")),
+ Files.readAllBytes(testDataDir.resolve("dummy/server_list.json")),
+ "server_list.json",
+ Instant.EPOCH
+ )).code);
+ }
+
+ @Test
+ void testWrongKey() {
+ assertEquals(3, assertThrows(VerifyException.class, () ->
+ Discovery.verify(
+ Files.readAllBytes(testDataDir.resolve("dummy/server_list.json.wrong_key.minisig")),
+ Files.readAllBytes(testDataDir.resolve("dummy/server_list.json")),
+ "server_list.json",
+ Instant.EPOCH
+ )).code);
+ }
+
+ @Test
+ void testOldSignature() {
+ assertEquals(4, assertThrows(VerifyException.class, () ->
+ Discovery.verify(
+ Files.readAllBytes(testDataDir.resolve("dummy/server_list.json.minisig")),
+ Files.readAllBytes(testDataDir.resolve("dummy/server_list.json")),
+ "server_list.json",
+ Instant.MAX
+ )).code);
+ }
+
+ @Test
+ void testUnknownExpectedFile() {
+ assertThrows(IllegalArgumentException.class, () ->
+ Discovery.verify(
+ Files.readAllBytes(testDataDir.resolve("dummy/other_list.json.minisig")),
+ Files.readAllBytes(testDataDir.resolve("dummy/other_list.json")),
+ "other_list.json",
+ Instant.EPOCH
+ ));
+ }
+} \ No newline at end of file