Asylo Java Client

This guide describes how to use Java to run an Asylo enclave that was written in C++. This guide assumes that the reader is familiar with Asylo quickstart guide.

Introduction

There are two parts in an enclave application written using Asylo framework, untrusted application and trusted application (enclave). Asylo release 0.5.2 and older required both trusted and untrusted components to be written in C++.

With the introduction of Asylo Java client, untrusted application can now be written in Java as well. An Asylo Java client can load and run an enclave written in C++. This model enables users to write their enclave once and then reuse it in an untrusted application written in C++ or Java.

Using a Java client

An enclave can be loaded using an EnclaveManager. It is a singleton class which can load an enclave from the file system by providing the path to the enclave binary using the EnclaveLoadConfig proto.

Users may interact with a loaded enclave through an EnclaveClient. The EnclaveManager returns a loaded and named EnclaveClient with the method getEnclaveClient.

Most of the configurations, inputs, and outputs in a Java client are passed using protocol-buffer messages.

One major difference between the Java and C++ APIs is that in Java, errors are thrown as exceptions derived from EnclaveException, rather returned through a StatusOr<T> type.

The following snippet is a small example of a Java client that interacts with an enclave written in C++.

public static void main(String[] args) {

  if (args.length != 1) {
    System.err.println("Expecting a single argument which is the filepath of an enclave.");
    System.exit(1);
  }

  String enclavePath = args[0];
  String enclaveName = "demo_enclave";

  // Part 1: Initialization
  // Specify the enclave file.
  FileEnclaveConfig fileEnclaveConfig =
      FileEnclaveConfig.newBuilder().setEnclavePath(enclavePath).build();

  // Specify that the enclave uses SGX, and configure the SGX loader with the
  // path to the enclave binary.
  SgxLoadConfig sgxLoadConfig =
      SgxLoadConfig.newBuilder().setDebug(true).setFileEnclaveConfig(fileEnclaveConfig).build();

  // Specify the enclave name and inject the SGX configuration.
  EnclaveLoadConfig enclaveLoadConfig =
      EnclaveLoadConfig.newBuilder()
          .setName(enclaveName)
          .setExtension(EnclaveLoadConfigSgxExtension.sgxLoadConfig, sgxLoadConfig)
          .build();

  EnclaveManager.getInstance().loadEnclave(enclaveLoadConfig);

  // Part 2: Secure execution
  // Get user input.
  String plainText = getMessage();

  // Prepare input for enclave.
  Demo demoInput = Demo.newBuilder().setValue(plainText).setAction(Demo.Action.ENCRYPT).build();
  EnclaveInput enclaveInput =
      EnclaveInput.newBuilder()
          .setExtension(EnclaveDemoExtension.quickstartInput, demoInput)
          .build();

  // Register protobuf extension for output.
  ExtensionRegistry registry = ExtensionRegistry.newInstance();
  registry.add(EnclaveDemoExtension.quickstartOutput);

  EnclaveClient client = EnclaveManager.getInstance().getEnclaveClient(enclaveName);
  EnclaveOutput output = client.enterAndRun(enclaveInput, registry);
  Demo encryptedText = output.getExtension(EnclaveDemoExtension.quickstartOutput);

  System.out.println("Encrypted message:" + encryptedText.getValue());

  // Part 3: Finalization
  EnclaveFinal finalInput = EnclaveFinal.getDefaultInstance();
  EnclaveManager.getInstance().destroyEnclaveClient(client, finalInput);
}

The above snippet is conceptually the same as the one mentioned in enclave lifecycle

Building and running an enclave Java application

The Java library //asylo:enclave_client_java provides the API to load C++ enclaves in Java.

java_binary(
    name = "quickstart",
    srcs = [
        "src/main/java/com/example/DemoDriver.java",
    ],
    main_class = "com.example.DemoDriver",
    deps = [
        ":demo_java_proto",
        "//java/com/google/protobuf",
        "@com_google_asylo//asylo:enclave_client_java",
    ],
)

java_proto_library(
    name = "demo_java_proto",
    deps = [
        "//quickstart:demo_proto",
    ],
)

The Bazel BUILD file shown above has untrusted java code in the target :quickstart, which contains the code to handle logic of initializing, running, and finalizing the enclave.

To run this example first we need an enclave. The following workflow uses the enclave from Asylo quickstart guide by running:

bazel build //quickstart:demo_enclave_sgx_sim.so

Copy the generated file to some location:

cp $(bazel info bazel-bin)/quickstart/demo_enclave_sgx_sim.so /tmp/demo_enclave_sgx_sim.so

Now, untrusted Java client can be run as:

bazel run //java/quickstart_client:quickstart /tmp/demo_enclave_sgx_sim.so

You should then see a prompt for a message to encrypt, similar to the quickstart guide.