diff --git a/Doc/AWS-documentation.md b/Doc/AWS-documentation.md new file mode 100644 index 000000000..351d23cd4 --- /dev/null +++ b/Doc/AWS-documentation.md @@ -0,0 +1,142 @@ +# AWS Bootcamp – Configuring an EC2 Instance + +--- + +## 1. Introduction to AWS + +### What is AWS? +Amazon Web Services (AWS) is a comprehensive cloud computing platform offering a wide range of services, including computing power, storage, networking, databases, analytics, and machine learning. AWS enables organizations and individuals to deploy applications and services without the need for physical hardware. + +### Why Use AWS? +- **Cost Efficiency** – Pay only for the resources you use. +- **Scalability** – Easily scale resources up or down to meet demand. +- **Global Reach** – Deploy resources in multiple geographic regions. +- **Security** – Enterprise-grade security with compliance certifications. + +--- + +## 2. Key AWS Concepts + +- **Region** – A geographical area containing AWS data centers. Selecting the correct region can optimize performance, reduce costs, and ensure compliance with data regulations. +- **Availability Zone (AZ)** – One or more isolated data centers within a region, providing redundancy and fault tolerance. +- **Service** – An AWS feature or capability (e.g., EC2 for compute, S3 for storage). +- **EC2 (Elastic Compute Cloud)** – A service that provides resizable virtual servers. +- **Instance** – A single virtual server running on AWS EC2. +- **AMI (Amazon Machine Image)** – A pre-configured template containing an operating system and optional software, used to launch an EC2 instance. + +--- + +## 3. Prerequisites + +- An active AWS account ([Create one here](https://aws.amazon.com)) +- A laptop or desktop computer with internet access +- For connection via terminal: basic familiarity with command-line tools (optional) + +--- + +## 4. Step-by-Step: Launching a Standard EC2 Instance + +**Objective:** Deploy a virtual server on AWS. + +### Step 1: Log in to the AWS Management Console +1. Navigate to [AWS Console](https://aws.amazon.com/console) +2. Sign in using your AWS credentials. + +### Step 2: Access the EC2 Service +1. In the search bar at the top of the AWS Console, type `EC2`. +2. Select **EC2** from the search results to access the EC2 dashboard. + +### Step 3: Launch a New Instance +1. Click **Launch Instance**. +2. Under **Name and tags**, provide a descriptive name for your instance (e.g., `myCertifierServer`). + +### Step 4: Select an AMI (Operating System) +- Recommended: **Amazon Linux 2 AMI** or **Ubuntu 20.04 LTS**. + +### Step 5: Choose an Instance Type +- For initial testing and free-tier eligibility, select **t2.micro**. + +### Step 6: Create a Key Pair (For Secure Login) +1. Under **Key pair (login)**, select **Create new key pair**. +2. Provide a name (e.g., `mykeypair`). +3. Choose file format: + - **PEM** for macOS/Linux + - **PPK** for Windows (PuTTY) +4. Download the file and store it securely — this is required for SSH access. + +### Step 7: Configure Network Settings (Security Group) +1. Allow **SSH (port 22)** access from your IP address for secure terminal access. +2. If hosting a website, also allow **HTTP (port 80)** and **HTTPS (port 443)**. + +### Step 8: Launch the Instance +- Review all configurations and click **Launch Instance**. +- Wait until the **Instance state** changes to **Running**. + +--- + +## 5. Connecting to Your Instance + +### Locate the Public IP Address +1. From the EC2 dashboard, select your instance. +2. Under **Details**, locate the **Public IPv4 address**. + +### macOS/Linux Connection +```bash +chmod 400 mykeypair.pem +ssh -i mykeypair.pem ec2-user@ +``` +*(Replace `` with your instance’s public IP address)* + +### Windows Connection +- Convert `.pem` to `.ppk` using PuTTYgen. +- Open PuTTY, enter your instance’s public IP, and configure the private key in the **SSH > Auth** section. +- Click **Open** to initiate the connection. + +--- + +## 6. Managing Your Instance +- **Stop** – Powers off the instance without deleting it (no compute charges while stopped). +- **Start** – Powers the instance back on. +- **Terminate** – Permanently deletes the instance. + +--- + +## 7. Advanced Topic: Secure Encrypted Virtualization (SEV) + +### Overview +SEV (Secure Encrypted Virtualization) is an AMD technology that encrypts the memory of an EC2 instance, ensuring that even the hypervisor cannot access it. This feature is part of AWS’s Confidential Computing offerings. + +### Benefits of SEV +- Enhanced data security during processing +- Protection against unauthorized access, even from privileged system components +- Ideal for industries with strict compliance requirements, such as finance and healthcare + +### Launching an SEV-Enabled Instance +1. Follow the same procedure as launching a standard EC2 instance. +2. In **Step 5 (Choose Instance Type)**, select an AMD SEV-compatible instance type: + - General Purpose: `m6a` + - Compute Optimized: `c6a` + - Memory Optimized: `r6a` + +### Verifying SEV in Your Instance +Once connected via SSH, run: +```bash +dmesg | grep -i sev +lscpu | grep -i sev +``` +If SEV is enabled, references to SEV will appear in the output. + +--- + +## 8. Best Practices +- Choose the AWS Region closest to your users for optimal latency and compliance. +- Secure AWS credentials and enable MFA. +- Stop or terminate unused instances to avoid unnecessary charges. +- Use IAM roles rather than embedding credentials in applications. + +--- + +## 9. References +- [AWS EC2 Documentation](https://docs.aws.amazon.com/ec2/) +- [AWS Free Tier Information](https://aws.amazon.com/free) +- [AWS AMD SEV Overview](https://aws.amazon.com/ec2/amd/) diff --git a/sample_apps/simple_app_java/app/build.gradle b/sample_apps/simple_app_java/app/build.gradle new file mode 100644 index 000000000..6089539d8 --- /dev/null +++ b/sample_apps/simple_app_java/app/build.gradle @@ -0,0 +1,57 @@ +plugins { + id 'com.android.application' +} + +android { + namespace 'com.example.certifier' + compileSdk 35 + + defaultConfig { + applicationId "com.example.certifier" + minSdk 24 + targetSdk 35 + versionCode 1 + versionName "1.0" + + // NDK ABIs + ndk { abiFilters "arm64-v8a" } // add "x86_64" if you want emulator + + // CMake/NDK config + externalNativeBuild { + cmake { + cppFlags "-std=c++17 -fexceptions -frtti" + // When you want to link the real Certifier repo directly: + // arguments "-DCERTIFIER_ROOT=/absolute/path/to/certifier-framework-for-confidential-computing" + } + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), + 'proguard-rules.pro' + } + debug { minifyEnabled false } + } + + // Point to CMakeLists.txt + externalNativeBuild { + cmake { path "src/main/cpp/CMakeLists.txt" } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + buildFeatures { + buildConfig true + } +} + +dependencies { + implementation 'androidx.appcompat:appcompat:1.7.0' + implementation 'com.google.android.material:material:1.12.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' +} diff --git a/sample_apps/simple_app_java/app/proguard-rules.pro b/sample_apps/simple_app_java/app/proguard-rules.pro new file mode 100644 index 000000000..37c900a65 --- /dev/null +++ b/sample_apps/simple_app_java/app/proguard-rules.pro @@ -0,0 +1 @@ +# will remain empty for now diff --git a/sample_apps/simple_app_java/app/src/main/AndroidManifest.xml b/sample_apps/simple_app_java/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..233cb7049 --- /dev/null +++ b/sample_apps/simple_app_java/app/src/main/AndroidManifest.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + diff --git a/sample_apps/simple_app_java/app/src/main/cpp/CMakeLists.txt b/sample_apps/simple_app_java/app/src/main/cpp/CMakeLists.txt new file mode 100644 index 000000000..b3381bbdf --- /dev/null +++ b/sample_apps/simple_app_java/app/src/main/cpp/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.18) +project(certifier_android LANGUAGES C CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +add_library(certifier_native SHARED + native-lib.cpp + simple_core_android.cc + # Later: add Certifier framework sources here or via CERTIFIER_ROOT +) + +find_library(log-lib log) +target_link_libraries(certifier_native ${log-lib}) +target_compile_options(certifier_native PRIVATE -fexceptions -frtti) diff --git a/sample_apps/simple_app_java/app/src/main/cpp/native-lib.cpp b/sample_apps/simple_app_java/app/src/main/cpp/native-lib.cpp new file mode 100644 index 000000000..d28b98b57 --- /dev/null +++ b/sample_apps/simple_app_java/app/src/main/cpp/native-lib.cpp @@ -0,0 +1,30 @@ +#include +#include + +std::string run_certifier_simple(const std::string& workDir, + const std::string& mode, + const std::string& host, + int port); + +extern "C" +JNIEXPORT jstring JNICALL +Java_org_certifier_examples_SimpleApp_runCertifierNative( + JNIEnv* env, jclass /*clazz*/, + jstring jWorkDir, jstring jMode, jstring jHost, jint jPort) { + + const char* w = env->GetStringUTFChars(jWorkDir, nullptr); + const char* m = env->GetStringUTFChars(jMode, nullptr); + const char* h = env->GetStringUTFChars(jHost, nullptr); + + std::string work = w ? w : ""; + std::string mode = m ? m : ""; + std::string host = h ? h : ""; + int port = static_cast(jPort); + + if (w) env->ReleaseStringUTFChars(jWorkDir, w); + if (m) env->ReleaseStringUTFChars(jMode, m); + if (h) env->ReleaseStringUTFChars(jHost, h); + + std::string result = run_certifier_simple(work, mode, host, port); + return env->NewStringUTF(result.c_str()); +} diff --git a/sample_apps/simple_app_java/app/src/main/cpp/simple_core_android.cc b/sample_apps/simple_app_java/app/src/main/cpp/simple_core_android.cc new file mode 100644 index 000000000..a7278b5fe --- /dev/null +++ b/sample_apps/simple_app_java/app/src/main/cpp/simple_core_android.cc @@ -0,0 +1,24 @@ +#include +#include +#include + +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "CertifierJNI", __VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "CertifierJNI", __VA_ARGS__) + +// Later you'll include Certifier headers and call its API. +// #include "..." // from your local copy or from CERTIFIER_ROOT/include + +std::string run_certifier_simple(const std::string& workDir, + const std::string& mode, + const std::string& host, + int port) { + LOGI("run_certifier_simple(workDir=%s, mode=%s, host=%s, port=%d)", + workDir.c_str(), mode.c_str(), host.c_str(), port); + + // TODO: Copy assets to workDir (policy/keys), then call TrustManager, etc. + std::ostringstream out; + out << "Certifier native OK\n" + << "mode=" << mode << " host=" << host << " port=" << port << "\n" + << "workDir=" << workDir; + return out.str(); +} diff --git a/sample_apps/simple_app_java/app/src/main/java/com/example/certifier/MainActivity.java b/sample_apps/simple_app_java/app/src/main/java/com/example/certifier/MainActivity.java new file mode 100644 index 000000000..d3692fccc --- /dev/null +++ b/sample_apps/simple_app_java/app/src/main/java/com/example/certifier/MainActivity.java @@ -0,0 +1,22 @@ +package com.example.certifier; + +import android.os.Bundle; +import android.widget.TextView; +import androidx.appcompat.app.AppCompatActivity; +import org.certifier.examples.SimpleApp; + +public class MainActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + String workDir = getFilesDir().getAbsolutePath(); // place assets here later if needed + String result = SimpleApp.runCertifier(workDir); // default client 127.0.0.1:8080 + + TextView tv = new TextView(this); + tv.setTextSize(16f); + tv.setPadding(32, 64, 32, 32); + tv.setText(result); + setContentView(tv); + } +} diff --git a/sample_apps/simple_app_java/app/src/main/java/org/certifier/SecureAuthenticatedChannel.java b/sample_apps/simple_app_java/app/src/main/java/org/certifier/SecureAuthenticatedChannel.java new file mode 100644 index 000000000..f92aaadbf --- /dev/null +++ b/sample_apps/simple_app_java/app/src/main/java/org/certifier/SecureAuthenticatedChannel.java @@ -0,0 +1,37 @@ +package org.certifier; + +import java.nio.charset.StandardCharsets; + +public class SecureAuthenticatedChannel { + static { + System.loadLibrary("certifier_jni"); + } + + public SecureAuthenticatedChannel() {} + + public native void close(); + public native int read(byte[] buffer); // returns bytes read + public native int write(byte[] data); // returns bytes written + public native boolean init_client_ssl(String serverAddr, int port); + + private static native int cf_channel_peer_id(long nativePtr, byte[] out, int outLen); + private static native int cf_channel_peer_cert(long nativePtr, byte[] out, int outLen); + + private transient long swigCPtr; + + public String getPeerId() { + byte[] buf = new byte[256]; + int n = cf_channel_peer_id(this.swigCPtr, buf, buf.length); + if (n <= 0) return ""; + return new String(buf, 0, n, StandardCharsets.UTF_8); + } + + public byte[] getPeerCert() { + byte[] buf = new byte[4096]; + int n = cf_channel_peer_cert(this.swigCPtr, buf, buf.length); + if (n <= 0) return new byte[0]; + byte[] out = new byte[n]; + System.arraycopy(buf, 0, out, 0, n); + return out; + } +} diff --git a/sample_apps/simple_app_java/app/src/main/java/org/certifier/Store.java b/sample_apps/simple_app_java/app/src/main/java/org/certifier/Store.java new file mode 100644 index 000000000..0bee79600 --- /dev/null +++ b/sample_apps/simple_app_java/app/src/main/java/org/certifier/Store.java @@ -0,0 +1,18 @@ +package org.certifier; + +public class Store { + static { + System.loadLibrary("certifier_jni"); + } + + public Store() {} + + public native long get_num_entries(); + public native int find_entry(String tag, String type); + public native String tag(long ent); + public native String type(long ent); + public native long get_entry(long ent); + public native boolean delete_entry(long ent); + public native boolean update_or_insert(String tag, String type, String value); + public native void print(); +} diff --git a/sample_apps/simple_app_java/app/src/main/java/org/certifier/TrustManager.java b/sample_apps/simple_app_java/app/src/main/java/org/certifier/TrustManager.java new file mode 100644 index 000000000..a5c406ab0 --- /dev/null +++ b/sample_apps/simple_app_java/app/src/main/java/org/certifier/TrustManager.java @@ -0,0 +1,34 @@ +package org.certifier; + +public class TrustManager { + static { + System.loadLibrary("certifier_jni"); // built from CMake + } + + // Native C++ bound via SWIG + public TrustManager() { } + + public native boolean init_policy_key(); + public native boolean initialize_enclave(); + public native boolean cold_init(); + public native boolean warm_restart(); + public native void print_trust_data(); + public native void clear_sensitive_data(); + + // Shimmed flags (1 = true, 0 = false) + private static native int cf_tm_auth_key_initialized(long nativePtr); + private static native int cf_tm_primary_admissions_cert_valid(long nativePtr); + + // SWIG exposes the native pointer in a hidden field for directors; name may vary by SWIG version. + // Typically it’s something like swigCPtr. Adjust if needed. + private transient long swigCPtr; + + // Accessors matching mentor’s ask: + public boolean isAuthKeyInitialized() { + return cf_tm_auth_key_initialized(this.swigCPtr) == 1; + } + + public boolean isPrimaryAdmissionsCertValid() { + return cf_tm_primary_admissions_cert_valid(this.swigCPtr) == 1; + } +} diff --git a/sample_apps/simple_app_java/app/src/main/java/org/certifier/examples/SimpleApp.java b/sample_apps/simple_app_java/app/src/main/java/org/certifier/examples/SimpleApp.java new file mode 100644 index 000000000..143bd4afa --- /dev/null +++ b/sample_apps/simple_app_java/app/src/main/java/org/certifier/examples/SimpleApp.java @@ -0,0 +1,144 @@ +package org.certifier.examples; + +import org.certifier.TrustManager; +import org.certifier.SecureAuthenticatedChannel; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.charset.StandardCharsets; + +/** + * Desktop usage: + * java org.certifier.examples.SimpleApp --mode=server --port=8080 + * java org.certifier.examples.SimpleApp --mode=client --host=127.0.0.1 --port=8080 + * + * Android usage (no command line): + * // In your Activity: + * String workDir = getFilesDir().getAbsolutePath(); + * String result = org.certifier.examples.SimpleApp.runCertifier(workDir); + * // Or choose explicit mode/host/port: + * // String result = org.certifier.examples.SimpleApp.runCertifier(workDir, "client", "127.0.0.1", 8080); + */ +public class SimpleApp { + + static { System.loadLibrary("certifier_native"); } + public static native String runCertifierNative(String workDir, String mode, String host, int port); + public static String runCertifier(String workDir) { + return runCertifierNative(workDir, "client", "127.0.0.1", 8080); + } + public static String runCertifier(String workDir, String mode, String host, int port) { + return runCertifierNative(workDir, mode, host, port); + } + + // Loads your NDK shared library (built via CMake). + // Ensure add_library(...) name in CMakeLists.txt matches "certifier_native". + static { System.loadLibrary("certifier_native"); } + + /** + * JNI entry (implementation in C++): run the Certifier workflow. + * You can route to native-only logic, or have native call back into Java as needed. + */ + public static native String runCertifierNative(String workDir, String mode, String host, int port); + + /** + * Android-friendly convenience: default to client:127.0.0.1:8080. + * Calls the JNI implementation above. + */ + public static String runCertifier(String workDir) { + return runCertifierNative(workDir, "client", "127.0.0.1", 8080); + } + + /** + * Android-friendly convenience with explicit options. + */ + public static String runCertifier(String workDir, String mode, String host, int port) { + return runCertifierNative(workDir, mode, host, port); + } + + // ----------------------------- Desktop entrypoint ----------------------------- + + public static void main(String[] args) throws Exception { + String mode = "client"; + String host = "127.0.0.1"; + int port = 8080; + + for (int i = 0; i < args.length; i++) { + if (args[i].startsWith("--mode=")) mode = args[i].substring(7); + else if (args[i].startsWith("--host=")) host = args[i].substring(7); + else if (args[i].startsWith("--port=")) port = Integer.parseInt(args[i].substring(7)); + } + + if (mode.equals("server")) { + runServer(port); + } else { + runClient(host, port); + } + } + + // ----------------------------- Original logic ----------------------------- + + private static void runServer(int port) throws Exception { + TrustManager tm = new TrustManager(); + if (!tm.init_policy_key() || !tm.initialize_enclave()) { + System.err.println("TrustManager init failed"); + return; + } + // First-time cold init, then warm restarts subsequently as needed + if (!tm.cold_init()) { + System.err.println("cold_init() failed"); + return; + } + tm.print_trust_data(); + System.out.println("AuthKeyInitialized=" + tm.isAuthKeyInitialized() + + ", PrimaryAdmissionsCertValid=" + tm.isPrimaryAdmissionsCertValid()); + + // Demo plaintext accept loop; replace with secure server path later. + try (ServerSocket ss = new ServerSocket(port)) { + System.out.println("[Server] Listening on " + port); + try (Socket s = ss.accept()) { + System.out.println("[Server] Connection from " + s.getRemoteSocketAddress()); + BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream(), StandardCharsets.UTF_8)); + String line = br.readLine(); + System.out.println("[Server] Received: " + line); + s.getOutputStream().write(("ACK:" + line + "\n").getBytes(StandardCharsets.UTF_8)); + } + } + + tm.clear_sensitive_data(); + } + + private static void runClient(String host, int port) throws Exception { + TrustManager tm = new TrustManager(); + if (!tm.init_policy_key() || !tm.initialize_enclave()) { + System.err.println("TrustManager init failed"); + return; + } + if (!tm.warm_restart()) { + System.err.println("warm_restart() failed (try cold_init() once on first run)"); + return; + } + tm.print_trust_data(); + + SecureAuthenticatedChannel ch = new SecureAuthenticatedChannel(); + if (!ch.init_client_ssl(host, port)) { + System.err.println("init_client_ssl failed"); + return; + } + + System.out.println("[Client] PeerId=" + ch.getPeerId()); + byte[] cert = ch.getPeerCert(); + System.out.println("[Client] PeerCertLen=" + cert.length); + + byte[] msg = "Hello Secure World!\n".getBytes(StandardCharsets.UTF_8); + ch.write(msg); + + byte[] buf = new byte[1024]; + int n = ch.read(buf); + System.out.println("[Client] Read: " + new String(buf, 0, n, StandardCharsets.UTF_8)); + ch.close(); + + tm.clear_sensitive_data(); + } +} diff --git a/sample_apps/simple_app_java/build.gradle b/sample_apps/simple_app_java/build.gradle new file mode 100644 index 000000000..48978475f --- /dev/null +++ b/sample_apps/simple_app_java/build.gradle @@ -0,0 +1,3 @@ +plugins { + id 'com.android.application' version '8.5.2' apply false +} diff --git a/sample_apps/simple_app_java/gradle.properties b/sample_apps/simple_app_java/gradle.properties new file mode 100644 index 000000000..57e2770b5 --- /dev/null +++ b/sample_apps/simple_app_java/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8 +android.useAndroidX=true +android.nonTransitiveRClass=true diff --git a/sample_apps/simple_app_java/instructions.md b/sample_apps/simple_app_java/instructions.md new file mode 100644 index 000000000..b65dcca5e --- /dev/null +++ b/sample_apps/simple_app_java/instructions.md @@ -0,0 +1,345 @@ + +# Java Simple Example (SWIG/JNI) — Build & Run Guide + +This is a **copy‑pasteable** guide to build and run the Java port of the Certifier Framework’s `simple_app`, using **SWIG + JNI**. It avoids hardcoded paths by auto‑detecting include/library directories and passing them to SWIG & CMake. It also includes the exact **run commands** for the Java server and client. + +> Works on Linux/macOS or Windows via **WSL**. For pure Windows (MSVC), see the notes under **Troubleshooting** about `native/build/Debug` and `.dll` paths. + +--- + +## Overview — What you’ll do + +1. Build the Certifier C++ repo (so headers/libs exist). +2. Auto‑detect JNI + Certifier include/lib paths (`native/detect_paths.sh`). +3. Generate SWIG wrappers for `TrustManager` and `SecureAuthenticatedChannel`. +4. Build the JNI shared library with CMake (`libcertifier_jni.so`/`.dylib`/`.dll`). +5. Run the **Java server** and **Java client** with Gradle. + +> If you’re starting from scratch, also drop in the `CMakeLists.txt`, `cf_shims.h/.cc`, and the SWIG `.i` files provided in the repo or in the “Appendix” below. + +--- + +## Prerequisites + +### Ubuntu / WSL +```bash +sudo apt update +sudo apt install -y build-essential cmake swig openjdk-17-jdk libssl-dev protobuf-compiler +``` + +### macOS (Homebrew) +```bash +brew install cmake swig openjdk@17 openssl protobuf +``` + +Ensure `JAVA_HOME` points to your JDK 17 (the detection script tries to auto‑find it if unset). + +--- + +## Project layout (assumed) +``` +/ + native/ # SWIG .i files, shims, CMakeLists.txt, detect_paths.sh + app/ # Java sources & Gradle build files +``` + +--- + +## 1) Build the Certifier C++ project (once) +Follow the upstream instructions to build the C++ libraries and headers. The JNI build below links against those libs (we’ll discover them automatically). + +--- + +## 2) Auto‑detect paths + +From the **repo root** (the directory that contains `native/` and `app/`): + +```bash +chmod +x native/detect_paths.sh +./native/detect_paths.sh +source paths.env +``` + +This writes `paths.env` with: +- `CERTIFIER_INC1/2/3` — include roots for Certifier headers +- `JNI_INC1/2` — JNI header folders (from `JAVA_HOME`) +- `CERTIFIER_LIBDIR` — a candidate folder containing `lib*.a`/`lib*.so` + +If you move repos or switch JDKs later, re‑run the script. + +--- + +## 3) Generate SWIG wrappers + +```bash +cd native +source ../paths.env + +# TrustManager +swig -c++ -java -package org.certifier \ + -outdir ../app/src/main/java/org/certifier \ + -I"$CERTIFIER_INC1" -I"$CERTIFIER_INC2" ${CERTIFIER_INC3:+-I"$CERTIFIER_INC3"} \ + trust_manager.i + +# SecureAuthenticatedChannel +swig -c++ -java -package org.certifier \ + -outdir ../app/src/main/java/org/certifier \ + -I"$CERTIFIER_INC1" -I"$CERTIFIER_INC2" ${CERTIFIER_INC3:+-I"$CERTIFIER_INC3"} \ + secure_authenticated_channel.i +``` + +> Because we pass `-I` include flags, your `.i` files should use **relative** includes like +> `#include "trust_manager/trust_manager.h"` rather than absolute paths. + +--- + +## 4) Build the JNI shared library + +```bash +# still under /native +cmake -B build -S . +cmake --build build -j +``` +You should see a library named roughly **`libcertifier_jni.so`** (Linux/WSL), **`libcertifier_jni.dylib`** (macOS), or **`certifier_jni.dll`** (Windows). + +> If linking fails with “undefined reference…”, scroll down to **Troubleshooting → Linker errors** and update the list of libraries in `native/CMakeLists.txt` to match what your build produced. + +--- + +## 5) Configure Gradle to find the JNI library + +Open `app/build.gradle` and ensure it contains: + +```gradle +plugins { + id 'application' +} + +repositories { mavenCentral() } +dependencies { } + +application { + // Entry point (adjust if your package/class name differs) + mainClass = 'org.certifier.examples.SimpleApp' +} + +tasks.run { + // Make sure this folder actually contains certifier_jni.{so|dylib|dll} + jvmArgs "-Djava.library.path=${projectDir}/../native/build" +} +``` + +**Windows/MSVC note:** if CMake places binaries under `native/build/Debug` (or `Release`), change the path to that folder. + +--- + +## 6) Run the Java app + +Open **two terminals**. + +### Terminal A — Server +```bash +cd app +gradle run --args="--mode=server --port=8080" +``` + +### Terminal B — Client +```bash +cd app +gradle run --args="--mode=client --host=127.0.0.1 --port=8080" +``` + +**Expected output** +- **Server:** trust init lines, flags (`AuthKeyInitialized`, `PrimaryAdmissionsCertValid`), “Listening on 8080…”, “Received: Hello Secure World!” +- **Client:** `init_client_ssl(...) OK`, `PeerId=...`, `PeerCertLen=NNNN`, “Read: ACK: Hello Secure World!” + +Success checklist: +- No `UnsatisfiedLinkError`. +- Client shows a non‑zero `PeerCertLen` (TLS builds). +- Client receives `ACK: Hello Secure World!`. + +--- + +## Troubleshooting + +### UnsatisfiedLinkError: `no certifier_jni` +Java can’t find the JNI library. +- Verify the file exists: `ls native/build/*certifier_jni*` (or `native/build/Debug/*certifier_jni*` on MSVC). +- Update one line in `app/build.gradle`: + ```gradle + tasks.run { jvmArgs "-Djava.library.path=${projectDir}/../native/build" } + ``` + (Change to `../native/build/Debug` if that’s where the binary is.) + +### SWIG can’t find headers +- Re‑run the detector and re‑source the env file: + ```bash + ./native/detect_paths.sh && source paths.env + ``` +- Ensure your `swig` command includes `-I"$CERTIFIER_INC1"` `-I"$CERTIFIER_INC2"` (and `INC3` if present). + +### Linker errors (undefined references) +- List the actual libs and match names in `native/CMakeLists.txt` (drop `lib` prefix and extension): + ```bash + ls -1 "$CERTIFIER_LIBDIR"/lib* + ``` +- Then edit the link line: + ```cmake + target_link_libraries(certifier_jni PRIVATE + trust_manager + secure_authenticated_channel + certifier_core + ssl crypto protobuf pthread # keep/remove per your platform + ) + ``` + On macOS, you usually don’t need `pthread` explicitly; on Windows/MSVC, you may need `ws2_32 bcrypt` instead of `ssl/crypto/pthread`. + +### Port already in use +- Change the port for the server and match it on the client: + ```bash + gradle run --args="--mode=server --port=9090" + gradle run --args="--mode=client --host=127.0.0.1 --port=9090" + ``` + +--- + +## Appendix A — Minimal `native/CMakeLists.txt` (drop‑in) + +```cmake +cmake_minimum_required(VERSION 3.16) +project(certifier_jni LANGUAGES C CXX) +set(CMAKE_CXX_STANDARD 17) + +# Env vars (from detect_paths.sh) +set(CERTIFIER_INC1 $ENV{CERTIFIER_INC1}) +set(CERTIFIER_INC2 $ENV{CERTIFIER_INC2}) +set(CERTIFIER_INC3 $ENV{CERTIFIER_INC3}) +set(JNI_INC1 $ENV{JNI_INC1}) +set(JNI_INC2 $ENV{JNI_INC2}) +set(CERTIFIER_LIBDIR $ENV{CERTIFIER_LIBDIR}) + +include_directories(${JNI_INC1} ${JNI_INC2}) +if (EXISTS "${CERTIFIER_INC1}") include_directories(${CERTIFIER_INC1}) endif() +if (EXISTS "${CERTIFIER_INC2}") include_directories(${CERTIFIER_INC2}) endif() +if (EXISTS "${CERTIFIER_INC3}") include_directories(${CERTIFIER_INC3}) endif() + +add_library(certifier_jni SHARED + cf_shims.cc + trust_manager_wrap.cxx + secure_authenticated_channel_wrap.cxx +) + +if (EXISTS "${CERTIFIER_LIBDIR}") + link_directories(${CERTIFIER_LIBDIR}) +endif() + +# Adjust these names to match your build output (see: ls -1 ${CERTIFIER_LIBDIR}/lib*) +target_link_libraries(certifier_jni PRIVATE + trust_manager + secure_authenticated_channel + certifier_core +) + +if(APPLE) + target_link_libraries(certifier_jni PRIVATE ssl crypto protobuf) +elseif(UNIX) + target_link_libraries(certifier_jni PRIVATE ssl crypto protobuf pthread dl) +elseif(WIN32) + target_link_libraries(certifier_jni PRIVATE ws2_32 bcrypt) +endif() + +set_target_properties(certifier_jni PROPERTIES OUTPUT_NAME "certifier_jni") +``` + +--- + +## Appendix B — `native/detect_paths.sh` (drop‑in) + +```bash +#!/usr/bin/env bash +set -euo pipefail + +# Repo root +if git rev-parse --show-toplevel >/dev/null 2>&1; then + CERTIFIER_ROOT="$(git rev-parse --show-toplevel)" +else + CERTIFIER_ROOT="$PWD" +fi + +# Key headers +TM_H="$(find "$CERTIFIER_ROOT" -type f -name 'trust_manager.h' | head -n1 || true)" +CH_H="$(find "$CERTIFIER_ROOT" -type f -name 'secure_authenticated_channel*.h' | head -n1 || true)" +STORE_H="$(find "$CERTIFIER_ROOT" -type f -name 'store.h' | head -n1 || true)" + +if [[ -z "${TM_H:-}" || -z "${CH_H:-}" ]]; then + echo "ERROR: Could not find trust_manager.h or secure_authenticated_channel*.h under $CERTIFIER_ROOT" + exit 1 +fi + +# Compute include roots +inc_root_of () { python3 - <<'PY' +import os, sys +h = sys.argv[1]; d = os.path.dirname(h) +print(os.path.dirname(d)) +PY +} +CERTIFIER_INC1="$(inc_root_of "$TM_H")" +CERTIFIER_INC2="$(inc_root_of "$CH_H")" +CERTIFIER_INC3=""; [[ -n "${STORE_H:-}" ]] && CERTIFIER_INC3="$(inc_root_of "$STORE_H")" + +# JNI +if [[ -z "${JAVA_HOME:-}" ]]; then + for J in /usr/lib/jvm/java-21* /usr/lib/jvm/java-17* /usr/lib/jvm/*; do + [[ -d "$J/include" ]] && JAVA_HOME="$J" && break + done +fi +[[ -z "${JAVA_HOME:-}" ]] && { echo "ERROR: set JAVA_HOME to a JDK (17+)."; exit 1; } +JNI_INC1="$JAVA_HOME/include" +case "$(uname -s)" in + Linux) JNI_INC2="$JAVA_HOME/include/linux" ;; + Darwin) JNI_INC2="$JAVA_HOME/include/darwin" ;; + *) JNI_INC2="$JAVA_HOME/include/linux" ;; +esac + +# Lib dir guess +CERTIFIER_LIBDIR="$(find "$CERTIFIER_ROOT" -type d -name lib | head -n1 || true)" + +cat > paths.env < +#include +#include +#include + +// ---------- Detection helpers (C++17) ---------- + +template +struct has_auth_key_initialized : std::false_type {}; +template +struct has_auth_key_initialized().auth_key_initialized())>> : std::true_type {}; + +template +struct has_is_auth_key_initialized : std::false_type {}; +template +struct has_is_auth_key_initialized().is_auth_key_initialized())>> : std::true_type {}; + +template +struct has_primary_admissions_cert_valid : std::false_type {}; +template +struct has_primary_admissions_cert_valid().primary_admissions_cert_valid())>> : std::true_type {}; + +template +struct has_peer_id : std::false_type {}; +template +struct has_peer_id().peer_id())>> : std::true_type {}; + +template +struct has_peer_id_str : std::false_type {}; +template +struct has_peer_id_str().peer_id_str())>> : std::true_type {}; + +template +struct has_peer_cert_der : std::false_type {}; +template +struct has_peer_cert_der().peer_cert_der())>> : std::true_type {}; + +template +struct has_peer_cert_pem : std::false_type {}; +template +struct has_peer_cert_pem().peer_cert_pem())>> : std::true_type {}; + +static int copy_str_to_out(const std::string& s, char* out, int out_len) { + if (!out || out_len <= 0) return -1; + int n = static_cast(s.size()); + if (n > out_len) n = out_len; + std::memcpy(out, s.data(), n); + return n; +} + +static int copy_bytes_to_out(const std::string& s, unsigned char* out, int out_len) { + if (!out || out_len <= 0) return -1; + int n = static_cast(s.size()); + if (n > out_len) n = out_len; + std::memcpy(out, s.data(), n); + return n; +} + +// ---------- TrustManager flags ---------- + +int cf_tm_auth_key_initialized(TrustManager* tm) { + if (!tm) return 0; + if constexpr (has_auth_key_initialized::value) { + return tm->auth_key_initialized() ? 1 : 0; + } else if constexpr (has_is_auth_key_initialized::value) { + return tm->is_auth_key_initialized() ? 1 : 0; + } else { + // Unknown API; default to false + return 0; + } +} + +int cf_tm_primary_admissions_cert_valid(TrustManager* tm) { + if (!tm) return 0; + if constexpr (has_primary_admissions_cert_valid::value) { + return tm->primary_admissions_cert_valid() ? 1 : 0; + } else { + // Unknown API; default to false + return 0; + } +} + +// ---------- Channel peer info ---------- + +int cf_channel_peer_id(SecureAuthenticatedChannel* ch, char* out_buf, int out_buf_len) { + if (!ch) return -1; + if constexpr (has_peer_id::value) { + auto id = ch->peer_id(); // expect std::string + return copy_str_to_out(id, out_buf, out_buf_len); + } else if constexpr (has_peer_id_str::value) { + auto id = ch->peer_id_str(); // alternative name + return copy_str_to_out(id, out_buf, out_buf_len); + } else { + return -1; + } +} + +int cf_channel_peer_cert(SecureAuthenticatedChannel* ch, unsigned char* out_buf, int out_buf_len) { + if (!ch) return -1; + if constexpr (has_peer_cert_der::value) { + auto cert = ch->peer_cert_der(); // expect DER bytes in std::string + return copy_bytes_to_out(cert, out_buf, out_buf_len); + } else if constexpr (has_peer_cert_pem::value) { + auto cert = ch->peer_cert_pem(); // expect PEM text in std::string + return copy_bytes_to_out(cert, out_buf, out_buf_len); + } else { + return -1; + } +} diff --git a/sample_apps/simple_app_java/native/cf_shims.h b/sample_apps/simple_app_java/native/cf_shims.h new file mode 100644 index 000000000..58015df10 --- /dev/null +++ b/sample_apps/simple_app_java/native/cf_shims.h @@ -0,0 +1,20 @@ +#pragma once + +// Adjust includes if your paths differ: +#include "trust_manager/trust_manager.h" +#include "secure_authenticated_channel/secure_authenticated_channel.h" + +extern "C" { + +// ---- TrustManager flags ---- +int cf_tm_auth_key_initialized(TrustManager* tm); // returns 1/0 +int cf_tm_primary_admissions_cert_valid(TrustManager* tm); // returns 1/0 + +// ---- Channel peer info ---- +// Returns length of copied peer_id into out_buf (<= out_buf_len), or -1 on error. +int cf_channel_peer_id(SecureAuthenticatedChannel* ch, char* out_buf, int out_buf_len); + +// Returns length of copied peer certificate bytes (DER/PEM) into out_buf, or -1 on error. +int cf_channel_peer_cert(SecureAuthenticatedChannel* ch, unsigned char* out_buf, int out_buf_len); + +} diff --git a/sample_apps/simple_app_java/native/detect_paths.sh b/sample_apps/simple_app_java/native/detect_paths.sh new file mode 100644 index 000000000..944dd6b6f --- /dev/null +++ b/sample_apps/simple_app_java/native/detect_paths.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +set -euo pipefail +# native/detect_paths.sh — auto-detect include/lib/JNI paths; writes paths.env + +# 1) Repo root +if git rev-parse --show-toplevel >/dev/null 2>&1; then + CERTIFIER_ROOT="$(git rev-parse --show-toplevel)" +else + CERTIFIER_ROOT="$PWD" +fi + +# 2) Key headers +TM_H="$(find "$CERTIFIER_ROOT" -type f -name 'trust_manager.h' | head -n1 || true)" +CH_H="$(find "$CERTIFIER_ROOT" -type f -name 'secure_authenticated_channel*.h' | head -n1 || true)" +STORE_H="$(find "$CERTIFIER_ROOT" -type f -name 'store.h' | head -n1 || true)" + +if [[ -z "${TM_H:-}" || -z "${CH_H:-}" ]]; then + echo "ERROR: Could not find trust_manager.h or secure_authenticated_channel*.h under $CERTIFIER_ROOT" + exit 1 +fi + +# 3) Compute include roots (parent of the folder containing the header) +inc_root_of () { python3 - <<'PY' +import os, sys +h = sys.argv[1] +d = os.path.dirname(h) # .../trust_manager +print(os.path.dirname(d)) # parent (often .../include) +PY +} +CERTIFIER_INC1="$(inc_root_of "$TM_H")" +CERTIFIER_INC2="$(inc_root_of "$CH_H")" +CERTIFIER_INC3="" +[[ -n "${STORE_H:-}" ]] && CERTIFIER_INC3="$(inc_root_of "$STORE_H")" + +# 4) JDK / JNI +if [[ -z "${JAVA_HOME:-}" ]]; then + for J in /usr/lib/jvm/java-21* /usr/lib/jvm/java-17* /usr/lib/jvm/*; do + [[ -d "$J/include" ]] && JAVA_HOME="$J" && break + done +fi +[[ -z "${JAVA_HOME:-}" ]] && { echo "ERROR: set JAVA_HOME to a JDK (17+)."; exit 1; } +JNI_INC1="$JAVA_HOME/include" +case "$(uname -s)" in + Linux) JNI_INC2="$JAVA_HOME/include/linux" ;; + Darwin) JNI_INC2="$JAVA_HOME/include/darwin" ;; + *) JNI_INC2="$JAVA_HOME/include/linux" ;; +esac + +# 5) Guess lib dir +CERTIFIER_LIBDIR="$(find "$CERTIFIER_ROOT" -type d -name lib | head -n1 || true)" + +# 6) Write env file +cat > paths.env < This step can take 10–30 minutes depending on internet speed. + +--- + +## 4. Configure SDK and NDK + +Since your project involves **JNI (Java Native Interface)** and **C++ libraries**, ensure NDK support is enabled. + +1. Open **Android Studio** → `File` → `Settings` (or `Preferences` on macOS). +2. Navigate to: + - `Appearance & Behavior > System Settings > Android SDK` + - Install the following: + - **Android SDK Platform** (latest stable, e.g., Android 14 or 13) + - **Android SDK Tools** + - **NDK (Side by side)** + - **CMake** +3. Note the installation paths: + - SDK: `.../Android/Sdk/` + - NDK: `.../Android/Sdk/ndk/` + +--- + +## 5. Environment Variables (Optional but Recommended) + +Add these to your system environment variables: + +- **Windows**: + - `ANDROID_HOME=C:\Users\\AppData\Local\Android\Sdk` + - Add `%ANDROID_HOME%\tools` and `%ANDROID_HOME%\platform-tools` to `PATH` + +- **macOS/Linux**: + ```bash + export ANDROID_HOME=$HOME/Android/Sdk + export PATH=$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$PATH diff --git a/src/java/Certifier Algorithms/KeyWrapperTest.java b/src/java/Certifier Algorithms/KeyWrapperTest.java new file mode 100644 index 000000000..4f39be0fa --- /dev/null +++ b/src/java/Certifier Algorithms/KeyWrapperTest.java @@ -0,0 +1,42 @@ +public class KeyWrapperTest { + static { + System.loadLibrary("key_wrapper"); + } + + public static void main(String[] args) { + KeyWrapper key = new KeyWrapper(); + + // 1. Generate a new key + if (!key.generate(2048)) { + System.err.println("Key generation failed"); + return; + } + System.out.println("✅ RSA key generated."); + + // 2. Sign a message + String message = "Hello from Android!"; + String signature = key.sign(message); + if (signature == null || signature.isEmpty()) { + System.err.println("Signing failed"); + return; + } + System.out.println("✍️ Message signed."); + + // 3. Verify the signature + boolean verified = key.verify(message, signature); + System.out.println("✅ Signature verified: " + verified); + + // 4. Export + Import key to simulate transfer/storage + String serializedKey = key.export_key(); + KeyWrapper key2 = new KeyWrapper(); + boolean restored = key2.import_key(serializedKey); + if (!restored) { + System.err.println("Failed to restore key"); + return; + } + + // Verify again using the restored key + boolean reverified = key2.verify(message, signature); + System.out.println("🔁 Signature verified using restored key: " + reverified); + } +} diff --git a/src/java/Certifier Algorithms/README.md b/src/java/Certifier Algorithms/README.md new file mode 100644 index 000000000..8cd7fa255 --- /dev/null +++ b/src/java/Certifier Algorithms/README.md @@ -0,0 +1,46 @@ +# How to Run + +``` +swig -c++ -java key_wrapper.i +``` + +# Compile + +``` +g++ -fPIC -c key_wrapper.cc key_wrapper_wrap.cxx -Iinclude -I/usr/lib/jvm/java-17-amazon-corretto/include -I/usr/lib/jvm/java-17-amazon-corretto/include/linux +``` +``` +g++ -shared key_wrapper.o key_wrapper_wrap.o -o libkey_wrapper.so +``` + +# Java Testing + +The Java test class uses the wrapped KeyWrapper class to: +1. Generate an RSA key +2. Sign a message +3. Verify the signature +4. Export and import the key (round trip) + +## How to Compile and Run +1. Make sure you have the following files in your Java folder: +- KeyWrapper.java +- KeyWrapperJNI.java +- KeyWrapperTest.java + +2. Then compile and run: + +``` +javac KeyWrapper*.java KeyWrapperTest.java +``` +``` +java KeyWrapperTest +``` +Make sure `libkey_wrapper.so` is in your `LD_LIBRARY_PATH` or in the same directory. + +# Note + +> `key_message` (in `certifier_algorithms.h`) is a protobuf class. To wrap it in SWIG, I have created a SWIG-friendly wrapper class. +> The wrapper class internally uses `key_message` and exposes clean `std::string' methods for" +> - loading a key +> - exporting a key +> - signing/verification diff --git a/src/java/Certifier Algorithms/certifier_algorithms.h b/src/java/Certifier Algorithms/certifier_algorithms.h new file mode 100644 index 000000000..3a3145c60 --- /dev/null +++ b/src/java/Certifier Algorithms/certifier_algorithms.h @@ -0,0 +1,3 @@ +bool generate_rsa_key(int key_size, key_message* key); +bool sign_message(const key_message& key, int in_size, byte* in, int* out_size, byte* out); +bool verify_message(const key_message& key, int in_size, byte* in, int sig_size, byte* sig); diff --git a/src/java/Certifier Algorithms/key_wrapper.cc b/src/java/Certifier Algorithms/key_wrapper.cc new file mode 100644 index 000000000..5cd746bb8 --- /dev/null +++ b/src/java/Certifier Algorithms/key_wrapper.cc @@ -0,0 +1,62 @@ +#include "key_wrapper.h" +#include "certifier.h" +#include "certifier_algorithms.h" +#include "certifier.pb.h" + +using namespace std; + +KeyWrapper::KeyWrapper() {} + +KeyWrapper::~KeyWrapper() {} + +bool KeyWrapper::generate(int key_size) { + key_message key; + if (!generate_rsa_key(key_size, &key)) + return false; + + key.SerializeToString(&key_bytes); + return true; +} + +bool KeyWrapper::sign(const string& message, string& signature) { + key_message key; + if (!key.ParseFromString(key_bytes)) + return false; + + const byte* in = reinterpret_cast(message.data()); + int in_size = message.size(); + byte sig[512]; // max size buffer + int sig_size = 0; + + if (!sign_message(key, in_size, (byte*)in, &sig_size, sig)) + return false; + + signature.assign((char*)sig, sig_size); + return true; +} + +bool KeyWrapper::verify(const string& message, const string& signature) { + key_message key; + if (!key.ParseFromString(key_bytes)) + return false; + + const byte* in = reinterpret_cast(message.data()); + int in_size = message.size(); + const byte* sig = reinterpret_cast(signature.data()); + int sig_size = signature.size(); + + return verify_message(key, in_size, (byte*)in, sig_size, (byte*)sig); +} + +string KeyWrapper::export_key() { + return key_bytes; +} + +bool KeyWrapper::import_key(const string& serialized_key) { + key_message key; + if (!key.ParseFromString(serialized_key)) + return false; + + key_bytes = serialized_key; + return true; +} diff --git a/src/java/Certifier Algorithms/key_wrapper.h b/src/java/Certifier Algorithms/key_wrapper.h new file mode 100644 index 000000000..13b7909cd --- /dev/null +++ b/src/java/Certifier Algorithms/key_wrapper.h @@ -0,0 +1,22 @@ +#ifndef KEY_WRAPPER_H +#define KEY_WRAPPER_H + +#include + +class KeyWrapper { +public: + KeyWrapper(); + ~KeyWrapper(); + + bool generate(int key_size); // Generates RSA key + bool sign(const std::string& message, std::string& signature); + bool verify(const std::string& message, const s:string& signature); + + std::string export_key(); // Returns key serialized to string + bool import_key(const std::string& serialized_key); // Loads from string + +private: + std::string key_bytes; // Serialized key +}; + +#endif diff --git a/src/java/Certifier Algorithms/key_wrapper.i b/src/java/Certifier Algorithms/key_wrapper.i new file mode 100644 index 000000000..2b641c53c --- /dev/null +++ b/src/java/Certifier Algorithms/key_wrapper.i @@ -0,0 +1,8 @@ +%module key_wrapper + +%{ +#include "key_wrapper.h" +%} + +%include "std_string.i" +%include "key_wrapper.h" diff --git a/src/java/Claim Verifier/README.md b/src/java/Claim Verifier/README.md new file mode 100644 index 000000000..d93ef56af --- /dev/null +++ b/src/java/Claim Verifier/README.md @@ -0,0 +1,36 @@ +# How to Run + +``` +swig -c++ -java claim_verifier.i +``` + +# Compile + +## Run SWIG +``` +g++ -fPIC -c claim_verifier.cc claim_verifier_wrap.cxx -Iinclude \ + -I/usr/lib/jvm/java-17-amazon-corretto/include \ + -I/usr/lib/jvm/java-17-amazon-corretto/include/linux +``` +## +``` +g++ -shared claim_verifier.o claim_verifier_wrap.o -o libclaim_verifier.so +``` + +# Run the Java Test + +Replace the placeholders with actual serialized data (either: raw binary loaded as byte string, or Base64-decoded if coming from Java) + +## Compile: + +``` +javac ClaimVerifier.java ClaimVerifierJNI.java ClaimVerifierTest.java +``` + +## Run: + +``` +java ClaimVerifierTest +``` + +> Make sure libclaim_verifier.so is in your LD_LIBRARY_PATH or same directory. diff --git a/src/java/Claim Verifier/claimVerifierTest.java b/src/java/Claim Verifier/claimVerifierTest.java new file mode 100644 index 000000000..faa34e50b --- /dev/null +++ b/src/java/Claim Verifier/claimVerifierTest.java @@ -0,0 +1,30 @@ +public class ClaimVerifierTest { + static { + System.loadLibrary("claim_verifier"); + } + + public static void main(String[] args) { + // These should be real serialized protobufs + String serializedClaim = getSerializedSignedClaim(); // stub + String serializedKey = getSerializedKey(); // stub + + ClaimVerifier verifier = new ClaimVerifier(); + boolean result = verifier.verify(serializedClaim, serializedKey); + + if (result) { + System.out.println("✅ Claim successfully verified."); + } else { + System.out.println("❌ Claim verification failed."); + } + } + + // These are just placeholders. + // Replace with actual Base64-encoded or raw serialized protobufs. + private static String getSerializedSignedClaim() { + return "..."; // TODO: inject real base64/byte string here + } + + private static String getSerializedKey() { + return "..."; // TODO: inject public key here + } +} diff --git a/src/java/Claim Verifier/claim_verifier.cc b/src/java/Claim Verifier/claim_verifier.cc new file mode 100644 index 000000000..8c303b5fd --- /dev/null +++ b/src/java/Claim Verifier/claim_verifier.cc @@ -0,0 +1,20 @@ +#include "claim_verifier.h" +#include "certifier.pb.h" +#include "support.h" + +ClaimVerifier::ClaimVerifier() {} + +ClaimVerifier::~ClaimVerifier() {} + +bool ClaimVerifier::verify(const std::string& serialized_claim, const std::string& serialized_key) { + signed_claim_message claim; + key_message key; + + if (!claim.ParseFromString(serialized_claim) || !key.ParseFromString(serialized_key)) { + return false; + } + + return verify_signed_claim(claim, key); + + +// verify_signed_claim(...) is the real framework function from support.cc diff --git a/src/java/Claim Verifier/claim_verifier.h b/src/java/Claim Verifier/claim_verifier.h new file mode 100644 index 000000000..5470703be --- /dev/null +++ b/src/java/Claim Verifier/claim_verifier.h @@ -0,0 +1,15 @@ +#ifndef CLAIM_VERIFIER_H +#define CLAIM_VERIFIER_H + +#include + +class ClaimVerifier { +public: + ClaimVerifier(); + ~ClaimVerifier(); + + // Accepts serialized protobufs as strings + bool verify(const std::string& serialized_claim, const std::string& serialized_key); +}; + +#endif diff --git a/src/java/Claim Verifier/claim_verifier.i b/src/java/Claim Verifier/claim_verifier.i new file mode 100644 index 000000000..b5221abf2 --- /dev/null +++ b/src/java/Claim Verifier/claim_verifier.i @@ -0,0 +1,8 @@ +%module claim_verifier + +%{ +#include "claim_verifier.h" +%} + +%include "std_string.i" +%include "claim_verifier.h" diff --git a/src/java/Policy Store/README.md b/src/java/Policy Store/README.md new file mode 100644 index 000000000..38bcfed59 --- /dev/null +++ b/src/java/Policy Store/README.md @@ -0,0 +1,28 @@ +# How to Run + +``` +swig -c++ -java policy_store.i +``` + +# Compile `.so` (Shared Library for Java) + +> Assuming JNI headers are at `/usr/lib/jvm/java-17-amazon-corretto/include` + +``` +g++ -fPIC -c policy_store_wrap.cxx -Iinclude \ + -I/usr/lib/jvm/java-17-amazon-corretto/include \ + -I/usr/lib/jvm/java-17-amazon-corretto/include/linux +``` +``` +g++ -shared policy_store_wrap.o -o libpolicy_store.so +``` + +> Place 'libpolicy_store.so' somewhere in your 'LD_LIBRARY_PATH' + +# Run the Java Test + +Compile: +``` +javac certifier/framework/*.java PolicyStoreTest.java +java certifier.framework.PolicyStoreTest +``` diff --git a/src/java/Policy Store/policy_store.i b/src/java/Policy Store/policy_store.i new file mode 100644 index 000000000..adc1105ac --- /dev/null +++ b/src/java/Policy Store/policy_store.i @@ -0,0 +1,25 @@ +%module policy_store + +%{ +#include "certifier.h" +using namespace certifier::framework; +%} + +%include "std_string.i" + +namespace certifier { + namespace framework { + class policy_store { + public: + policy_store(); + policy_store(unsigned max_ents); + ~policy_store(); + + unsigned get_num_entries(); + bool add_entry(const std::string& tag, const std::string& type, const std::string& value); + int find_entry(const std::string& tag, const std::string& type); + bool get(unsigned ent, std::string* v); + bool put(unsigned ent, const std::string v); + }; + } +} diff --git a/src/java/Policy Store/policy_store_dummy.cc b/src/java/Policy Store/policy_store_dummy.cc new file mode 100644 index 000000000..4905f5be9 --- /dev/null +++ b/src/java/Policy Store/policy_store_dummy.cc @@ -0,0 +1,16 @@ +namespace certifier::framework { + +class policy_store { + public: + policy_store(); + policy_store(unsigned max_ents); + ~policy_store(); + + unsigned get_num_entries(); + bool add_entry(const std::string& tag, const std::string& type, const std::string& value); + int find_entry(const std::string& tag, const std::string& type); + bool get(unsigned ent, std::string* v); + bool put(unsigned ent, const std::string v); +}; + +} diff --git a/src/java/Policy Store/test.java b/src/java/Policy Store/test.java new file mode 100644 index 000000000..88ce24dc4 --- /dev/null +++ b/src/java/Policy Store/test.java @@ -0,0 +1,19 @@ +package certifier.framework; + +public class PolicyStoreTest { + static { + System.loadLibrary("policy_store"); + } + + public static void main(String[] args) { + policy_store store = new policy_store(10); + store.add_entry("example", "string", "hello"); + int idx = store.find_entry("example", "string"); + + if (idx >= 0) { + System.out.println("Found entry at: " + idx); + } else { + System.out.println("Entry not found."); + } + } +} diff --git a/src/java/Simulated Enclave/README.md b/src/java/Simulated Enclave/README.md new file mode 100644 index 000000000..0ed10e990 --- /dev/null +++ b/src/java/Simulated Enclave/README.md @@ -0,0 +1,31 @@ +# Generate SWIG Output + +``` +swig -c++ -java simulated_enclave.i +``` +This creates: + +- simulated_enclave_wrap.cxx +- simulated_enclave.java +- simulated_enclaveJNI.java + +# Compile `.so` (Shared Library for Java) + +> Assuming headers are in `include/` and JNI path is: + +``` +g++ -fPIC -c simulated_enclave_wrap.cxx -Iinclude \ + -I/usr/lib/jvm/java-17-amazon-corretto/include \ + -I/usr/lib/jvm/java-17-amazon-corretto/include/linux +``` +``` +g++ -shared simulated_enclave_wrap.o -o libsimulated_enclave.so +``` + +# Run the Java Test + +Compile: +``` +javac simulated_enclave*.java SimulatedTest.java +java SimulatedTest +``` diff --git a/src/java/Simulated Enclave/simulated_enclave.i b/src/java/Simulated Enclave/simulated_enclave.i new file mode 100644 index 000000000..72278445c --- /dev/null +++ b/src/java/Simulated Enclave/simulated_enclave.i @@ -0,0 +1,13 @@ +%module simulated_enclave + +%{ +#include "simulated_enclave.h" +%} + +%include "std_string.i" + +// Wraps functions from simulated_enclave.h +bool simulated_init(); +bool simulated_attest(std::string* out); +bool simulated_get_platform_cert(std::string* out_cert); +bool simulated_get_measurement(std::string* out_measurement); diff --git a/src/java/Simulated Enclave/simulated_enclave_dummy.h b/src/java/Simulated Enclave/simulated_enclave_dummy.h new file mode 100644 index 000000000..3de73a130 --- /dev/null +++ b/src/java/Simulated Enclave/simulated_enclave_dummy.h @@ -0,0 +1,4 @@ +bool simulated_init(); +bool simulated_attest(std::string* out); +bool simulated_get_platform_cert(std::string* out_cert); +bool simulated_get_measurement(std::string* out_measurement); diff --git a/src/java/Simulated Enclave/test.java b/src/java/Simulated Enclave/test.java new file mode 100644 index 000000000..dd164cf89 --- /dev/null +++ b/src/java/Simulated Enclave/test.java @@ -0,0 +1,26 @@ +public class SimulatedTest { + static { + System.loadLibrary("simulated_enclave"); + } + + public static void main(String[] args) { + StringBuilder attestation = new StringBuilder(); + StringBuilder platformCert = new StringBuilder(); + StringBuilder measurement = new StringBuilder(); + + boolean initStatus = simulated_enclave.simulated_init(); + System.out.println("Init successful: " + initStatus); + + if (simulated_enclave.simulated_attest(attestation)) { + System.out.println("Attestation: " + attestation.toString()); + } + + if (simulated_enclave.simulated_get_platform_cert(platformCert)) { + System.out.println("Platform Cert: " + platformCert.toString()); + } + + if (simulated_enclave.simulated_get_measurement(measurement)) { + System.out.println("Measurement: " + measurement.toString()); + } + } +}