Skip to content

Development using JavaScript

Shams Asari edited this page Jan 24, 2023 · 1 revision

Running JavaScript inside an enclave

When you use the graalvm-native-image runtime, you have the option to enable JavaScript language support. When enabled, you can create a context in which you can load and execute a JavaScript source module. This module can either run to completion and terminate, or it can define a set of functions and variables that can subsequently be called and accessed from your Java enclave code.

Modifying the sample enclave to use JavaScript

The sample "hello world" enclave took us through a tutorial on how to write an enclave that takes a string, reverses it, and returns it via the host to the client. In this section, we will take the code from the sample and modify it to reverse the string using JavaScript to replace the existing Java reverse() function.

Make sure you've already run through the tutorial and have a working sample application as a starting point.

Enable JavaScript in the conclave configuration

Enabling JavaScript support in an enclave requires pulling in a number of dependencies that result in a larger enclave size. Therefore, JavaScript is not enabled by default. To enable support, add the following line to your enclave build.gradle.

Javascript

```groovy hl_lines="4"
conclave {
    productID = 1
    revocationLevel = 0
    supportLanguages = "js"
}
```

More details on enclave configuration are available on this page.

Import the GraalVM SDK classes

We need to use the GraalVM SDK to build a context in which to run the JavaScript code. The dependency to the SDK is automatically added when you specify supportLanguages = "js" for Javascript. So you just need to add the following import statements to ReverseEnclave.java:

import com.r3.conclave.enclave.Enclave;
import com.r3.conclave.mail.EnclaveMail;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;

Parse the JavaScript code and set up bindings to Java

The next step is to define and parse our JavaScript code. Once we have done this we can set up the bindings to Java which allow us to access the functions and variables that are defined within the JavaScript code. Add a constructor that prepares the JavaScript context:

Javascript

```java hl_lines="4-15"
    // We store the previous result to showcase that the enclave internals can be examined in a mock test.
    byte[] previousResult;

    private final Value bindings;
    private static final String jsCode = "function reverse(input) {"
            + "  var split = input.split('');"
            + "  var reverse = split.reverse();"
            + "  return reverse.join('');"
            + "}";

    public ReverseEnclave() {
        Context context = Context.create("js");
        bindings = context.getBindings("js");
        context.eval("js", jsCode);
    }

    @Override
    protected byte[] receiveFromUntrustedHost(byte[] bytes) {
```

The context that runs the code must be closed before the enclave is destroyed. Otherwise, the application will hang once the method destroyEnclave is invoked. The best place to close the context is at the bottom of the receiveMail method as shown below:

```java hl_lines="13-16"

    @Override
    protected void receiveMail(long id, EnclaveMail mail, String routingHint) {
        // This is used when the host delivers a message from the client.
        // First, decode the Mail body as a String.
        final String stringToReverse = new String(mail.getBodyAsBytes());
        // Reverse it and re-encode to UTF-8 to send back.
        final byte[] reversedEncodedString = reverse(stringToReverse).getBytes();
        // Get the post office object for responding back to this mail and use it to encrypt our response.
        final byte[] responseBytes = postOffice(mail).encryptMail(reversedEncodedString);
        postMail(responseBytes, routingHint);
    
        // Please ensure that close is called before or while the enclave is being destroyed. Failing to do so
        // will hang the application when the method destroyEnclave is called
        context.close();
    }
```

Replace the Java function with a call to the JavaScriptfunction

Remove the Java code that reverses the string and replace it with the following function. Note that static has been removed from the function declaration because it now accesses the bindings member variable.

        return result;
    }

    private String reverse(String input) {
        Value result = bindings.getMember("reverse").execute(input);
        return result.asString();
    }

    @Override
    protected void receiveMail(long id, EnclaveMail mail, String routingHint) {

Finally, run the sample code as described in the tutorial.

Build times can be quite long when running in simulation mode. For productivity reasons, it is advisable to run the sample in mock mode. Before running the sample in mock mode, it is necessary to:

1. Download [graalvm-ce-java17](https://github.com/graalvm/graalvm-ce-builds/releases).
2. Set the environment variable ```JAVA_HOME``` to point to the GraalVM that was previously downloaded. For instance, 
```export JAVA_HOME=/usr/lib/jvm/graalvm-ce-java17-22.0.0.2)```.
3. Update the environment variable PATH by running ```export PATH=JAVA_HOME/bin:$PATH```.

More information

Conclave support for JavaScript is provided by the polyglot capabilities in GraalVM. Refer to the GraalVM documentation on embedding languages for detailed instructions on how to use this capability.

Note

  • The functionality described on this page involves JIT compilation within the secure enclave. Due to the unavailability of the CPUID instruction in SGX enclaves, some optimizations which depend on the presence of certain instruction set extensions may not take place, and performance may be degraded.

  • The processor of the host system must support the SSE and SSE2 instruction set extensions. If these extensions are not present, the enclave may abort unexpectedly.