summaryrefslogtreecommitdiffstats
path: root/toolkit/components/telemetry/dap/ffi-gtest
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/telemetry/dap/ffi-gtest')
-rw-r--r--toolkit/components/telemetry/dap/ffi-gtest/Cargo.toml20
-rw-r--r--toolkit/components/telemetry/dap/ffi-gtest/PrgAes128_tests.json80
-rw-r--r--toolkit/components/telemetry/dap/ffi-gtest/TestDAPTelemetry.cpp23
-rw-r--r--toolkit/components/telemetry/dap/ffi-gtest/moz.build7
-rw-r--r--toolkit/components/telemetry/dap/ffi-gtest/test.rs230
5 files changed, 360 insertions, 0 deletions
diff --git a/toolkit/components/telemetry/dap/ffi-gtest/Cargo.toml b/toolkit/components/telemetry/dap/ffi-gtest/Cargo.toml
new file mode 100644
index 0000000000..756d93a74e
--- /dev/null
+++ b/toolkit/components/telemetry/dap/ffi-gtest/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "dap_ffi-gtest"
+version = "0.1.0"
+authors = [
+ "Simon Friedberger <simon@mozilla.com>",
+]
+license = "MPL-2.0"
+description = "Tests for Rust code for DAP; mainly encoding and NSS bindings."
+edition = "2021"
+
+[dependencies]
+dap_ffi = { path = "../ffi" }
+hex = { version = "0.4.3", features = ["serde"] }
+prio = {version = "0.9.0", default-features = false }
+serde = { version = "1.0", features = ["derive"] }
+serde_json = { version = "1.0" }
+thin-vec = { version = "0.2.1", features = ["gecko-ffi"] }
+
+[lib]
+path = "test.rs"
diff --git a/toolkit/components/telemetry/dap/ffi-gtest/PrgAes128_tests.json b/toolkit/components/telemetry/dap/ffi-gtest/PrgAes128_tests.json
new file mode 100644
index 0000000000..7227b589c1
--- /dev/null
+++ b/toolkit/components/telemetry/dap/ffi-gtest/PrgAes128_tests.json
@@ -0,0 +1,80 @@
+[
+ {
+ "seed": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ "info_string": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ "buffer1_out": [
+ 73, 12, 252, 221, 214, 131, 103, 213, 8, 125, 53, 152, 93, 163, 78, 35,
+ 181, 41, 221, 100
+ ],
+ "buffer2_out": [
+ 244, 233, 25, 27, 130, 143, 245, 245, 158, 25, 70, 216, 49, 52, 48, 166,
+ 234, 182, 146, 63, 140, 157, 155, 191, 24, 195, 111, 244, 212, 81, 93, 76,
+ 198, 93, 108, 144, 80, 116, 232, 76, 229, 167, 252, 3, 88, 209, 226, 11,
+ 167, 130, 127, 16, 165, 185, 225, 16, 200, 194, 93, 70, 166, 7, 104, 33,
+ 164, 93, 26, 14, 98, 188, 210, 45, 76, 191, 10, 107, 145, 174, 4, 247, 99,
+ 162, 77, 183, 198, 246, 163, 162, 1, 109, 16, 172, 213, 145, 124, 163,
+ 219, 215, 60, 58, 210, 65, 21, 106, 109, 244, 51, 140, 167, 82, 216, 222,
+ 113, 105, 194, 189, 119, 146, 17, 170, 232, 216, 191, 224, 64, 216, 54,
+ 37, 242, 62, 127, 108, 232, 195, 19, 20, 0, 168, 102, 98, 72, 30, 21, 198,
+ 235, 241, 35, 230, 107, 24, 81, 75, 174, 49, 10, 177, 238, 183, 131, 209,
+ 64, 95, 220, 30, 87, 230, 221, 72, 66, 201, 106, 44, 22, 52, 39, 159, 73,
+ 157, 120, 133, 3, 103, 114, 54, 48, 59, 223, 200, 37, 182, 24, 160, 43,
+ 224, 39, 242, 20, 252, 24, 197, 181, 91, 1, 189, 78, 207, 184, 200, 98,
+ 141, 141, 172, 212, 22, 13, 86, 63, 54, 85, 97, 230, 123, 117, 85, 60, 48,
+ 111, 136, 254, 126, 252, 250, 21, 126, 157, 127, 72, 148, 100, 205, 179,
+ 154, 67, 69, 149, 96, 95, 62, 241, 104, 30, 63, 72, 198, 75, 238, 42, 174,
+ 128, 118, 110, 8, 105, 176, 219, 24, 69, 17, 69, 76, 9, 56, 146, 195, 198,
+ 12, 89, 50, 133, 144, 43, 93, 98, 45, 54, 253, 48, 72, 38, 128, 108, 22,
+ 173, 8, 228, 180, 254, 96, 224, 103, 215, 255, 163, 189, 142, 35, 18, 102,
+ 166, 241, 225, 16, 231, 106, 31, 29, 230, 172, 108, 134, 57, 69, 126, 120,
+ 45, 60, 149, 96, 91, 17, 43, 220, 103, 217, 94, 149, 25, 111, 50, 252,
+ 237, 147, 4, 21, 230, 128, 132, 41, 51, 132, 6, 134, 167, 155, 179, 79,
+ 38, 181, 129, 149, 223, 125, 192, 48, 71, 122, 69, 160, 136, 172, 171, 62,
+ 135, 206, 109, 219, 68, 184, 173, 248, 255, 120, 31, 195, 85, 207, 177,
+ 158, 241, 42, 246, 250, 7, 124, 135, 67, 6, 2, 149, 107, 98, 118, 63, 54,
+ 55, 104, 176, 194, 128, 79, 49, 220, 31, 31, 185, 63, 205, 176, 36, 28,
+ 17, 34, 138, 162, 2, 77, 60, 82, 174, 137, 223, 14, 113, 206, 111, 132,
+ 76, 246, 185, 64, 161, 205, 118, 132, 142, 133, 165, 75, 139, 161, 244,
+ 42, 189, 21, 198, 199, 9, 252, 244, 181, 36, 210, 46, 13, 173, 199, 33,
+ 252, 174, 231, 207, 112, 132, 192, 146, 201, 55, 45, 90, 176, 47, 111,
+ 190, 198, 154, 191, 178, 238, 103, 255, 239, 130, 179, 60, 84, 217, 156,
+ 246, 208, 179
+ ]
+ },
+ {
+ "seed": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
+ "info_string": [105, 110, 102, 111, 32, 115, 116, 114, 105, 110, 103],
+ "buffer1_out": [],
+ "buffer2_out": [
+ 204, 243, 190, 112, 76, 152, 33, 130, 173, 41, 97, 233, 121, 90, 136, 170
+ ]
+ },
+ {
+ "seed": [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5],
+ "info_string": [105, 110, 102, 111, 32, 115, 116, 114, 105, 110, 103],
+ "buffer1_out": [],
+ "buffer2_out": [
+ 134, 173, 103, 37, 215, 0, 146, 211, 132, 6, 147, 110, 147, 170, 26, 196
+ ]
+ },
+ {
+ "seed": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
+ "info_string": [110, 110, 102, 111, 32, 115, 116, 114, 105, 110, 103],
+ "buffer1_out": [],
+ "buffer2_out": [
+ 245, 62, 144, 220, 139, 16, 59, 178, 153, 145, 113, 98, 101, 104, 47, 213
+ ]
+ },
+ {
+ "seed": [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
+ "info_string": [],
+ "buffer1_out": [67, 49],
+ "buffer2_out": [108, 157, 199, 13, 12]
+ },
+ {
+ "seed": [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
+ "info_string": [110, 110, 110, 110, 110],
+ "buffer1_out": [152, 11],
+ "buffer2_out": [186, 202, 32, 223, 212]
+ }
+]
diff --git a/toolkit/components/telemetry/dap/ffi-gtest/TestDAPTelemetry.cpp b/toolkit/components/telemetry/dap/ffi-gtest/TestDAPTelemetry.cpp
new file mode 100644
index 0000000000..080224ad99
--- /dev/null
+++ b/toolkit/components/telemetry/dap/ffi-gtest/TestDAPTelemetry.cpp
@@ -0,0 +1,23 @@
+
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "mozilla/DAPTelemetryBindings.h"
+
+using namespace mozilla;
+
+extern "C" void dap_test_prg();
+TEST(DAPTelemetryTests, TestPrg)
+{ dap_test_prg(); }
+
+extern "C" void dap_test_hpke_encrypt();
+TEST(DAPTelemetryTests, TestHpkeEnc)
+{ dap_test_hpke_encrypt(); }
+
+extern "C" void dap_test_encoding();
+TEST(DAPTelemetryTests, TestReportSerialization)
+{ dap_test_encoding(); }
diff --git a/toolkit/components/telemetry/dap/ffi-gtest/moz.build b/toolkit/components/telemetry/dap/ffi-gtest/moz.build
new file mode 100644
index 0000000000..b8444a26d5
--- /dev/null
+++ b/toolkit/components/telemetry/dap/ffi-gtest/moz.build
@@ -0,0 +1,7 @@
+UNIFIED_SOURCES = ["TestDAPTelemetry.cpp"]
+FINAL_LIBRARY = "xul-gtest"
+
+TEST_HARNESS_FILES.gtest += [
+ "../../../../../security/nss/gtests/pk11_gtest/hpke-vectors.json",
+ "PrgAes128_tests.json",
+]
diff --git a/toolkit/components/telemetry/dap/ffi-gtest/test.rs b/toolkit/components/telemetry/dap/ffi-gtest/test.rs
new file mode 100644
index 0000000000..8db79f5f05
--- /dev/null
+++ b/toolkit/components/telemetry/dap/ffi-gtest/test.rs
@@ -0,0 +1,230 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use serde::Deserialize;
+use std::ffi::c_void;
+use std::fs::File;
+use std::io::Cursor;
+
+use thin_vec::ThinVec;
+
+use dap_ffi::prg::PrgAes128Alt;
+use dap_ffi::types::Report;
+
+use prio::codec::{Decode, Encode};
+use prio::vdaf::prg::{Prg, SeedStream};
+
+#[no_mangle]
+pub extern "C" fn dap_test_encoding() {
+ let r = Report::new_dummy();
+ let mut encoded = Vec::<u8>::new();
+ Report::encode(&r, &mut encoded);
+ let decoded = Report::decode(&mut Cursor::new(&encoded)).expect("Report decoding failed!");
+ if r != decoded {
+ println!("Report:");
+ println!("{:?}", r);
+ println!("Encoded Report:");
+ println!("{:?}", encoded);
+ println!("Decoded Report:");
+ println!("{:?}", decoded);
+ panic!("Report changed after encoding & decoding.");
+ }
+}
+
+#[derive(Deserialize, Debug)]
+struct PrgTestCase {
+ seed: [u8; 16],
+ info_string: Vec<u8>,
+ buffer1_out: Vec<u8>,
+ buffer2_out: Vec<u8>,
+}
+
+#[no_mangle]
+pub extern "C" fn dap_test_prg() {
+ let file = File::open("PrgAes128_tests.json").unwrap();
+ let testcases: Vec<PrgTestCase> = serde_json::from_reader(file).unwrap();
+ for testcase in testcases {
+ let mut p = PrgAes128Alt::init(&testcase.seed);
+ p.update(&testcase.info_string);
+ let mut s = p.into_seed_stream();
+ let mut b1 = vec![0u8; testcase.buffer1_out.len()];
+ s.fill(&mut b1);
+ assert_eq!(b1, testcase.buffer1_out);
+ let mut b2 = vec![0u8; testcase.buffer2_out.len()];
+ s.fill(&mut b2);
+ assert_eq!(b2, testcase.buffer2_out);
+ }
+}
+
+extern "C" {
+ pub fn dapHpkeEncrypt(
+ aContext: *mut c_void,
+ aAad: *mut u8,
+ aAadLength: u32,
+ aPlaintext: *mut u8,
+ aPlaintextLength: u32,
+ aOutputShare: &mut ThinVec<u8>,
+ ) -> bool;
+ pub fn dapSetupHpkeContextForTesting(
+ aKey: *const u8,
+ aKeyLength: u32,
+ aInfo: *mut u8,
+ aInfoLength: u32,
+ aPkEm: *const u8,
+ aPkEmLength: u32,
+ aSkEm: *const u8,
+ aSkEmLength: u32,
+ aOutputEncapsulatedKey: &mut ThinVec<u8>,
+ ) -> *mut c_void;
+ pub fn dapDestroyHpkeContext(aContext: *mut c_void);
+}
+
+struct HpkeContext(*mut c_void);
+
+impl Drop for HpkeContext {
+ fn drop(&mut self) {
+ unsafe {
+ dapDestroyHpkeContext(self.0);
+ }
+ }
+}
+
+type Testsuites = Vec<CiphersuiteTest>;
+
+#[derive(Debug, Deserialize)]
+pub struct HexString(#[serde(with = "hex")] Vec<u8>);
+impl AsRef<[u8]> for HexString {
+ fn as_ref(&self) -> &[u8] {
+ &self.0
+ }
+}
+#[derive(Debug, Deserialize)]
+struct CiphersuiteTest {
+ mode: i64,
+ kem_id: i64,
+ kdf_id: i64,
+ aead_id: i64,
+ info: HexString,
+ #[serde(rename = "ikmR")]
+ ikm_r: HexString,
+ #[serde(rename = "ikmE")]
+ ikm_e: HexString,
+ #[serde(rename = "skRm")]
+ sk_r_m: HexString,
+ #[serde(rename = "skEm")]
+ sk_e_m: HexString,
+ #[serde(rename = "pkRm")]
+ pk_r_m: HexString,
+ #[serde(rename = "pkEm")]
+ pk_e_m: HexString,
+ enc: HexString,
+ shared_secret: HexString,
+ key_schedule_context: HexString,
+ secret: HexString,
+ key: HexString,
+ base_nonce: HexString,
+ exporter_secret: HexString,
+ encryptions: Vec<Encryption>,
+ exports: Vec<Export>,
+ psk: Option<HexString>,
+ psk_id: Option<HexString>,
+ ikm_s: Option<HexString>,
+ sk_sm: Option<HexString>,
+ pk_sm: Option<HexString>,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct Encryption {
+ pub aad: HexString,
+ pub ciphertext: HexString,
+ pub nonce: HexString,
+ pub plaintext: HexString,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct Export {
+ pub exporter_context: HexString,
+ #[serde(rename = "L")]
+ pub length: i64,
+ pub exported_value: HexString,
+}
+
+#[no_mangle]
+pub extern "C" fn dap_test_hpke_encrypt() {
+ let file = File::open("hpke-vectors.json").unwrap();
+ let tests: Testsuites = serde_json::from_reader(file).unwrap();
+
+ let mut have_tested = false;
+
+ for (test_idx, test) in tests.into_iter().enumerate() {
+ // Mode must be "Base"
+ if test.mode != 0
+ // KEM must be DHKEM(X25519, HKDF-SHA256)
+ || test.kem_id != 32
+ // KDF must be HKDF-SHA256
+ || test.kdf_id != 1
+ // AEAD must be AES-128-GCM
+ || test.aead_id != 1
+ {
+ continue;
+ }
+
+ have_tested = true;
+
+ let mut pk_r_serialized = test.pk_r_m.0;
+ let mut info = test.info.0;
+ let mut pk_e_serialized = test.pk_e_m.0;
+ let mut sk_e_serialized = test.sk_e_m.0;
+
+ let mut encapsulated_key = ThinVec::<u8>::new();
+
+ let ctx = HpkeContext(unsafe {
+ dapSetupHpkeContextForTesting(
+ pk_r_serialized.as_mut_ptr(),
+ pk_r_serialized.len().try_into().unwrap(),
+ info.as_mut_ptr(),
+ info.len().try_into().unwrap(),
+ pk_e_serialized.as_mut_ptr(),
+ pk_e_serialized.len().try_into().unwrap(),
+ sk_e_serialized.as_mut_ptr(),
+ sk_e_serialized.len().try_into().unwrap(),
+ &mut encapsulated_key,
+ )
+ });
+ if ctx.0.is_null() {
+ panic!("Failed to set up HPKE context.");
+ }
+ if encapsulated_key != test.enc.0 {
+ panic!("Encapsulated key is wrong!");
+ }
+
+ for (encryption_idx, encryption) in test.encryptions.into_iter().enumerate() {
+ let mut encrypted_share = ThinVec::<u8>::new();
+
+ let mut aad = encryption.aad.0.clone();
+ let mut pt = encryption.plaintext.0.clone();
+ unsafe {
+ dapHpkeEncrypt(
+ ctx.0,
+ aad.as_mut_ptr(),
+ aad.len().try_into().unwrap(),
+ pt.as_mut_ptr(),
+ pt.len().try_into().unwrap(),
+ &mut encrypted_share,
+ );
+ }
+
+ if encrypted_share != encryption.ciphertext.0 {
+ println!("Test: {}, Encryption: {}", test_idx, encryption_idx);
+ println!("Expected:");
+ println!("{:?}", encryption.ciphertext.0);
+ println!("Actual:");
+ println!("{:?}", encrypted_share);
+ panic!("Encryption outputs did not match!");
+ }
+ }
+ }
+
+ assert!(have_tested);
+}