Intel® Software Guard Extensions (Intel® SGX)
Discussion board focused on hardware-based isolation and memory encryption to provide extended code protection in solutions.

External call to SGX with node

Johnson__Scott
Beginner
1,829 Views

Hi,

I have setup nodejs and I am using node-gyp (node-api) which allows me to use C++ code with nodejs.

I have two projects within the same solution in Visual Studio. One is Nodejs based and the other is SGX

However, when I use my node-api c++ file to call my create_enclave function which typically sets up the enclave. The enclave fails to create.

I have verified if I try to create the enclave without node being involved then it creates.

So my assumption is that the SGX code somehow knows that is being called from another project and therefore does not allow it.

Is there a way to allow my "external" function to interact with the SGX code so that an enclave is created? I have tried using a proxy that was part of the trusted section in the EDL but that generated the same result.

I got error code 8237. But no other details.

0 Kudos
16 Replies
JesusG_Intel
Moderator
1,829 Views

Hi Scott,

That error code, 8237, which is 0x202D, does not appear to come from SGX.

Please give us more details:

  1. SGX SDK version
  2. OS version 
  3. Visual Studio version
  4. Which function call specifically sent the error code?
  5. Screenshot of the error

Regards,

Jesus

0 Kudos
Johnson__Scott
Beginner
1,829 Views

Error code changed to #8206.

Don't seem able to add screenshot at present but full text is:

"Failed to create enclave: Error #8206"

Error is returned by this line:

sgx_status = sgx_create_enclave(ENCLAVE_FILE, SGX_DEBUG_FLAG, &launch_token, &updated, &enclaveId, NULL);

1. SGX is 2.7.101

2. Windows 10 64bit

3.VS 2017 Version 15.9.4

 

Node-Api code:

//Declaring NAPI c++ function
Napi::String addition(const Napi::CallbackInfo& info) {
	Napi::Env env = info.Env();

	//std::string arg0 = (std::string) info[0].ToString();
	//int result = enc();
	string name = (std::string) info[0].ToString();
	int n = enc();
	//return Napi::String::New(env, name);
	Napi::String retvals = Napi::String::New(env, name);
	return retvals;
} 


//Napi object which calls addition function above (initialisation)
Napi::Object Init(Napi::Env env, Napi::Object exports) {

	//Napi
	exports.Set(
		Napi::String::New(env, "addition"),
		Napi::Function::New(env, addition)
	);
	return exports;
}
//Exposing module to be called by other js files.
NODE_API_MODULE(make_sum, Init)

SGX code:

static int create_enclave(sgx_enclave_id_t *eid)
{
		sgx_status = sgx_create_enclave(ENCLAVE_FILE, SGX_DEBUG_FLAG, &launch_token, &updated, &enclaveId, NULL);
		cout << sgx_status << '\n';
		cout << eid << '\n';
		if (sgx_status == SGX_SUCCESS) {
				if (eid != NULL) *eid = enclaveId;
				cout << eid;
				launched = 1;
			return 1;
		}

		return 0;
}

The enc() function referenced in the node code just runs the above SGX code.

0 Kudos
Johnson__Scott
Beginner
1,829 Views

I am just not sure if I can trigger the enclave creation this way.

0 Kudos
JesusG_Intel
Moderator
1,829 Views

Scott,

You should be able to create the enclave from your node code.

Error 8206 is 0x200e (hex), which, according to sgx_error.h is SGX_ERROR_MODE_INCOMPATIBLE  = SGX_MK_ERROR(0x200e),      /* The target enclave 32/64 bit mode or sim/hw mode is incompatible with the mode of current uRTS. */

The SGX Developer Reference states that:

SGX_ERROR_MODE_INCOMPATIBLE: The target enclave mode is incompatible with the mode of the current RTS. For example, a 64-bit application tries to load a 32-bit enclave or a simulation uRTS tries to load a hardware enclave.

Does this help?

Regards,

Jesus

0 Kudos
Johnson__Scott
Beginner
1,829 Views

Oddly, yes. I worked out that the node code was using a library that made it seem like i was trying to run HW mode. So I changed that.

However, new problem. I now have status 7 returned when trying to do the addition with node which i believe maps to error: SGX_ERROR_HYPERV_ENABLED

But I do not have hyper-v enabled. (I double checked in windows features).

Relevant code:

sgx_status_t enclaveAdd(sgx_enclave_id_t eid, int x, int y)
{
	sgx_status_t status;
	ms_enclaveAdd_t ms;
	ms.ms_x = x;
	ms.ms_y = y;
	status = sgx_ecall(eid, 1, &ocall_table_EnclaveAddition3, &ms);
	return status;
}

Again this is only shown when triggering the enclave via node.

 

These are the libraries I am using with node for SGX:

"C:\\Program Files (x86)\\Intel\\IntelSGXSDK\\bin\\x64\\Debug\\sgx_urts_sim.lib",
            "C:\\Program Files (x86)\\Intel\\IntelSGXSDK\\bin\\x64\\Debug\\sgx_uae_service_sim.lib",
            "C:\\Program Files (x86)\\Intel\\IntelSGXSDK\\bin\\x64\\Debug\\sgx_launch_sim.lib",
            "C:\\Program Files (x86)\\Intel\\IntelSGXSDK\\bin\\x64\\Debug\\sgx_platform_sim.lib",
            "C:\\Program Files (x86)\\Intel\\IntelSGXSDK\\bin\\x64\\Debug\\sgx_quote_ex_sim.lib",
            "C:\\Program Files (x86)\\Intel\\IntelSGXSDK\\bin\\x64\\Debug\\sgx_enclave_common.lib",
            "C:\\Program Files (x86)\\Intel\\IntelSGXSDK\\bin\\x64\\Debug\\sgx_tservice_sim.lib",
            "C:\\Program Files (x86)\\Intel\\IntelSGXSDK\\bin\\x64\\Debug\\sgx_epid_sim.lib"

0 Kudos
JesusG_Intel
Moderator
1,829 Views

Hi Scott,

I created an enclaveAdd ecall just like you and it works fine without node. I even got the same ecall definition in my enclave_u.c file that you posted (yours is called EnclaveAddition3_u.c). I am not familiar with working with node.js but I will try to help you get to the root of your problem.

To debug, open your EnclaveAddition3_t.c file which you will find in the "Generated Files" of your EnclaveAddition3 project. Insert a breakpoint in the first line of the function "status sgx_status_t SGX_CDECL sgx_enclaveAdd(void* pms). When you execute your application, determine where exactly your error is generated. If you do not reach this breakpoint then your proxy functions in EnclaveAddition3_u.c are not properly calling the proxys in EnclaveAddition3_t.c.

Regards,

Jesus

0 Kudos
Johnson__Scott
Beginner
1,829 Views

I appreciate that.

Running the debug doesn't help as the breakpoints on the sgx side are ignored when I execute the node code.

https://github.com/nodejs/node-addon-api

I'll have to share the code so you can understand the crazy a little better.

0 Kudos
Johnson__Scott
Beginner
1,829 Views

Hi,

I have changed tactics a little bit and got further with Go.

So, I am at a point when trying to pass ints to the enclave but this seems to fail.

At present I have a 4097 error which matches to SGX_ERROR_INVALID_FUNCTION.

I never seem to reach the enclave code as the string doesn't print out either. I think my problem is with the ecall/ocalls

APP

int test(void) {
    if (initialize_enclave(&global_eid, "enclave.token", "enclave.signed.so") < 0) {
        std::cout << "Failed to initialize enclave." << std::endl;
        return 1;
    }
        sgx_status_t ret;
        int a = 5;
        int retVal = 0;
        int some = 1;
        int s = 0;
        print_error_message(ret);
        s=sumAdd(global_eid,&some,a,&retVal);
        if(!is_ecall_successful(ret,"Failed",ret));
        std::cout<<retVal<<"\n";
         std::cout<<some<<"\n";
        std::cout<<s<<"\n";
        print_error_message(ret);
        return 0;
        }

EDL

enclave {
    from "sgx_tae_service.edl" import *;


    trusted {
        public int sumAdd(int a,[out] int* res);
};

    untrusted {
        /* define OCALLs here. */
        void ocall_print_int([in] int* num);
        void ocall_print([in, string]const char* str);
    };
};

Enclave

void sumAdd(int a,int *result){
        sgx_status_t ret;
        int busy_retry_times = 2;
        do {
        ret = sgx_create_pse_session();
       } while (ret == SGX_ERROR_BUSY && busy_retry_times--);
       if (ret != SGX_SUCCESS)
           return ret;
        int b =6;
        ocall_print("ENCLAVE");
        check_sgx_status(ret);
        sgx_close_pse_session();
        *result = 26;
        return b;
}

 

0 Kudos
JesusG_Intel
Moderator
1,829 Views

Hi Scott,

I see a few problems.

1. The return type of your ecall function in your EDL file must match the return type in Enclave.cpp/.h.  Make your ecall declaration in the EDL file public void sumAdd. It should look like this:

trusted {
        public void sumAdd(int a, [out] int* res);
};

In app.cpp, you are assigning to s the status of the ecall sumAdd. I think you meant to use ret like this:

sgx_status_t ret;
ret = sumAdd(global_eid…);
if(!is_ecall_successful(ret,"Failed",ret));

If you want to use "s" then  "s" should be of type sgx_status_t. Your is_ecall_successfull should check "s" since that is the variable that holds the status of the ecall.

2. When you are calling sumAdd in app.cpp, whether you use four variables or three depends on whether the return type of sumAdd is int or void. If you sumAdd is void, then you do not need to pass the second pointer &some. If your return type is int, then you need &some to hold the returned value from sumAdd.

Here is where things can get tricky.

If you want the return type of sumAdd to be int rather than void, this is how your files must look...

EDL

trusted {
            public int enclaveAdd(int x, [out] int *res);
};

Enclave.h

int enclaveAdd(int x, int *res);

Enclave.cpp

int enclaveAdd(int x, int *result) {
 *result = x + 10; //this is the [out] variable you declared in the EDL
 int z = 5;
 return z + x; //this value gets returned via &resultAdd argument in app.cpp
}

App.cpp

In app.cpp, when you call an ecall with a return type other than void, you have to add an extra argument that will hold the returned value. See below how I use &resultAdd to hold the returned value from sumAdd. If your return type is void, then you do not need this extra argument.

int x = 2;
int retVal = 0;
int resultAdd; //this will hold the return value from enclaveAdd
sgx_status_t ret;
ret = enclaveAdd(global_eid, &resultAdd, x, &retVal); //&resultAdd holds value returned via the return statement in eclave.cpp

After this code runs the values are:

resultAdd = 7 //z + x = 5 + 2 from enclave.cpp
retVal = 12 //2 + 10 from enclave.cpp

 

Johnson__Scott
Beginner
1,829 Views

Hi,

So I modified the code to mirror yours but for some reason I don't get the same results.

resultAdd returns different values each time similar to this 32583

retVal returns 0

It's as if the pointers are never updated.

 

0 Kudos
JesusG_Intel
Moderator
1,829 Views

Hello Scott,

Please send the relevant code from EDL, enclave.cpp, and app.cpp.

Regards,

Jesus

0 Kudos
Johnson__Scott
Beginner
1,829 Views

Sure, thank you for your help thus far.

app.cpp

int test() {
    if (initialize_enclave(&global_eid, "enclave.token", "enclave.signed.so") < 0) {
        std::cout << "Fail to initialize enclave." << std::endl;
        return 1;
    }
    int x = 5;
    int retVal = 0;
    int resultAdd;                                                                                                              sgx_status_t ret;
    ret = sumAdd(global_eid,&resultAdd,x,&retVal);
    std::cout<<resultAdd<<std::endl;
    std::cout<<retVal<<std::endl;
    return 0;                                                                                                           
}

 

Enclave.cpp

int sumAdd(int x, int *result){
   *result = x+10;
    int z = 5;
    return z + x;

}

EDL

enclave {
    from "sgx_tae_service.edl" import *;

    trusted {
        /* define ECALLs here. */
        public int sumAdd(int x,[out] int* result);

    };

    untrusted {
        /* define OCALLs here. */
        void ocall_print([in, string]const char* str);
    };
};

I am using the enclave_t.h for the prototype.

0 Kudos
JesusG_Intel
Moderator
1,829 Views

Hi Scott, you code is perfect from the perspective of SGX. It works. Are you testing the enclave directly in C++/C or are you abstracting with Go?

Regards,
Jesus

0 Kudos
Johnson__Scott
Beginner
1,829 Views

Hi,

The go function simply calls the C++ code. Nothing too fancy.

Go code below:

/*
#include "./App/TEE.h"
#cgo LDFLAGS: -L. -ltee
*/
import "C"

import (
        "fmt"
)

func main() {
        fmt.Println("Intel SGX starting")
        C.test()
}

 

0 Kudos
Johnson__Scott
Beginner
1,829 Views

Hey,

Out of curiosity, are you aware of any abstracted examples similar to what I am trying to do?

0 Kudos
JesusG_Intel
Moderator
1,829 Views

Hello Scott,

We have not seen this before. Have you seen this project on Github, https://github.com/rupc/go-with-intel-sgx -> https://github.com/rupc/go-with-intel-sgx/tree/master/SampleCode/SampleEnclave? It might help you.

 

I have been having some problems getting my hands on a Linux machine with SGX support so I can try to setup the SampleEnclave Go example from the link above. I do not have experience with Go.

Regards,

Jesus

Intel Customer Support

0 Kudos
Reply