This is an automated email from the ASF dual-hosted git repository. shaojunwang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-teaclave-java-tee-sdk.git
commit bda96fd9775d07b08fef58a2e570c2973aa36263 Author: jeffery.wsj <[email protected]> AuthorDate: Wed Jun 15 19:02:49 2022 +0800 [sdk] Support remote attestation for TEE_SDK enclave mode Summary: 1. Add TeeSdkAttestationReport class for TEE_SDK enclave 2. Refactor toolchains to support user giving private.pem for signing enclave .so 3. Implement remote attestation generation and verification for TEE_SDK enclave Test Plan: all tests pass Reviewers: lei.yul, cengfeng.lzy, sanhong.lsh Issue: https://aone.alibaba-inc.com/task/42544014 CR: https://code.aone.alibaba-inc.com/java-tee/JavaEnclave/codereview/9084250 --- build.sh | 6 +- .../remote_attestation_generate/Makefile | 13 ++ .../generate_attestation_report.c | 22 +++ .../generate_attestation_report.h | 24 +++ .../platform/tee_sdk_svm/wrapper/tee_sdk_wrapper.c | 1 + .../host/AbstractEnclave.java | 39 +++-- .../host/AttestationReport.java | 22 +-- .../host/InnerNativeInvocationResult.java | 27 ---- .../host/MockInJvmEnclave.java | 12 +- .../host/MockInSvmEnclave.java | 58 ++------ .../host/RemoteAttestation.java | 10 +- .../host/RemoteAttestationVerifyResult.java | 25 ++++ .../host/SGXRemoteAttestationVerify.java | 46 ++++++ .../host/TeeSdkAttestationReport.java | 35 +++++ .../confidentialcomputing/host/TeeSdkEnclave.java | 78 +++------- .../native/cpp/attestation_verify/sgx/jni/Makefile | 17 +++ .../sgx/jni/jni_remote_attestation_verify.c | 118 +++++++++++++++ .../sgx/jni/jni_remote_attestation_verify.h | 45 ++++++ .../cpp/platform/mock_in_svm/jni/jni_mock_in_svm.c | 91 +++++++----- .../cpp/platform/mock_in_svm/jni/jni_mock_in_svm.h | 40 ++++- .../main/native/cpp/platform/tee_sdk_svm/Makefile | 7 +- .../platform/tee_sdk_svm/edge_routines/Makefile | 3 + .../tee_sdk_svm/edge_routines/ocall_attestation.c | 6 + .../tee_sdk_svm/edge_routines/ocall_attestation.h | 22 +++ .../native/cpp/platform/tee_sdk_svm/jni/Makefile | 3 + .../tee_sdk_svm/jni/generate_attestation_report.c | 69 +++++++++ .../tee_sdk_svm/jni/generate_attestation_report.h | 38 +++++ .../cpp/platform/tee_sdk_svm/jni/jni_tee_sdk_svm.c | 164 +++++++++++++++++---- .../cpp/platform/tee_sdk_svm/jni/jni_tee_sdk_svm.h | 54 ++++++- .../host/MockTestEnclave.java | 25 ++-- .../host/TestRemoteAttestation.java | 2 +- sdk/native/bin/remote_attestation/sgx/jni/.gitkeep | 0 .../platform/tee_sdk_svm/edl/tee_sdk_enclave.edl | 6 + .../config/platform/tee_sdk_svm/jni/config.mk | 10 +- .../config/remote_attestation_verify/sgx/config.mk | 13 ++ sdk/native/script/build_app/Makefile | 22 +-- sdk/native/script/build_app/make.sh | 8 +- sdk/native/script/build_enclave_sdk/Makefile | 2 + sdk/native/script/build_host_sdk/Makefile | 2 + sdk/native/script/build_host_sdk/make.sh | 1 + test/enclave/pom.xml | 2 + .../test/host/TestJavaEnclaveService.java | 42 ++++-- tools/cicd/make.sh | 7 +- 43 files changed, 949 insertions(+), 288 deletions(-) diff --git a/build.sh b/build.sh index 44288a0..5d096d2 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,9 @@ #!/bin/bash +# set sgx enclave remote attestation PCCS_URL. +echo "PCCS_URL=${PCCS_URL}" > /etc/sgx_default_qcnl.conf +echo "USE_SECURE_CERT=TRUE" >> /etc/sgx_default_qcnl.conf + # parse shell file's path location. SHELL_FOLDER=$(cd "$(dirname "$0")";pwd) @@ -15,4 +19,4 @@ cd "${WORKDIR}"/sdk && mvn $SETTING clean install rm -rf /opt/javaenclave && mkdir -p /opt/javaenclave && cp -r ${SHELL_FOLDER}/sdk/native/bin /opt/javaenclave \ && cp -r ${SHELL_FOLDER}/sdk/native/config /opt/javaenclave && cp -r ${SHELL_FOLDER}/sdk/native/script/build_app /opt/javaenclave # Test unit test cases in JavaEnclave -cd "${WORKDIR}"/test && mvn -X $SETTING -Pnative -e clean package +cd "${WORKDIR}"/test && mvn $SETTING -Pnative clean package diff --git a/sdk/enclave/src/main/native/cpp/platform/tee_sdk_svm/remote_attestation_generate/Makefile b/sdk/enclave/src/main/native/cpp/platform/tee_sdk_svm/remote_attestation_generate/Makefile new file mode 100644 index 0000000..957be54 --- /dev/null +++ b/sdk/enclave/src/main/native/cpp/platform/tee_sdk_svm/remote_attestation_generate/Makefile @@ -0,0 +1,13 @@ +include $(NATIVE_BASE_DIR)/config/config.mk +include $(NATIVE_BASE_DIR)/config/platform/tee_sdk_svm/jni/config.mk + +.PHONY: all build clean + +all: build + +build: + $(CC) -g -c -I$(INCLUDE) -I$(JAVA_HOME)/lib $(TS_ENCLAVE_INCDIR) $(TS_ENCLAVE_CFLAGS) generate_attestation_report.c \ + -o $(BIN)/platform/tee_sdk_svm/generate_attestation_report.o + +clean: + rm -rf $(BIN)/platform/tee_sdk_svm/generate_attestation_report.o \ No newline at end of file diff --git a/sdk/enclave/src/main/native/cpp/platform/tee_sdk_svm/remote_attestation_generate/generate_attestation_report.c b/sdk/enclave/src/main/native/cpp/platform/tee_sdk_svm/remote_attestation_generate/generate_attestation_report.c new file mode 100644 index 0000000..0935fd2 --- /dev/null +++ b/sdk/enclave/src/main/native/cpp/platform/tee_sdk_svm/remote_attestation_generate/generate_attestation_report.c @@ -0,0 +1,22 @@ +#include "generate_attestation_report.h" + +int generate_remote_attestation_report(void* hash, size_t hash_length, sgx_report_t* ra_report) { + sgx_report_data_t report_data; + quote3_error_t sgx_error; + if (hash_length != SGX_REPORT_DATA_SIZE) { + return (int)SGX_ERROR_INVALID_PARAMETER; + } + memset(&report_data, 0, sizeof(sgx_report_data_t)); + memcpy(report_data.d, hash, SGX_REPORT_DATA_SIZE); + + sgx_target_info_t qe_target_info; + memset(&qe_target_info, 0, sizeof(sgx_target_info_t)); + + ocall_get_target_info(&sgx_error, &qe_target_info); + if(sgx_error != SGX_QL_SUCCESS) { + return (int)sgx_error; + } + + /* Generate the report for the app_enclave */ + return (int)sgx_create_report(&qe_target_info, &report_data, ra_report); +} diff --git a/sdk/enclave/src/main/native/cpp/platform/tee_sdk_svm/remote_attestation_generate/generate_attestation_report.h b/sdk/enclave/src/main/native/cpp/platform/tee_sdk_svm/remote_attestation_generate/generate_attestation_report.h new file mode 100644 index 0000000..f93c1b4 --- /dev/null +++ b/sdk/enclave/src/main/native/cpp/platform/tee_sdk_svm/remote_attestation_generate/generate_attestation_report.h @@ -0,0 +1,24 @@ +#ifndef _GENERATE_ATTESTATION_REPORT_H_ +#define _GENERATE_ATTESTATION_REPORT_H_ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> + +#include "sgx_trts.h" +#include "sgx_error.h" +#include "sgx_report.h" +#include "sgx_utils.h" +#include "sgx_quote_3.h" +#include "sgx_ql_lib_common.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + int generate_remote_attestation_report(void* hash, size_t hash_length, sgx_report_t* ra_report); +#if defined(__cplusplus) +} +#endif + +#endif /* !_GENERATE_ATTESTATION_REPORT_H_ */ diff --git a/sdk/enclave/src/main/native/cpp/platform/tee_sdk_svm/wrapper/tee_sdk_wrapper.c b/sdk/enclave/src/main/native/cpp/platform/tee_sdk_svm/wrapper/tee_sdk_wrapper.c index 6d651ea..95255d4 100644 --- a/sdk/enclave/src/main/native/cpp/platform/tee_sdk_svm/wrapper/tee_sdk_wrapper.c +++ b/sdk/enclave/src/main/native/cpp/platform/tee_sdk_svm/wrapper/tee_sdk_wrapper.c @@ -33,6 +33,7 @@ int tee_sdk_random(void* data, long size) { } int enclave_svm_isolate_create(void* isolate, void* isolateThread) { + // printf("JavaEnclave Warning: %s is called in enclave svm.\n", __FUNCTION__); graal_isolate_t* isolate_t; graal_isolatethread_t* thread_t; diff --git a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/AbstractEnclave.java b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/AbstractEnclave.java index 15eefb1..486a59d 100644 --- a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/AbstractEnclave.java +++ b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/AbstractEnclave.java @@ -44,11 +44,13 @@ abstract class AbstractEnclave implements Enclave { return enclaveContext; } - abstract InnerNativeInvocationResult loadServiceNative(byte[] payload); + abstract byte[] loadServiceNative(byte[] payload) throws ServicesLoadingException; - abstract InnerNativeInvocationResult unloadServiceNative(byte[] payload); + abstract byte[] unloadServiceNative(byte[] payload) throws ServicesUnloadingException; - abstract InnerNativeInvocationResult invokeMethodNative(byte[] payload); + abstract byte[] invokeMethodNative(byte[] payload) throws EnclaveMethodInvokingException; + + abstract AttestationReport generateAttestationReportNative(byte[] userData) throws RemoteAttestationException; // load service by interface name. ServiceHandler[] loadService(Class<?> service) throws ServicesLoadingException { @@ -64,15 +66,9 @@ abstract class AbstractEnclave implements Enclave { } catch (IOException e) { throw new ServicesLoadingException("service name serialization failed.", e); } - InnerNativeInvocationResult resultNativeWrapper = loadServiceNative(payload); - // If loadServiceNative native call return value is error, an ServicesLoadingException exception - // will be thrown. - if (resultNativeWrapper.getRet() != 0) { - throw new ServicesLoadingException("load service native call failed."); - } EnclaveInvocationResult resultWrapper; try { - resultWrapper = (EnclaveInvocationResult) SerializationHelper.deserialize(resultNativeWrapper.getPayload()); + resultWrapper = (EnclaveInvocationResult) SerializationHelper.deserialize(loadServiceNative(payload)); } catch (IOException | ClassNotFoundException e) { throw new ServicesLoadingException("EnclaveInvokeResultWrapper deserialization failed.", e); } @@ -108,13 +104,9 @@ abstract class AbstractEnclave implements Enclave { } catch (IOException e) { throw new ServicesUnloadingException("unload service serialization failed.", e); } - InnerNativeInvocationResult resultNativeWrapper = unloadServiceNative(payload); - if (resultNativeWrapper.getRet() != 0) { - throw new ServicesUnloadingException("unload service native call failed."); - } EnclaveInvocationResult resultWrapper; try { - resultWrapper = (EnclaveInvocationResult) SerializationHelper.deserialize(resultNativeWrapper.getPayload()); + resultWrapper = (EnclaveInvocationResult) SerializationHelper.deserialize(unloadServiceNative(payload)); } catch (IOException | ClassNotFoundException e) { throw new ServicesUnloadingException("EnclaveInvokeResultWrapper deserialization failed.", e); } @@ -139,13 +131,9 @@ abstract class AbstractEnclave implements Enclave { } catch (IOException e) { throw new EnclaveMethodInvokingException("EnclaveInvokeMetaWrapper serialization failed.", e); } - InnerNativeInvocationResult resultNativeWrapper = invokeMethodNative(payload); - if (resultNativeWrapper.getRet() != 0) { - throw new EnclaveMethodInvokingException("method invoke native call failed."); - } EnclaveInvocationResult resultWrapper; try { - resultWrapper = (EnclaveInvocationResult) SerializationHelper.deserialize(resultNativeWrapper.getPayload()); + resultWrapper = (EnclaveInvocationResult) SerializationHelper.deserialize(invokeMethodNative(payload)); } catch (IOException | ClassNotFoundException e) { throw new EnclaveMethodInvokingException("EnclaveInvokeResultWrapper deserialization failed.", e); } @@ -161,7 +149,16 @@ abstract class AbstractEnclave implements Enclave { } } - abstract AttestationReport generateAttestationReport(byte[] userData) throws RemoteAttestationException; + AttestationReport generateAttestationReport(byte[] userData) throws RemoteAttestationException { + if (!getEnclaveContext().getEnclaveToken().tryAcquireToken()) { + throw new RemoteAttestationException("enclave was destroyed."); + } + try { + return generateAttestationReportNative(userData); + } finally { + getEnclaveContext().getEnclaveToken().restoreToken(); + } + } @Override public <T> Iterator<T> load(Class<T> service) throws ServicesLoadingException { diff --git a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/AttestationReport.java b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/AttestationReport.java index 4dd574d..dd8bcf9 100644 --- a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/AttestationReport.java +++ b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/AttestationReport.java @@ -5,15 +5,15 @@ import java.io.Serializable; /** * AttestationReport wraps enclave's type and generated remote attestation report. */ -public final class AttestationReport implements Serializable { +public class AttestationReport implements Serializable { private static final long serialVersionUID = -2781780414647128479L; private final EnclaveType enclaveType; - private final byte[] report; + private final byte[] quote; - AttestationReport(EnclaveType enclaveType, byte[] report) { + AttestationReport(EnclaveType enclaveType, byte[] quote) { this.enclaveType = enclaveType; - this.report = report; + this.quote = quote; } /** @@ -27,25 +27,25 @@ public final class AttestationReport implements Serializable { } /** - * Get enclave report from an AttestationReport instance. + * Get enclave quote from an AttestationReport instance. * <p> * - * @return Remote attestation report data. + * @return Remote attestation quote data. */ - public byte[] getReport() { - return report; + public byte[] getQuote() { + return quote; } /** - * Bind an AttestationReport's type and report into a buffer for rpc transmission. + * Bind an AttestationReport's type and quote into a buffer for rpc transmission. * <p> * * @return Serialized buffer. */ public byte[] toByteArray() { - byte[] bindReport = new byte[1 + report.length]; + byte[] bindReport = new byte[1 + quote.length]; bindReport[0] = (byte) enclaveType.ordinal(); - System.arraycopy(report, 0, bindReport, 1, report.length); + System.arraycopy(quote, 0, bindReport, 1, quote.length); return bindReport; } diff --git a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/InnerNativeInvocationResult.java b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/InnerNativeInvocationResult.java deleted file mode 100644 index 6e8e240..0000000 --- a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/InnerNativeInvocationResult.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.alibaba.confidentialcomputing.host; - -/** - * InnerNativeInvocationResult is load_service unload_service and invoke_method - * native call's return value. It not only contains enclave e_call's return value, - * also contains an EnclaveInvocationResult object's serialization payload from - * method invocation in enclave. - */ -class InnerNativeInvocationResult { - // enclave method native call's result. - private final int ret; - // payload is an EnclaveInvocationResult object's serialization data. - private final byte[] payload; - - InnerNativeInvocationResult(int ret, byte[] payload) { - this.ret = ret; - this.payload = payload; - } - - int getRet() { - return ret; - } - - byte[] getPayload() { - return payload; - } -} diff --git a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/MockInJvmEnclave.java b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/MockInJvmEnclave.java index 030feaf..dc2e982 100644 --- a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/MockInJvmEnclave.java +++ b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/MockInJvmEnclave.java @@ -1,6 +1,6 @@ package com.alibaba.confidentialcomputing.host; -import com.alibaba.confidentialcomputing.host.exception.RemoteAttestationException; +import com.alibaba.confidentialcomputing.host.exception.*; /** * MockInJvmEnclave is a mock jvm enclave. Both host and enclave codes run @@ -13,7 +13,7 @@ class MockInJvmEnclave extends AbstractEnclave { } @Override - AttestationReport generateAttestationReport(byte[] userData) throws RemoteAttestationException { + AttestationReport generateAttestationReportNative(byte[] userData) throws RemoteAttestationException { throw new RemoteAttestationException("MOCK_IN_JVM enclave doesn't support remote attestation generation."); } @@ -22,22 +22,22 @@ class MockInJvmEnclave extends AbstractEnclave { } @Override - InnerNativeInvocationResult loadServiceNative(byte[] payload) { + byte[] loadServiceNative(byte[] payload) throws ServicesLoadingException { return null; } @Override - InnerNativeInvocationResult unloadServiceNative(byte[] payload) { + byte[] unloadServiceNative(byte[] payload) throws ServicesUnloadingException { return null; } @Override - InnerNativeInvocationResult invokeMethodNative(byte[] payload) { + byte[] invokeMethodNative(byte[] payload) throws EnclaveMethodInvokingException { return null; } @Override - public void destroy() { + public void destroy() throws EnclaveDestroyingException { ; // Do nothing here. } } diff --git a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/MockInSvmEnclave.java b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/MockInSvmEnclave.java index 3c4d030..d953afe 100644 --- a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/MockInSvmEnclave.java +++ b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/MockInSvmEnclave.java @@ -1,7 +1,6 @@ package com.alibaba.confidentialcomputing.host; -import com.alibaba.confidentialcomputing.host.exception.EnclaveCreatingException; -import com.alibaba.confidentialcomputing.host.exception.EnclaveDestroyingException; +import com.alibaba.confidentialcomputing.host.exception.*; import com.alibaba.confidentialcomputing.host.exception.RemoteAttestationException; import java.io.IOException; @@ -54,19 +53,13 @@ class MockInSvmEnclave extends AbstractEnclave { } // Create svm sdk enclave by native call, enclaveSvmSdkHandle are set in jni in nativeHandlerContext. - int ret = nativeCreateEnclave(extractTempPath.getEnclaveSvmFilePath()); - if (ret != 0) { - throw new EnclaveCreatingException("create svm sdk enclave by native calling failed."); - } + nativeCreateEnclave(extractTempPath.getEnclaveSvmFilePath()); // Create svm attach isolate and isolateThread, and they are set in jni in nativeHandlerContext. - ret = nativeSvmAttachIsolate(enclaveSvmSdkHandle); - if (ret != 0) { - throw new EnclaveCreatingException("create svm isolate by native calling failed."); - } + nativeSvmAttachIsolate(enclaveSvmSdkHandle); } @Override - AttestationReport generateAttestationReport(byte[] userData) throws RemoteAttestationException { + AttestationReport generateAttestationReportNative(byte[] userData) throws RemoteAttestationException { throw new RemoteAttestationException("MOCK_IN_SVM enclave doesn't support remote attestation generation."); } @@ -75,17 +68,17 @@ class MockInSvmEnclave extends AbstractEnclave { } @Override - InnerNativeInvocationResult loadServiceNative(byte[] payload) { + byte[] loadServiceNative(byte[] payload) throws ServicesLoadingException { return nativeLoadService(enclaveSvmSdkHandle, isolateHandle, payload); } @Override - InnerNativeInvocationResult unloadServiceNative(byte[] payload) { + byte[] unloadServiceNative(byte[] payload) throws ServicesUnloadingException { return nativeUnloadService(enclaveSvmSdkHandle, isolateHandle, payload); } @Override - InnerNativeInvocationResult invokeMethodNative(byte[] payload) { + byte[] invokeMethodNative(byte[] payload) throws EnclaveMethodInvokingException { return nativeInvokeMethod(enclaveSvmSdkHandle, isolateHandle, payload); } @@ -96,45 +89,26 @@ class MockInSvmEnclave extends AbstractEnclave { // interrupt enclave services' recycler firstly. this.getEnclaveContext().getEnclaveServicesRecycler().interruptServiceRecycler(); // destroy svm isolate. - int ret = nativeSvmDetachIsolate(enclaveSvmSdkHandle, isolateThreadHandle); - if (ret != 0) { - throw new EnclaveDestroyingException("isolate destroy native call failed."); - } - ret = nativeDestroyEnclave(enclaveSvmSdkHandle); - if (ret != 0) { - throw new EnclaveDestroyingException("enclave destroy native call failed."); - } + nativeSvmDetachIsolate(enclaveSvmSdkHandle, isolateThreadHandle); + nativeDestroyEnclave(enclaveSvmSdkHandle); } } private static native void registerNatives(); - private native int nativeCreateEnclave(String path); + private native int nativeCreateEnclave(String path) throws EnclaveCreatingException; - private native int nativeSvmAttachIsolate( - long enclaveSvmSdkHandle); + private native int nativeSvmAttachIsolate(long enclaveSvmSdkHandle) throws EnclaveCreatingException; - private native InnerNativeInvocationResult nativeLoadService( - long enclaveSvmSdkHandle, - long isolateHandler, - byte[] serviceHandler); + private native byte[] nativeLoadService(long enclaveSvmSdkHandle, long isolateHandler, byte[] serviceHandler) throws ServicesLoadingException; - private native InnerNativeInvocationResult nativeInvokeMethod( - long enclaveSvmSdkHandle, - long isolateHandler, - byte[] enclaveInvokeMetaWrapper); + private native byte[] nativeInvokeMethod(long enclaveSvmSdkHandle, long isolateHandler, byte[] enclaveInvokeMetaWrapper) throws EnclaveMethodInvokingException; - private native InnerNativeInvocationResult nativeUnloadService( - long enclaveSvmSdkHandle, - long isolateHandler, - byte[] serviceHandler); + private native byte[] nativeUnloadService(long enclaveSvmSdkHandle, long isolateHandler, byte[] serviceHandler) throws ServicesUnloadingException; - private native int nativeSvmDetachIsolate( - long enclaveSvmSdkHandle, - long isolateThreadHandler); + private native int nativeSvmDetachIsolate(long enclaveSvmSdkHandle, long isolateThreadHandler) throws EnclaveDestroyingException; - private native int nativeDestroyEnclave( - long enclaveSvmSdkHandle); + private native int nativeDestroyEnclave(long enclaveSvmSdkHandle) throws EnclaveDestroyingException; class MockInSvmExtractTempPath { private final String jniTempFilePath; diff --git a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/RemoteAttestation.java b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/RemoteAttestation.java index c5bd9df..239a35d 100644 --- a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/RemoteAttestation.java +++ b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/RemoteAttestation.java @@ -52,11 +52,15 @@ public final class RemoteAttestation { * * @param report signed data in an enclave and its tee type info. * @return Zero means enclave is valid, Other value means enclave is invalid. + * @throws RemoteAttestationException {@link RemoteAttestationException} If enclave remote + * attestation verify failed. */ public static int verifyAttestationReport(AttestationReport report) throws RemoteAttestationException { - if (report.getEnclaveType() != EnclaveType.TEE_SDK) { - throw new RemoteAttestationException("enclaveType must be TEE_SDK."); + switch (report.getEnclaveType()) { + case TEE_SDK: + return TeeSdkEnclave.verifyAttestationReport(report.getQuote()); + default: + throw new RemoteAttestationException("enclaveType must be TEE_SDK."); } - return TeeSdkEnclave.verifyAttestationReport(report.getReport()); } } diff --git a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/RemoteAttestationVerifyResult.java b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/RemoteAttestationVerifyResult.java new file mode 100644 index 0000000..b99cb2d --- /dev/null +++ b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/RemoteAttestationVerifyResult.java @@ -0,0 +1,25 @@ +package com.alibaba.confidentialcomputing.host; + +class RemoteAttestationVerifyResult { + private volatile int status; + private volatile int versionCheck; + private volatile int verifyFlag; + + RemoteAttestationVerifyResult(int status, int versionCheck, int verifyFlag) { + this.status = status; + this.versionCheck = versionCheck; + this.verifyFlag = verifyFlag; + } + + int getStatus() { + return this.status; + } + + int getVersionCheck() { + return this.versionCheck; + } + + int getVerifyFlag() { + return this.verifyFlag; + } +} diff --git a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/SGXRemoteAttestationVerify.java b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/SGXRemoteAttestationVerify.java new file mode 100644 index 0000000..c8c0343 --- /dev/null +++ b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/SGXRemoteAttestationVerify.java @@ -0,0 +1,46 @@ +package com.alibaba.confidentialcomputing.host; + +import com.alibaba.confidentialcomputing.host.ExtractLibrary; +import com.alibaba.confidentialcomputing.host.exception.RemoteAttestationException; + +import java.io.IOException; + +public class SGXRemoteAttestationVerify { + private final static String JNI_EXTRACTED_PACKAGE_PATH = "remote_attestation/sgx/jni/lib_jni_sgx_remote_attestation_verify.so"; + + static { + try { + String jniTempFilePath = ExtractLibrary.extractLibrary(SGXRemoteAttestationVerify.class.getClassLoader(), + JNI_EXTRACTED_PACKAGE_PATH); + System.load(jniTempFilePath); + registerNatives(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static native void registerNatives(); + private static native int nativeVerifyAttestationReport(byte[] report, RemoteAttestationVerifyResult result); + + public static int VerifyAttestationReport(byte[] report) throws RemoteAttestationException { + RemoteAttestationVerifyResult verifyResult = new RemoteAttestationVerifyResult(0, 0, 0); + nativeVerifyAttestationReport(report, verifyResult); + if (verifyResult.getVersionCheck() == -1) { + throw new RemoteAttestationException("sgx_qv_get_quote_supplemental_data_size returned size is not same with header definition in SGX SDK"); + } else if (verifyResult.getStatus() == 1) { + throw new RemoteAttestationException("sgx_qv_get_quote_supplemental_data_size failed"); + } else if (verifyResult.getStatus() == 2) { + throw new RemoteAttestationException("sgx_qv_verify_quote failed"); + } else if (verifyResult.getStatus() == 3) { + throw new RemoteAttestationException("supplemental data memory allocation failed"); + } else if (verifyResult.getVerifyFlag() == 1) { + throw new RemoteAttestationException("verification completed, but collateral is out of date"); + } else if (verifyResult.getVerifyFlag() == 2) { + throw new RemoteAttestationException("verification completed with non-terminal result"); + } else if (verifyResult.getVerifyFlag() == 3) { + throw new RemoteAttestationException("verification completed with terminal result, but verification check failed"); + } else { + return verifyResult.getVerifyFlag(); + } + } +} diff --git a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/TeeSdkAttestationReport.java b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/TeeSdkAttestationReport.java new file mode 100644 index 0000000..6ab0f44 --- /dev/null +++ b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/TeeSdkAttestationReport.java @@ -0,0 +1,35 @@ +package com.alibaba.confidentialcomputing.host; + +/** + * TeeSdkAttestationReport parse more details information from a tee sdk type enclave's remote attestation report. + */ +public final class TeeSdkAttestationReport extends AttestationReport { + private final byte[] mrSigner; + private final byte[] mrEnclave; + + TeeSdkAttestationReport(byte[] quote, byte[] mrSigner, byte[] mrEnclave) { + super(EnclaveType.TEE_SDK, quote); + this.mrSigner = mrSigner; + this.mrEnclave = mrEnclave; + } + + /** + * Get enclave measurementEnclave from an enclave's remote attestation report. + * <p> + * + * @return Remote attestation measurementEnclave value. + */ + public byte[] getMeasurementEnclave() { + return this.mrEnclave; + } + + /** + * Get enclave measurementSigner from an enclave's remote attestation report. + * <p> + * + * @return Remote attestation measurementSigner value. + */ + public byte[] getMeasurementSigner() { + return this.mrSigner; + } +} diff --git a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/TeeSdkEnclave.java b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/TeeSdkEnclave.java index ef71ece..50bd225 100644 --- a/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/TeeSdkEnclave.java +++ b/sdk/host/src/main/java/com/alibaba/confidentialcomputing/host/TeeSdkEnclave.java @@ -1,8 +1,6 @@ package com.alibaba.confidentialcomputing.host; -import com.alibaba.confidentialcomputing.host.exception.EnclaveCreatingException; -import com.alibaba.confidentialcomputing.host.exception.EnclaveDestroyingException; -import com.alibaba.confidentialcomputing.host.exception.RemoteAttestationException; +import com.alibaba.confidentialcomputing.host.exception.*; import java.io.IOException; @@ -49,75 +47,53 @@ class TeeSdkEnclave extends AbstractEnclave { } // Create tee sdk enclave by native call, enclaveHandler is set in jni in nativeHandlerContext. - int ret = nativeCreateEnclave(mode.getValue(), extractTempPath.getTeeSdkSignedFilePath()); - if (ret != 0) { - throw new EnclaveCreatingException("create tee sdk enclave by native calling failed."); - } + nativeCreateEnclave(mode.getValue(), extractTempPath.getTeeSdkSignedFilePath()); // Create svm attach isolate and isolateThread, and they are set in jni in nativeHandlerContext. - ret = nativeSvmAttachIsolate(enclaveHandle); - if (ret != 0) { - throw new EnclaveCreatingException("create svm isolate by native calling failed."); - } + nativeSvmAttachIsolate(enclaveHandle); } private static native void registerNatives(); - private native int nativeCreateEnclave(int mode, String path); - - private native InnerNativeInvocationResult nativeGenerateAttestationReport(byte[] userData); - - private static native InnerNativeInvocationResult nativeVerifyAttestationReport(byte[] report); + private native int nativeCreateEnclave(int mode, String path) throws EnclaveCreatingException; - private native int nativeSvmAttachIsolate(long enclaveHandler); + private native TeeSdkAttestationReport nativeGenerateAttestationReport(long enclaveHandler, byte[] userData) throws RemoteAttestationException; - private native InnerNativeInvocationResult nativeLoadService( - long enclaveHandler, long isolateHandler, byte[] serviceHandler); + private native int nativeSvmAttachIsolate(long enclaveHandler) throws EnclaveCreatingException; - private native InnerNativeInvocationResult nativeInvokeMethod( - long enclaveHandler, long isolateHandler, byte[] enclaveInvokeMetaWrapper); + private native byte[] nativeLoadService(long enclaveHandler, long isolateHandler, byte[] serviceHandler) throws ServicesLoadingException; - private native InnerNativeInvocationResult nativeUnloadService( - long enclaveHandler, long isolateHandler, byte[] serviceHandler); + private native byte[] nativeInvokeMethod(long enclaveHandler, long isolateHandler, byte[] enclaveInvokeMetaWrapper) throws EnclaveMethodInvokingException; - private native int nativeSvmDetachIsolate(long enclaveHandler, long isolateThreadHandler); + private native byte[] nativeUnloadService(long enclaveHandler, long isolateHandler, byte[] serviceHandler) throws ServicesUnloadingException; - private native int nativeDestroyEnclave(long enclaveHandler); + private native int nativeSvmDetachIsolate(long enclaveHandler, long isolateThreadHandler) throws EnclaveDestroyingException; - @Override - AttestationReport generateAttestationReport(byte[] userData) throws RemoteAttestationException { - InnerNativeInvocationResult result = nativeGenerateAttestationReport(userData); - if (result.getRet() != 0) { - throw new RemoteAttestationException("TEE_SDK's attestation report generation native call error code: " + result.getRet()); - } - return new AttestationReport(EnclaveType.TEE_SDK, result.getPayload()); - } + private native int nativeDestroyEnclave(long enclaveHandler) throws EnclaveDestroyingException; - static int verifyAttestationReport(byte[] report) throws RemoteAttestationException { - InnerNativeInvocationResult result = nativeVerifyAttestationReport(report); - if (result.getRet() != 0) { - throw new RemoteAttestationException("TEE_SDK's attestation verification native call error code: " + result.getRet()); - } - if (result.getPayload() == null) { - return 0; // Remote Attestation Verification result is succeed. - } - return 1; // Remote Attestation Verification result is failed. + static int verifyAttestationReport(byte[] quote) throws RemoteAttestationException { + return SGXRemoteAttestationVerify.VerifyAttestationReport(quote); } @Override - InnerNativeInvocationResult loadServiceNative(byte[] payload) { + byte[] loadServiceNative(byte[] payload) throws ServicesLoadingException { return nativeLoadService(enclaveHandle, isolateHandle, payload); } @Override - InnerNativeInvocationResult unloadServiceNative(byte[] payload) { + byte[] unloadServiceNative(byte[] payload) throws ServicesUnloadingException { return nativeUnloadService(enclaveHandle, isolateHandle, payload); } @Override - InnerNativeInvocationResult invokeMethodNative(byte[] payload) { + byte[] invokeMethodNative(byte[] payload) throws EnclaveMethodInvokingException { return nativeInvokeMethod(enclaveHandle, isolateHandle, payload); } + @Override + AttestationReport generateAttestationReportNative(byte[] userData) throws RemoteAttestationException { + return nativeGenerateAttestationReport(enclaveHandle, userData); + } + @Override public void destroy() throws EnclaveDestroyingException { // destroyToken will wait for all ongoing enclave invocations finished. @@ -125,19 +101,13 @@ class TeeSdkEnclave extends AbstractEnclave { // interrupt enclave services' recycler firstly. this.getEnclaveContext().getEnclaveServicesRecycler().interruptServiceRecycler(); // destroy svm isolate. - int ret = nativeSvmDetachIsolate(enclaveHandle, isolateThreadHandle); - if (ret != 0) { - throw new EnclaveDestroyingException("isolate destroy native call failed."); - } + nativeSvmDetachIsolate(enclaveHandle, isolateThreadHandle); // destroy the enclave. - ret = nativeDestroyEnclave(enclaveHandle); - if (ret != 0) { - throw new EnclaveDestroyingException("enclave destroy native call failed."); - } + nativeDestroyEnclave(enclaveHandle); } } - class TeeSdkExtractTempPath { + static class TeeSdkExtractTempPath { private final String jniTempFilePath; private final String teeSdkSignedFilePath; diff --git a/sdk/host/src/main/native/cpp/attestation_verify/sgx/jni/Makefile b/sdk/host/src/main/native/cpp/attestation_verify/sgx/jni/Makefile new file mode 100644 index 0000000..fda3ec9 --- /dev/null +++ b/sdk/host/src/main/native/cpp/attestation_verify/sgx/jni/Makefile @@ -0,0 +1,17 @@ +# Copyright (c) + +include $(NATIVE_BASE_DIR)/config/config.mk +include $(NATIVE_BASE_DIR)/config/remote_attestation_verify/sgx/config.mk + +.PHONY: all build clean + +all: build + +build: + $(CC) -g -c -Wno-unused-parameter $(RA_VERIFY_INCDIR) -I$(JAVA_HOME)/lib -I$(JAVA_HOME)/include \ + -I$(JAVA_HOME)/include/$(shell uname -s | tr A-Z a-z) -fPIC jni_remote_attestation_verify.c + $(CC) jni_remote_attestation_verify.o $(RA_VERIFY_LDFLAGS) -fPIC -shared -o $(BIN)/remote_attestation/sgx/jni/lib_jni_sgx_remote_attestation_verify.so + +clean: + rm -rf *.o + rm -rf $(BIN)/remote_attestation/sgx/jni/lib_jni_sgx_remote_attestation_verify.so \ No newline at end of file diff --git a/sdk/host/src/main/native/cpp/attestation_verify/sgx/jni/jni_remote_attestation_verify.c b/sdk/host/src/main/native/cpp/attestation_verify/sgx/jni/jni_remote_attestation_verify.c new file mode 100644 index 0000000..fa53006 --- /dev/null +++ b/sdk/host/src/main/native/cpp/attestation_verify/sgx/jni/jni_remote_attestation_verify.c @@ -0,0 +1,118 @@ +#include "jni_remote_attestation_verify.h" + +#define QUOTE_VERIFICATION_STATUS_SUCCESS 0 +#define QUOTE_VERIFICATION_STATUS_GET_DATA_SIZE_FAILED 1 +#define QUOTE_VERIFICATION_STATUS_QUOTE_VERIFY_FAILED 2 +#define QUOTE_VERIFICATION_STATUS_MEMORY_MALLOC_FAILED 3 +#define QUOTE_VERIFICATION_VERSION_CHECK_SUCCESS 0 +#define QUOTE_VERIFICATION_VERSION_CHECK_FAILED -1 +#define QUOTE_VERIFICATION_SUCCESS 0 +#define QUOTE_VERIFICATION_OUT_OF_DATA 1 +#define QUOTE_VERIFICATION_NO_TERMINAL 2 +#define QUOTE_VERIFICATION_FAILED_WITH_TERMINAL 3 + +static JNINativeMethod sgx_remote_attestation_verify_methods[] = { + {"nativeVerifyAttestationReport", SGX_ENCLAVE_REMOTE_ATTESTATION_VERIFY_SIGNATURE, (void *)&JavaEnclave_SGX_ENCLAVE_REMOTE_ATTESTATION_VERIFY}, +}; + +void set_int_field_value(JNIEnv *env, jclass class_mirror, jobject obj, const char *field_name, jint value) { + jfieldID field_id = (*env)->GetFieldID(env, class_mirror, field_name, "I"); + (*env)->SetIntField(env, obj, field_id, value); +} + +verify_result_wrapper ecdsa_quote_verification_qvl(const uint8_t* quote, uint32_t length) { + verify_result_wrapper result; + result.status = QUOTE_VERIFICATION_STATUS_SUCCESS; + result.version_check = QUOTE_VERIFICATION_VERSION_CHECK_SUCCESS; + result.verify_flag = QUOTE_VERIFICATION_SUCCESS; + + quote3_error_t dcap_ret = SGX_QL_ERROR_UNEXPECTED; + uint32_t supplemental_data_size = 0; + uint8_t *p_supplemental_data = NULL; + time_t current_time = 0; + uint32_t collateral_expiration_status = 1; + sgx_ql_qv_result_t quote_verification_result = SGX_QL_QV_RESULT_UNSPECIFIED; + + // Step one, get supplemental_data_size. + dcap_ret = sgx_qv_get_quote_supplemental_data_size(&supplemental_data_size); + if (dcap_ret != SGX_QL_SUCCESS) { + // printf("JavaEnclave Remote Attestation Error: sgx_qv_get_quote_supplemental_data_size failed: 0x%04x\n", dcap_ret); + result.status = QUOTE_VERIFICATION_STATUS_GET_DATA_SIZE_FAILED; + return result; + } + if (supplemental_data_size != sizeof(sgx_ql_qv_supplemental_t)) { + // printf("JavaEnclave Remote Attestation Warning: sgx_qv_get_quote_supplemental_data_size returned size is not same with header definition in SGX SDK, please make sure you are using same version of SGX SDK and DCAP QVL.\n"); + result.version_check = QUOTE_VERIFICATION_VERSION_CHECK_FAILED; + return result; + } + + p_supplemental_data = (uint8_t*)malloc(supplemental_data_size); + if (p_supplemental_data != NULL) { + memset(p_supplemental_data, 0, sizeof(supplemental_data_size)); + } else { + result.status = QUOTE_VERIFICATION_STATUS_MEMORY_MALLOC_FAILED; + return result; + } + + current_time = time(NULL); + dcap_ret = sgx_qv_verify_quote( + quote, length, NULL, + current_time, &collateral_expiration_status, + "e_verification_result, NULL, + supplemental_data_size, p_supplemental_data); + + free(p_supplemental_data); + + if (dcap_ret != SGX_QL_SUCCESS) { + result.status = QUOTE_VERIFICATION_STATUS_QUOTE_VERIFY_FAILED; + // printf("JavaEnclave Remote Attestation Error: sgx_qv_verify_quote failed: 0x%04x\n", dcap_ret); + return result; + } + + switch (quote_verification_result) { + case SGX_QL_QV_RESULT_OK: + if (collateral_expiration_status == 0) { + // Verification completed successfully. + result.verify_flag = QUOTE_VERIFICATION_SUCCESS; + } else { + // Verification completed, but collateral is out of date based on 'expiration_check_date' you provided. + result.verify_flag = QUOTE_VERIFICATION_OUT_OF_DATA; + } + break; + case SGX_QL_QV_RESULT_CONFIG_NEEDED: + case SGX_QL_QV_RESULT_OUT_OF_DATE: + case SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED: + case SGX_QL_QV_RESULT_SW_HARDENING_NEEDED: + case SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED: + // Verification completed with Non-terminal result, you could view value of quote_verification_result for more info. + result.verify_flag = QUOTE_VERIFICATION_NO_TERMINAL; + break; + case SGX_QL_QV_RESULT_INVALID_SIGNATURE: + case SGX_QL_QV_RESULT_REVOKED: + case SGX_QL_QV_RESULT_UNSPECIFIED: + default: + // Verification completed with Terminal result, you could view value of quote_verification_result for more info. + result.verify_flag = QUOTE_VERIFICATION_FAILED_WITH_TERMINAL; + break; + } + return result; +} + +JNIEXPORT void JNICALL Java_com_alibaba_confidentialcomputing_host_SGXRemoteAttestationVerify_registerNatives(JNIEnv *env, jclass cls) { + (*env)->RegisterNatives(env, cls, sgx_remote_attestation_verify_methods, sizeof(sgx_remote_attestation_verify_methods)/sizeof(sgx_remote_attestation_verify_methods[0])); +} + +JNIEXPORT jint JNICALL +JavaEnclave_SGX_ENCLAVE_REMOTE_ATTESTATION_VERIFY(JNIEnv *env, jclass mirror, jbyteArray quote, jobject jResult) { + jbyte *quote_copy = (*env)->GetByteArrayElements(env, quote, NULL); + int quote_length = (*env)->GetArrayLength(env, quote); + verify_result_wrapper result = ecdsa_quote_verification_qvl(quote_copy, quote_length); + (*env)->ReleaseByteArrayElements(env, quote, quote_copy, 0); + + jclass j_result_class = (*env)->GetObjectClass(env, jResult); + set_int_field_value(env, j_result_class, jResult, "status", (jint)result.status); + set_int_field_value(env, j_result_class, jResult, "versionCheck", (jint)result.version_check); + set_int_field_value(env, j_result_class, jResult, "verifyFlag", (jint)result.verify_flag); + + return 0; +} \ No newline at end of file diff --git a/sdk/host/src/main/native/cpp/attestation_verify/sgx/jni/jni_remote_attestation_verify.h b/sdk/host/src/main/native/cpp/attestation_verify/sgx/jni/jni_remote_attestation_verify.h new file mode 100644 index 0000000..a387909 --- /dev/null +++ b/sdk/host/src/main/native/cpp/attestation_verify/sgx/jni/jni_remote_attestation_verify.h @@ -0,0 +1,45 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class com_alibaba_confidentialcomputing_host_SGXRemoteAttestationVerify */ + +#include <stdio.h> +#include <stdlib.h> + +#include "sgx_urts.h" +#include "sgx_ql_quote.h" +#include "sgx_dcap_quoteverify.h" + +#ifndef _Included_com_alibaba_confidentialcomputing_host_SGXRemoteAttestationVerify +#define _Included_com_alibaba_confidentialcomputing_host_SGXRemoteAttestationVerify +#ifdef __cplusplus +extern "C" { +#endif + +#define SGX_ENCLAVE_REMOTE_ATTESTATION_VERIFY_SIGNATURE "([BLcom/alibaba/confidentialcomputing/host/RemoteAttestationVerifyResult;)I" + +typedef struct { + int status; + int version_check; + int verify_flag; +} verify_result_wrapper; + +/* + * Class: com_alibaba_confidentialcomputing_host_SGXRemoteAttestationVerify + * Method: registerNatives + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_alibaba_confidentialcomputing_host_SGXRemoteAttestationVerify_registerNatives + (JNIEnv *, jclass); + +/* + * Class: com_alibaba_confidentialcomputing_host_SGXRemoteAttestationVerify + * Method: nativeVerifyAttestationReport + * Signature: ([BLcom/alibaba/confidentialcomputing/host/RemoteAttestationVerifyResult;)I + */ +JNIEXPORT jint JNICALL JavaEnclave_SGX_ENCLAVE_REMOTE_ATTESTATION_VERIFY + (JNIEnv *, jclass, jbyteArray, jobject); + +#ifdef __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/sdk/host/src/main/native/cpp/platform/mock_in_svm/jni/jni_mock_in_svm.c b/sdk/host/src/main/native/cpp/platform/mock_in_svm/jni/jni_mock_in_svm.c index 88be3a0..32c189b 100644 --- a/sdk/host/src/main/native/cpp/platform/mock_in_svm/jni/jni_mock_in_svm.c +++ b/sdk/host/src/main/native/cpp/platform/mock_in_svm/jni/jni_mock_in_svm.c @@ -18,9 +18,9 @@ typedef int (*mock_enclave_stub)(graal_isolate_t*, enc_data_t*, enc_data_t*, cal static JNINativeMethod mock_in_svm_methods[] = { {"nativeCreateEnclave", "(Ljava/lang/String;)I", (void *)&JavaEnclave_MockSVMNativeCreateEnclave}, {"nativeSvmAttachIsolate", "(J)I", (void *)&JavaEnclave_MockSVMNativeSvmAttachIsolate}, - {"nativeLoadService", MOCK_IN_SVM_NATIVE_CALL_SIGNATURE, (void *)&JavaEnclave_MockSVMNativeLoadService}, - {"nativeInvokeMethod", MOCK_IN_SVM_NATIVE_CALL_SIGNATURE, (void *)&JavaEnclave_MockSVMNativeInvokeMethod}, - {"nativeUnloadService", MOCK_IN_SVM_NATIVE_CALL_SIGNATURE, (void *)&JavaEnclave_MockSVMNativeUnloadService}, + {"nativeLoadService", "(JJ[B)[B", (void *)&JavaEnclave_MockSVMNativeLoadService}, + {"nativeInvokeMethod", "(JJ[B)[B", (void *)&JavaEnclave_MockSVMNativeInvokeMethod}, + {"nativeUnloadService", "(JJ[B)[B", (void *)&JavaEnclave_MockSVMNativeUnloadService}, {"nativeSvmDetachIsolate", "(JJ)I", (void *)&JavaEnclave_MockSVMNativeSvmDetachIsolate}, {"nativeDestroyEnclave", "(J)I", (void *)&JavaEnclave_MockSVMNativeDestroyEnclave}, }; @@ -46,14 +46,7 @@ char* memcpy_char_pointer(char* src, int len) { return (char*)ptr; } -jobject build_invocation_result(JNIEnv *env, jint ret, jbyteArray array) { - // build jni return object InnerNativeInvocationResult. - jclass invocation_result_clazz = (*env)->FindClass(env, MOCK_IN_SVM_RETURN_OBJECT_SIGNATURE); - jmethodID id = (*env)->GetMethodID(env, invocation_result_clazz, "<init>", "(I[B)V"); - return (*env)->NewObject(env, invocation_result_clazz, id, (jint)ret, array); -} - -jobject mock_enclave_calling_entry(JNIEnv *env, jlong isolate_handler, jbyteArray payload, mock_enclave_stub stub) { +enclave_calling_stub_result mock_enclave_calling_entry(JNIEnv *env, jlong isolate_handler, jbyteArray payload, mock_enclave_stub stub) { jbyte *payload_copy = (*env)->GetByteArrayElements(env, payload, NULL); int payload_copy_length = (*env)->GetArrayLength(env, payload); @@ -64,14 +57,25 @@ jobject mock_enclave_calling_entry(JNIEnv *env, jlong isolate_handler, jbyteArra output.data = NULL; output.data_len = 0x0; + jbyteArray invocation_result_array; + enclave_calling_stub_result result_wrapper; + result_wrapper.ret = 0; + result_wrapper.result = invocation_result_array; + callbacks_t callback_methods; callback_methods.memcpy_char_pointer = &memcpy_char_pointer; callback_methods.exception_handler = NULL; callback_methods.get_random_number = NULL; - int ret = stub((graal_isolate_t*)isolate_handler, &input, &output, &callback_methods); + + result_wrapper.ret = stub((graal_isolate_t*)isolate_handler, &input, &output, &callback_methods); + if (result_wrapper.ret != 0) { + (*env)->ReleaseByteArrayElements(env, payload, payload_copy, 0); + free(output.data); + return result_wrapper; + } // create a byte array. - jbyteArray invocation_result_array = (*env)->NewByteArray(env, output.data_len); + invocation_result_array = (*env)->NewByteArray(env, output.data_len); jbyte *invocation_result_array_ptr = (*env)->GetByteArrayElements(env, invocation_result_array, NULL); memcpy(invocation_result_array_ptr, output.data, output.data_len); @@ -81,7 +85,8 @@ jobject mock_enclave_calling_entry(JNIEnv *env, jlong isolate_handler, jbyteArra // free buffer malloc in native image by callback mechanism. free(output.data); - return build_invocation_result(env, ret, invocation_result_array); + result_wrapper.result = invocation_result_array; + return result_wrapper; } JNIEXPORT jint JNICALL @@ -90,29 +95,25 @@ JavaEnclave_MockSVMNativeCreateEnclave(JNIEnv *env, jobject obj, jstring path) { void *enclave_handler = dlopen(path_str , RTLD_LOCAL | RTLD_LAZY); (*env)->ReleaseStringUTFChars(env, path, path_str); if (enclave_handler == 0x0) { - fprintf(stderr, "mock in svm dlopen error:%s\n", dlerror()); - return -1; + THROW_EXCEPTION(env, ENCLAVE_CREATING_EXCEPTION, "mock in svm dlopen error.") } // find load service symbol. mock_in_svm_load_service_symbol = dlsym((void *)enclave_handler, "java_loadservice_invoke"); if (!mock_in_svm_load_service_symbol) { - fprintf(stderr, "java_loadservice_invoke error:%s\n", dlerror()); dlclose(enclave_handler); - return -1; + THROW_EXCEPTION(env, ENCLAVE_CREATING_EXCEPTION, "java_loadservice_invoke error.") } // find invoke service symbol. mock_in_svm_invoke_service_symbol = dlsym((void *)enclave_handler, "java_enclave_invoke"); if (!mock_in_svm_invoke_service_symbol) { - fprintf(stderr, "mock_in_svm_invoke_service_symbol error:%s\n", dlerror()); dlclose(enclave_handler); - return -1; + THROW_EXCEPTION(env, ENCLAVE_CREATING_EXCEPTION, "mock_in_svm_invoke_service_symbol error.") } // find unload service symbol. mock_in_svm_unload_service_symbol = dlsym((void *)enclave_handler, "java_unloadservice_invoke"); if (!mock_in_svm_unload_service_symbol) { - fprintf(stderr, "mock_in_svm_unload_service_symbol error:%s\n", dlerror()); dlclose(enclave_handler); - return -1; + THROW_EXCEPTION(env, ENCLAVE_CREATING_EXCEPTION, "mock_in_svm_unload_service_symbol error.") } // set enclave_handler back to MockInSvmEnclave.enclaveSvmSdkHandle field. jclass class_enclave = (*env)->GetObjectClass(env, obj); @@ -127,39 +128,48 @@ JavaEnclave_MockSVMNativeSvmAttachIsolate(JNIEnv *env, jobject obj, jlong enclav graal_isolatethread_t* isolate_thread_t; int (*graal_create_isolate)(graal_create_isolate_params_t* params, graal_isolate_t** isolate, graal_isolatethread_t** thread); - graal_create_isolate = (int (*)(graal_create_isolate_params_t*, graal_isolate_t**, graal_isolatethread_t**)) - dlsym((void *)enclave_handler, "graal_create_isolate"); + graal_create_isolate = (int (*)(graal_create_isolate_params_t*, graal_isolate_t**, graal_isolatethread_t**)) dlsym((void *)enclave_handler, "graal_create_isolate"); if (!graal_create_isolate) { - fprintf(stderr, "dlsym error:%s\n", dlerror()); - return -1; + THROW_EXCEPTION(env, ENCLAVE_CREATING_EXCEPTION, "create isolate dlsym error.") } - int ret = graal_create_isolate(NULL, &isolate_t, &isolate_thread_t); - if (ret != 0) { - fprintf(stderr, "graal_create_isolate create error:%s\n", dlerror()); - return ret; + if (graal_create_isolate(NULL, &isolate_t, &isolate_thread_t) != 0) { + // fprintf(stderr, "graal_create_isolate create error:%s\n", dlerror()); + THROW_EXCEPTION(env, ENCLAVE_CREATING_EXCEPTION, "graal_create_isolate create error.") } // set isolate_t and isolate_thread_t back to MockInSvmEnclave.isolateHandle and MockInSvmEnclave.isolateThreadHandle jclass class_enclave = (*env)->GetObjectClass(env, obj); set_long_field_value(env, class_enclave, obj, "isolateHandle", (jlong)isolate_t); set_long_field_value(env, class_enclave, obj, "isolateThreadHandle", (jlong)isolate_thread_t); - return ret; + return 0; } JNIEXPORT jobject JNICALL JavaEnclave_MockSVMNativeLoadService(JNIEnv *env, jobject obj, jlong enclave_handler, jlong isolate_handler, jbyteArray load_service_payload) { - return mock_enclave_calling_entry(env, isolate_handler, load_service_payload, (mock_enclave_stub) mock_in_svm_load_service_symbol); + enclave_calling_stub_result result_wrapper = mock_enclave_calling_entry(env, isolate_handler, load_service_payload, (mock_enclave_stub) mock_in_svm_load_service_symbol); + if (result_wrapper.ret != 0) { + THROW_EXCEPTION(env, ENCLAVE_SERVICE_LOADING_EXCEPTION, "tee sdk service loading native call failed.") + } + return result_wrapper.result; } JNIEXPORT jobject JNICALL JavaEnclave_MockSVMNativeInvokeMethod(JNIEnv *env, jobject obj, jlong enclave_handler, jlong isolate_handler, jbyteArray invoke_payload) { - return mock_enclave_calling_entry(env, isolate_handler, invoke_payload, (mock_enclave_stub) mock_in_svm_invoke_service_symbol); + enclave_calling_stub_result result_wrapper = mock_enclave_calling_entry(env, isolate_handler, invoke_payload, (mock_enclave_stub) mock_in_svm_invoke_service_symbol); + if (result_wrapper.ret != 0) { + THROW_EXCEPTION(env, ENCLAVE_SERVICE_INVOKING_EXCEPTION, "tee sdk service method invoking native call failed.") + } + return result_wrapper.result; } JNIEXPORT jobject JNICALL JavaEnclave_MockSVMNativeUnloadService(JNIEnv *env, jobject obj, jlong enclave_handler, jlong isolate_handler, jbyteArray unload_service_payload) { - return mock_enclave_calling_entry(env, isolate_handler, unload_service_payload, (mock_enclave_stub) mock_in_svm_unload_service_symbol); + enclave_calling_stub_result result_wrapper = mock_enclave_calling_entry(env, isolate_handler, unload_service_payload, (mock_enclave_stub) mock_in_svm_unload_service_symbol); + if (result_wrapper.ret != 0) { + THROW_EXCEPTION(env, ENCLAVE_SERVICE_UNLOADING_EXCEPTION, "tee sdk service unloading native call failed.") + } + return result_wrapper.result; } JNIEXPORT jint JNICALL @@ -168,13 +178,18 @@ JavaEnclave_MockSVMNativeSvmDetachIsolate(JNIEnv *env, jobject obj, jlong enclav graal_detach_all_threads_and_tear_down_isolate = (int (*)(graal_isolatethread_t*)) dlsym((void *)enclave_handler, "graal_detach_all_threads_and_tear_down_isolate"); if (!graal_detach_all_threads_and_tear_down_isolate) { - fprintf(stderr, "graal_detach_all_threads_and_tear_down_isolate error:%s\n", dlerror()); - return -1; + THROW_EXCEPTION(env, ENCLAVE_DESTROYING_EXCEPTION, "graal_detach_all_threads_and_tear_down_isolate dlsym error.") + } + if (0x0 != graal_detach_all_threads_and_tear_down_isolate((graal_isolatethread_t*)isolate_thread_handler)) { + THROW_EXCEPTION(env, ENCLAVE_DESTROYING_EXCEPTION, "graal_detach_all_threads_and_tear_down_isolate error.") } - return (jint)graal_detach_all_threads_and_tear_down_isolate((graal_isolatethread_t*)isolate_thread_handler); + return 0; } JNIEXPORT jint JNICALL JavaEnclave_MockSVMNativeDestroyEnclave(JNIEnv *env, jobject obj, jlong enclave_handler) { - return dlclose((void *)enclave_handler); + if(0x0 != dlclose((void *)enclave_handler)) { + THROW_EXCEPTION(env, ENCLAVE_DESTROYING_EXCEPTION, "dlclose failed.") + } + return 0; } diff --git a/sdk/host/src/main/native/cpp/platform/mock_in_svm/jni/jni_mock_in_svm.h b/sdk/host/src/main/native/cpp/platform/mock_in_svm/jni/jni_mock_in_svm.h index bbcedf1..53db1a2 100644 --- a/sdk/host/src/main/native/cpp/platform/mock_in_svm/jni/jni_mock_in_svm.h +++ b/sdk/host/src/main/native/cpp/platform/mock_in_svm/jni/jni_mock_in_svm.h @@ -3,8 +3,32 @@ #ifndef _Included_jni_mock_in_svm #define _Included_jni_mock_in_svm -#define MOCK_IN_SVM_NATIVE_CALL_SIGNATURE "(JJ[B)Lcom/alibaba/confidentialcomputing/host/InnerNativeInvocationResult;" -#define MOCK_IN_SVM_RETURN_OBJECT_SIGNATURE "com/alibaba/confidentialcomputing/host/InnerNativeInvocationResult" +typedef struct { + int ret; + jbyteArray result; +} enclave_calling_stub_result; + +#define REMOTE_ATTESTATION_CLASS_NAME "com/alibaba/confidentialcomputing/host/exception/RemoteAttestationException" +#define ENCLAVE_CREATING_EXCEPTION "com/alibaba/confidentialcomputing/host/exception/EnclaveCreatingException" +#define ENCLAVE_DESTROYING_EXCEPTION "com/alibaba/confidentialcomputing/host/exception/EnclaveDestroyingException" +#define ENCLAVE_SERVICE_LOADING_EXCEPTION "com/alibaba/confidentialcomputing/host/exception/ServicesLoadingException" +#define ENCLAVE_SERVICE_UNLOADING_EXCEPTION "com/alibaba/confidentialcomputing/host/exception/ServicesUnloadingException" +#define ENCLAVE_SERVICE_INVOKING_EXCEPTION "com/alibaba/confidentialcomputing/host/exception/EnclaveMethodInvokingException" + +#define MOCK_IN_SVM_NATIVE_CALL_SIGNATURE "(JJ[B)[B" + +#define THROW_EXCEPTION(env, exception, info) \ +{ \ + jclass ra_class = (*env)->FindClass(env, exception); \ + if (ra_class == NULL) { \ + printf("JavaEnclave Error: "); \ + printf(exception); \ + printf(" class loading failed.\n"); \ + return; \ + } \ + (*env)->ThrowNew(env, ra_class, info); \ + return; \ +} #ifdef __cplusplus extern "C" { @@ -28,23 +52,23 @@ JNIEXPORT jint JNICALL JavaEnclave_MockSVMNativeSvmAttachIsolate(JNIEnv *, jobje /* * Class: JavaEnclave_MockSVMNativeLoadService * Method: nativeLoadService - * Signature: (JJ[B)Lcom/alibaba/confidentialcomputing/host/InnerNativeInvocationResult; + * Signature: (JJ[B)[B */ -JNIEXPORT jobject JNICALL JavaEnclave_MockSVMNativeLoadService(JNIEnv *, jobject, jlong, jlong, jbyteArray); +JNIEXPORT jbyteArray JNICALL JavaEnclave_MockSVMNativeLoadService(JNIEnv *, jobject, jlong, jlong, jbyteArray); /* * Class: JavaEnclave_MockSVMNativeInvokeMethod * Method: nativeInvokeMethod - * Signature: (JJ[B)Lcom/alibaba/confidentialcomputing/host/InnerNativeInvocationResult; + * Signature: (JJ[B)[B */ -JNIEXPORT jobject JNICALL JavaEnclave_MockSVMNativeInvokeMethod(JNIEnv *, jobject, jlong, jlong, jbyteArray); +JNIEXPORT jbyteArray JNICALL JavaEnclave_MockSVMNativeInvokeMethod(JNIEnv *, jobject, jlong, jlong, jbyteArray); /* * Class: JavaEnclave_MockSVMNativeUnloadService * Method: nativeUnloadService - * Signature: (JJ[B)Lcom/alibaba/confidentialcomputing/host/InnerNativeInvocationResult; + * Signature: (JJ[B)[B */ -JNIEXPORT jobject JNICALL JavaEnclave_MockSVMNativeUnloadService(JNIEnv *, jobject, jlong, jlong, jbyteArray); +JNIEXPORT jbyteArray JNICALL JavaEnclave_MockSVMNativeUnloadService(JNIEnv *, jobject, jlong, jlong, jbyteArray); /* * Class: JavaEnclave_MockSVMNativeSvmDetachIsolate diff --git a/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/Makefile b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/Makefile index 0620ffd..7bc2590 100644 --- a/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/Makefile +++ b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/Makefile @@ -8,9 +8,10 @@ include $(NATIVE_BASE_DIR)/config/platform/tee_sdk_svm/jni/config.mk all: build build: jni.o - $(CC) edge_routines/ocall_svm.o edge_routines/tee_sdk_enclave_u.o jni/jni_tee_sdk_svm.o \ - $(TS_HOST_CFLAGS) $(TS_HOST_LDFLAGS) -fPIC -shared -o $(BIN)/platform/tee_sdk_svm/jni/lib_jni_tee_sdk_svm.so - + $(CC) edge_routines/ocall_svm.o edge_routines/ocall_attestation.o edge_routines/tee_sdk_enclave_u.o \ + jni/generate_attestation_report.o jni/jni_tee_sdk_svm.o $(TS_HOST_CFLAGS) $(TS_HOST_LDFLAGS) \ + -fPIC -shared -o $(BIN)/platform/tee_sdk_svm/jni/lib_jni_tee_sdk_svm.so + rm -rf edge_routines/*.o edge_routines/tee_sdk_enclave_u.* jni/*.o edge_routines.o: diff --git a/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/edge_routines/Makefile b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/edge_routines/Makefile index 26b7183..7fc3254 100644 --- a/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/edge_routines/Makefile +++ b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/edge_routines/Makefile @@ -12,6 +12,9 @@ build: --search-path $(TEE_SDK_PATH)/include $(CC) -g -c -fPIC $(TS_HOST_INCDIR) $(TS_HOST_CFLAGS) -fPIC ocall_svm.c + + $(CC) -g -c -fPIC $(TS_HOST_INCDIR) $(TS_HOST_CFLAGS) -fPIC ocall_attestation.c + $(CC) -g -c -fPIC $(TS_HOST_INCDIR) $(TS_HOST_CFLAGS) -fPIC tee_sdk_enclave_u.c clean: diff --git a/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/edge_routines/ocall_attestation.c b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/edge_routines/ocall_attestation.c new file mode 100644 index 0000000..7d741dd --- /dev/null +++ b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/edge_routines/ocall_attestation.c @@ -0,0 +1,6 @@ +#include "ocall_attestation.h" + +// ocall_get_target_info get target info from host. +quote3_error_t ocall_get_target_info(sgx_target_info_t *qe_target_info) { + return sgx_qe_get_target_info(qe_target_info); +} \ No newline at end of file diff --git a/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/edge_routines/ocall_attestation.h b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/edge_routines/ocall_attestation.h new file mode 100644 index 0000000..2051781 --- /dev/null +++ b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/edge_routines/ocall_attestation.h @@ -0,0 +1,22 @@ +#ifndef _OCALL_ATTESTATION_H_ +#define _OCALL_ATTESTATION_H_ + +#include <stdio.h> + +#include "sgx_urts.h" +#include "sgx_report.h" +#include "sgx_dcap_ql_wrapper.h" +#include "sgx_pce.h" +#include "sgx_error.h" +#include "sgx_quote_3.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + quote3_error_t ocall_get_target_info(sgx_target_info_t *qe_target_info); +#if defined(__cplusplus) +} +#endif + +#endif /* !_OCALL_ATTESTATION_H_ */ \ No newline at end of file diff --git a/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/Makefile b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/Makefile index e635614..9a212ab 100644 --- a/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/Makefile +++ b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/Makefile @@ -11,5 +11,8 @@ build: $(CC) -g -c -Wno-unused-parameter -fPIC $(TS_HOST_CFLAGS) $(TS_HOST_INCDIR) -I./../edge_routines -I$(JAVA_HOME)/lib -I$(INCLUDE) -I$(JAVA_HOME)/include \ -I$(JAVA_HOME)/include/$(shell uname -s | tr A-Z a-z) jni_tee_sdk_svm.c + $(CC) -g -c -Wno-unused-parameter -fPIC $(TS_HOST_CFLAGS) $(TS_HOST_INCDIR) -I$(JAVA_HOME)/lib -I$(INCLUDE) -I$(JAVA_HOME)/include \ + -I$(JAVA_HOME)/include/$(shell uname -s | tr A-Z a-z) generate_attestation_report.c + clean: rm -rf *.o \ No newline at end of file diff --git a/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/generate_attestation_report.c b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/generate_attestation_report.c new file mode 100644 index 0000000..715c68e --- /dev/null +++ b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/generate_attestation_report.c @@ -0,0 +1,69 @@ +#include "generate_attestation_report.h" + +// use_aesm_qe_service determines sgx aesm remote attestation service or local qe service. +bool use_aesm_qe_service() { + bool flag = false; + // If environment "SGX_AESM_ADDR" is set, remote qe will be adapted. + char *sgx_aesm_address = getenv(SGX_AESM_ADR); + if(sgx_aesm_address) { + flag = true; + } + return flag; +} + +// load_qe_signed_package loads all .signed packages which qe will use. +quote3_error_t load_qe_signed_package() { + quote3_error_t qe3_ret = SGX_QL_SUCCESS; + if(!use_aesm_qe_service()) { + // Set enclave load policy. + qe3_ret = sgx_qe_set_enclave_load_policy(SGX_QL_PERSISTENT); + if(SGX_QL_SUCCESS != qe3_ret) { + // printf("Error in set enclave load policy: 0x%04x\n", qe3_ret); + return qe3_ret; + } + + // Check it is Ubuntu-like OS system or RedHat-like OS system. + char* lib_sgx_pce_path = NULL; + char* lib_sgx_qe3_path = NULL; + char* lib_dcap_quote_prov = NULL; + const char* folder_ubuntu = UBUNTU_LIB_PATH; + const char* folder_rhel = RHEL_LIB_PATH; + struct stat sb; + if (stat(folder_ubuntu, &sb) == 0 && S_ISDIR(sb.st_mode)) { + // Ubuntu-like OS system. + lib_sgx_pce_path = UBUNTU_LIB_SGX_PCE_PATH; + lib_sgx_qe3_path = UBUNTU_LIB_SGX_QE3_PATH; + lib_dcap_quote_prov = UBUNTU_LIB_DCAP_QUOTE_PROV; + } else if (stat(folder_rhel, &sb) == 0 && S_ISDIR(sb.st_mode)) { + // RedHat-like OS system. + lib_sgx_pce_path = RHEL_LIB_SGX_PCE_PATH; + lib_sgx_qe3_path = RHEL_LIB_SGX_QE3_PATH; + lib_dcap_quote_prov = RHEL_LIB_DCAP_QUOTE_PROV; + } else { + // printf("Unsupported OS Platform Type.\n"); + return SGX_QL_SERVICE_UNAVAILABLE; + } + + if (SGX_QL_SUCCESS != (qe3_ret = sgx_ql_set_path(SGX_QL_PCE_PATH, lib_sgx_pce_path)) || + SGX_QL_SUCCESS != (qe3_ret = sgx_ql_set_path(SGX_QL_QE3_PATH, lib_sgx_qe3_path))) { + // printf("Error in set PCE/QE3 directory.\n"); + return qe3_ret; + } + if (SGX_QL_SUCCESS != (qe3_ret = sgx_ql_set_path(SGX_QL_QPL_PATH, lib_dcap_quote_prov))) { + // printf("Warning: Cannot set QPL directory, you may get ECDSA quote with `Encrypted PPID` cert type.\n"); + return qe3_ret; + } + } + return qe3_ret; +} + +// unload_qe_signed_package unloads .signed packages load_qe_signed_package loaded. +quote3_error_t unload_qe_signed_package() { + quote3_error_t qe3_ret = SGX_QL_SUCCESS; + if(!use_aesm_qe_service()) { + if(SGX_QL_SUCCESS != (qe3_ret = sgx_qe_cleanup_by_policy())) { + // printf("Error in cleanup enclave load policy: 0x%04x\n", qe3_ret); + } + } + return qe3_ret; +} diff --git a/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/generate_attestation_report.h b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/generate_attestation_report.h new file mode 100644 index 0000000..a36724e --- /dev/null +++ b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/generate_attestation_report.h @@ -0,0 +1,38 @@ +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> + +#include <graal_isolate.h> + +#include "sgx_urts.h" +#include "sgx_report.h" +#include "sgx_dcap_ql_wrapper.h" +#include "sgx_pce.h" +#include "sgx_error.h" +#include "sgx_quote_3.h" + +#define SGX_AESM_ADR "SGX_AESM_ADDR" +#define UBUNTU_LIB_PATH "/usr/lib/x86_64-linux-gnu" +#define RHEL_LIB_PATH "/usr/lib64" +#define UBUNTU_LIB_SGX_PCE_PATH "/usr/lib/x86_64-linux-gnu/libsgx_pce.signed.so" +#define UBUNTU_LIB_SGX_QE3_PATH "/usr/lib/x86_64-linux-gnu/libsgx_qe3.signed.so" +#define UBUNTU_LIB_DCAP_QUOTE_PROV "/usr/lib/x86_64-linux-gnu/libdcap_quoteprov.so.1" +#define RHEL_LIB_SGX_PCE_PATH "/usr/lib64/libsgx_pce.signed.so" +#define RHEL_LIB_SGX_QE3_PATH "/usr/lib64/libsgx_qe3.signed.so" +#define RHEL_LIB_DCAP_QUOTE_PROV "/usr/lib64/libdcap_quoteprov.so.1" + +#ifndef _Included_jni_generate_attestation_report +#define _Included_jni_generate_attestation_report + +#ifdef __cplusplus +extern "C" { +#endif + +quote3_error_t load_qe_signed_package(); +quote3_error_t unload_qe_signed_package(); + +#ifdef __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/jni_tee_sdk_svm.c b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/jni_tee_sdk_svm.c index 7142959..6a1870f 100644 --- a/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/jni_tee_sdk_svm.c +++ b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/jni_tee_sdk_svm.c @@ -16,16 +16,15 @@ #include "tee_sdk_enclave_u.h" #include "jni_tee_sdk_svm.h" -typedef void (*enclave_calling_stub)(jlong, int*, graal_isolate_t*, void*, size_t, void*, size_t*); - static JNINativeMethod tee_sdk_svm_methods[] = { - {"nativeCreateEnclave", "(ILjava/lang/String;)I", (void *)&JavaEnclave_TeeSDKSVMNativeCreateEnclave}, - {"nativeSvmAttachIsolate", "(J)I", (void *)&JavaEnclave_TeeSDKSVMNativeSvmAttachIsolate}, - {"nativeLoadService", TEE_SDK_SVM_NATIVE_CALL_SIGNATURE, (void *)&JavaEnclave_TeeSDKSVMNativeLoadService}, - {"nativeInvokeMethod", TEE_SDK_SVM_NATIVE_CALL_SIGNATURE, (void *)&JavaEnclave_TeeSDKSVMNativeInvokeMethod}, - {"nativeUnloadService", TEE_SDK_SVM_NATIVE_CALL_SIGNATURE, (void *)&JavaEnclave_TeeSDKSVMNativeUnloadService}, - {"nativeSvmDetachIsolate", "(JJ)I", (void *)&JavaEnclave_TeeSDKSVMNativeSvmDetachIsolate}, - {"nativeDestroyEnclave", "(J)I", (void *)&JavaEnclave_TeeSDKSVMNativeDestroyEnclave}, + {"nativeCreateEnclave", "(ILjava/lang/String;)I", (void *)&JavaEnclave_TeeSDKSVMNativeCreateEnclave}, + {"nativeSvmAttachIsolate", "(J)I", (void *)&JavaEnclave_TeeSDKSVMNativeSvmAttachIsolate}, + {"nativeLoadService", TEE_SDK_SVM_NATIVE_CALL_SIGNATURE, (void *)&JavaEnclave_TeeSDKSVMNativeLoadService}, + {"nativeInvokeMethod", TEE_SDK_SVM_NATIVE_CALL_SIGNATURE, (void *)&JavaEnclave_TeeSDKSVMNativeInvokeMethod}, + {"nativeUnloadService", TEE_SDK_SVM_NATIVE_CALL_SIGNATURE, (void *)&JavaEnclave_TeeSDKSVMNativeUnloadService}, + {"nativeSvmDetachIsolate", "(JJ)I", (void *)&JavaEnclave_TeeSDKSVMNativeSvmDetachIsolate}, + {"nativeDestroyEnclave", "(J)I", (void *)&JavaEnclave_TeeSDKSVMNativeDestroyEnclave}, + {"nativeGenerateAttestationReport", TEE_SDK_REMOTE_ATTESTATION_REPORT_SIGNATURE, (void *)&JavaEnclave_TeeSDK_REMOTE_ATTESTATION_REPORT}, }; JNIEXPORT void JNICALL @@ -38,14 +37,12 @@ void set_long_field_value(JNIEnv *env, jclass class_mirror, jobject obj, const c (*env)->SetLongField(env, obj, field_id, value); } -jobject build_invocation_result(JNIEnv *env, jint ret, jbyteArray array) { - // build jni return object InnerNativeInvocationResult. - jclass invocation_result_clazz = (*env)->FindClass(env, TEE_SDK_SVM_RETURN_OBJECT_SIGNATURE); - jmethodID id = (*env)->GetMethodID(env, invocation_result_clazz, "<init>", "(I[B)V"); - return (*env)->NewObject(env, invocation_result_clazz, id, (jint)ret, array); +void set_int_field_value(JNIEnv *env, jclass class_mirror, jobject obj, const char *field_name, jint value) { + jfieldID field_id = (*env)->GetFieldID(env, class_mirror, field_name, "I"); + (*env)->SetIntField(env, obj, field_id, value); } -jobject enclave_calling_entry(JNIEnv *env, jlong enclave_handler, jlong isolate_handler, jbyteArray payload, enclave_calling_stub stub) { +enclave_calling_stub_result enclave_calling_entry(JNIEnv *env, jlong enclave_handler, jlong isolate_handler, jbyteArray payload, enclave_calling_stub stub) { jbyte *payload_copy = (*env)->GetByteArrayElements(env, payload, NULL); int payload_copy_length = (*env)->GetArrayLength(env, payload); @@ -56,11 +53,21 @@ jobject enclave_calling_entry(JNIEnv *env, jlong enclave_handler, jlong isolate_ output.data = NULL; output.data_len = 0x0; - int ret = 0x0; - stub(enclave_handler, &ret, (graal_isolate_t*)isolate_handler, (void*)(input.data), (size_t)(input.data_len), (void*)(&(output.data)), (size_t*)(&(output.data_len))); + jbyteArray invocation_result_array; + enclave_calling_stub_result result_wrapper; + result_wrapper.ret = 0; + result_wrapper.result = invocation_result_array; + + stub(enclave_handler, &result_wrapper.ret, (graal_isolate_t*)isolate_handler, (void*)(input.data), (size_t)(input.data_len), (void*)(&(output.data)), (size_t*)(&(output.data_len))); + if (result_wrapper.ret != 0) { + (*env)->ReleaseByteArrayElements(env, payload, payload_copy, 0); + // free buffer malloc in native image by callback mechanism. + free(output.data); + return result_wrapper; + } // create a byte array. - jbyteArray invocation_result_array = (*env)->NewByteArray(env, output.data_len); + invocation_result_array = (*env)->NewByteArray(env, output.data_len); jbyte *invocation_result_array_ptr = (*env)->GetByteArrayElements(env, invocation_result_array, NULL); memcpy(invocation_result_array_ptr, output.data, (size_t)output.data_len); @@ -70,7 +77,8 @@ jobject enclave_calling_entry(JNIEnv *env, jlong enclave_handler, jlong isolate_ // free buffer malloc in native image by callback mechanism. free(output.data); - return build_invocation_result(env, ret, invocation_result_array); + result_wrapper.result = invocation_result_array; + return result_wrapper; } JNIEXPORT jint JNICALL @@ -91,7 +99,7 @@ JavaEnclave_TeeSDKSVMNativeCreateEnclave(JNIEnv *env, jobject obj, jint mode, js (*env)->ReleaseStringUTFChars(env, path, path_str); if (ret != SGX_SUCCESS) { - return (int)ret; + THROW_EXCEPTION(env, ENCLAVE_CREATING_EXCEPTION, "create tee sdk enclave by native calling failed.") } // set enclave_handler back to TeeSdkEnclave.enclaveHandle field. @@ -108,6 +116,9 @@ JavaEnclave_TeeSDKSVMNativeSvmAttachIsolate(JNIEnv *env, jobject obj, jlong encl uint64_t isolateThread = 0; int ret = 0; enclave_svm_isolate_create((size_t)enclave_handler, &ret, (void *)(&isolate), (void *)(&isolateThread)); + if (ret != 0) { + THROW_EXCEPTION(env, ENCLAVE_CREATING_EXCEPTION, "attach native svm failed when creating an enclave.") + } jclass enclave_class = (*env)->GetObjectClass(env, obj); // set isolate back to isolateHandle field. @@ -118,29 +129,126 @@ JavaEnclave_TeeSDKSVMNativeSvmAttachIsolate(JNIEnv *env, jobject obj, jlong encl return ret; } -JNIEXPORT jobject JNICALL +JNIEXPORT jbyteArray JNICALL JavaEnclave_TeeSDKSVMNativeLoadService(JNIEnv *env, jobject obj, jlong enclave_handler, jlong isolate_handler, jbyteArray load_service_payload) { - return enclave_calling_entry(env, enclave_handler, isolate_handler, load_service_payload, (enclave_calling_stub) load_enclave_svm_services); + enclave_calling_stub_result result_wrapper = enclave_calling_entry(env, enclave_handler, isolate_handler, load_service_payload, (enclave_calling_stub) load_enclave_svm_services); + if (result_wrapper.ret != 0) { + THROW_EXCEPTION(env, ENCLAVE_SERVICE_LOADING_EXCEPTION, "tee sdk service loading native call failed.") + } + return result_wrapper.result; } -JNIEXPORT jobject JNICALL +JNIEXPORT jbyteArray JNICALL JavaEnclave_TeeSDKSVMNativeInvokeMethod(JNIEnv *env, jobject obj, jlong enclave_handler, jlong isolate_handler, jbyteArray invoke_service_payload) { - return enclave_calling_entry(env, enclave_handler, isolate_handler, invoke_service_payload, (enclave_calling_stub) invoke_enclave_svm_service); + enclave_calling_stub_result result_wrapper = enclave_calling_entry(env, enclave_handler, isolate_handler, invoke_service_payload, (enclave_calling_stub) invoke_enclave_svm_service); + if (result_wrapper.ret != 0) { + THROW_EXCEPTION(env, ENCLAVE_SERVICE_INVOKING_EXCEPTION, "tee sdk service method invoking native call failed.") + } + return result_wrapper.result; } -JNIEXPORT jobject JNICALL +JNIEXPORT jbyteArray JNICALL JavaEnclave_TeeSDKSVMNativeUnloadService(JNIEnv *env, jobject obj, jlong enclave_handler, jlong isolate_handler, jbyteArray unload_service_payload) { - return enclave_calling_entry(env, enclave_handler, isolate_handler, unload_service_payload, (enclave_calling_stub) unload_enclave_svm_service); + enclave_calling_stub_result result_wrapper = enclave_calling_entry(env, enclave_handler, isolate_handler, unload_service_payload, (enclave_calling_stub) unload_enclave_svm_service); + if (result_wrapper.ret != 0) { + THROW_EXCEPTION(env, ENCLAVE_SERVICE_UNLOADING_EXCEPTION, "tee sdk service unloading native call failed.") + } + return result_wrapper.result; } JNIEXPORT jint JNICALL JavaEnclave_TeeSDKSVMNativeSvmDetachIsolate(JNIEnv *env, jobject obj, jlong enclave_handler, jlong isolate_thread_handler) { int ret = 0x0; enclave_svm_isolate_destroy((sgx_enclave_id_t)enclave_handler, &ret, (uint64_t)isolate_thread_handler); - return ret; + if (ret != 0) { + THROW_EXCEPTION(env, ENCLAVE_DESTROYING_EXCEPTION, "isolate destroy native call failed.") + } + return 0; } JNIEXPORT jint JNICALL JavaEnclave_TeeSDKSVMNativeDestroyEnclave(JNIEnv *env, jobject obj, jlong enclave_handler) { - return (jint)sgx_destroy_enclave((sgx_enclave_id_t)enclave_handler); + if ((jint)sgx_destroy_enclave((sgx_enclave_id_t)enclave_handler) != 0) { + THROW_EXCEPTION(env, ENCLAVE_DESTROYING_EXCEPTION, "enclave destroy native call failed.") + } + return 0; +} + +JNIEXPORT jobject JNICALL +JavaEnclave_TeeSDK_REMOTE_ATTESTATION_REPORT(JNIEnv *env, jobject obj, jlong enclave_handler, jbyteArray data) { + int ret = 0; + + quote3_error_t qe3_ret = SGX_QL_SUCCESS; + // Step one, load remote attestation related .signed files. + if (SGX_QL_SUCCESS != (qe3_ret = load_qe_signed_package())) { + THROW_EXCEPTION(env, REMOTE_ATTESTATION_CLASS_NAME, "load remote attestation related .signed files failed") + } + + // Step two, generate target enclave's report info. + sgx_report_t ra_report; + jbyte *data_copy = (*env)->GetByteArrayElements(env, data, NULL); + int length = (*env)->GetArrayLength(env, data); + generate_remote_attestation_report(enclave_handler, &ret, (void *)data_copy, (size_t)length, &ra_report); + if (ret != 0) { + (*env)->ReleaseByteArrayElements(env, data, data_copy, 0); + THROW_EXCEPTION(env, REMOTE_ATTESTATION_CLASS_NAME, "generate target enclave's report info failed") + } + + // Step three, get quote size. + uint32_t quote_size = 0; + qe3_ret = sgx_qe_get_quote_size("e_size); + if (SGX_QL_SUCCESS != qe3_ret) { + (*env)->ReleaseByteArrayElements(env, data, data_copy, 0); + THROW_EXCEPTION(env, REMOTE_ATTESTATION_CLASS_NAME, "get quote size failed") + } + + // Step four, get quote data from target enclave's report. + // quote_buffer_ptr will store sgx_quote3_t struct data. + uint8_t* quote_buffer_ptr = NULL; + quote_buffer_ptr = (uint8_t*)malloc(quote_size); + if (NULL == quote_buffer_ptr) { + (*env)->ReleaseByteArrayElements(env, data, data_copy, 0); + THROW_EXCEPTION(env, REMOTE_ATTESTATION_CLASS_NAME, "get quote temp heap for target enclave's report failed") + } + memset(quote_buffer_ptr, 0, quote_size); + + qe3_ret = sgx_qe_get_quote(&ra_report, quote_size, quote_buffer_ptr); + if (SGX_QL_SUCCESS != qe3_ret) { + if (NULL != quote_buffer_ptr) { + free(quote_buffer_ptr); + } + (*env)->ReleaseByteArrayElements(env, data, data_copy, 0); + THROW_EXCEPTION(env, REMOTE_ATTESTATION_CLASS_NAME ,"get quote data from target enclave's report failed") + } + + // Step five, clear up loaded qe. + qe3_ret = unload_qe_signed_package(); + if (SGX_QL_SUCCESS != qe3_ret) { + printf("JavaEnclave Warning: clear up loaded qe files failed"); + } + + // create a quote byte array. + jbyteArray quote_array = (*env)->NewByteArray(env, quote_size); + jbyte *quote_array_ptr = (*env)->GetByteArrayElements(env, quote_array, NULL); + memcpy(quote_array_ptr, quote_buffer_ptr, (size_t)quote_size); + + // create mr enclave byte array. + jbyteArray mr_enclave = (*env)->NewByteArray(env, SGX_HASH_SIZE); + jbyte *mr_enclave_buf = (*env)->GetByteArrayElements(env, mr_enclave, NULL); + memcpy(mr_enclave_buf, ra_report.body.mr_enclave.m, SGX_HASH_SIZE); + + // create mr signer byte array. + jbyteArray mr_signer = (*env)->NewByteArray(env, SGX_HASH_SIZE); + jbyte *mr_signer_buf = (*env)->GetByteArrayElements(env, mr_signer, NULL); + memcpy(mr_signer_buf, ra_report.body.mr_signer.m, SGX_HASH_SIZE); + + (*env)->ReleaseByteArrayElements(env, data, data_copy, 0); + (*env)->ReleaseByteArrayElements(env, quote_array, quote_array_ptr, 0); + (*env)->ReleaseByteArrayElements(env, mr_enclave, mr_enclave_buf, 0); + (*env)->ReleaseByteArrayElements(env, mr_signer, mr_signer_buf, 0); + free(quote_buffer_ptr); + + jclass tee_sdk_ra_report_clazz = (*env)->FindClass(env, TEE_SDK_REMOTE_ATTESTATION_REPORT_CLASS_NAME); + jmethodID construct = (*env)->GetMethodID(env, tee_sdk_ra_report_clazz, "<init>", "([B[B[B)V"); + return (*env)->NewObject(env, tee_sdk_ra_report_clazz, construct, quote_array, mr_signer, mr_enclave); } \ No newline at end of file diff --git a/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/jni_tee_sdk_svm.h b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/jni_tee_sdk_svm.h index 7ac0650..561b448 100644 --- a/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/jni_tee_sdk_svm.h +++ b/sdk/host/src/main/native/cpp/platform/tee_sdk_svm/jni/jni_tee_sdk_svm.h @@ -1,14 +1,45 @@ #include <jni.h> +#include "generate_attestation_report.h" + #ifndef _Included_jni_tee_sdk_svm #define _Included_jni_tee_sdk_svm -#define TEE_SDK_SVM_NATIVE_CALL_SIGNATURE "(JJ[B)Lcom/alibaba/confidentialcomputing/host/InnerNativeInvocationResult;" -#define TEE_SDK_SVM_RETURN_OBJECT_SIGNATURE "com/alibaba/confidentialcomputing/host/InnerNativeInvocationResult" +typedef void (*enclave_calling_stub)(jlong, int*, graal_isolate_t*, void*, size_t, void*, size_t*); + +typedef struct { + int ret; + jbyteArray result; +} enclave_calling_stub_result; + +#define REMOTE_ATTESTATION_CLASS_NAME "com/alibaba/confidentialcomputing/host/exception/RemoteAttestationException" +#define ENCLAVE_CREATING_EXCEPTION "com/alibaba/confidentialcomputing/host/exception/EnclaveCreatingException" +#define ENCLAVE_DESTROYING_EXCEPTION "com/alibaba/confidentialcomputing/host/exception/EnclaveDestroyingException" +#define ENCLAVE_SERVICE_LOADING_EXCEPTION "com/alibaba/confidentialcomputing/host/exception/ServicesLoadingException" +#define ENCLAVE_SERVICE_UNLOADING_EXCEPTION "com/alibaba/confidentialcomputing/host/exception/ServicesUnloadingException" +#define ENCLAVE_SERVICE_INVOKING_EXCEPTION "com/alibaba/confidentialcomputing/host/exception/EnclaveMethodInvokingException" + +#define TEE_SDK_SVM_NATIVE_CALL_SIGNATURE "(JJ[B)[B" +#define TEE_SDK_REMOTE_ATTESTATION_REPORT_SIGNATURE "(J[B)Lcom/alibaba/confidentialcomputing/host/TeeSdkAttestationReport;" +#define TEE_SDK_REMOTE_ATTESTATION_REPORT_CLASS_NAME "com/alibaba/confidentialcomputing/host/TeeSdkAttestationReport" + +#define THROW_EXCEPTION(env, exception, info) \ +{ \ + jclass ra_class = (*env)->FindClass(env, exception); \ + if (ra_class == NULL) { \ + printf("JavaEnclave Error: "); \ + printf(exception); \ + printf(" class loading failed.\n"); \ + return; \ + } \ + (*env)->ThrowNew(env, ra_class, info); \ + return; \ +} #ifdef __cplusplus extern "C" { #endif + JNIEXPORT void JNICALL Java_com_alibaba_confidentialcomputing_host_TeeSdkEnclave_registerNatives(JNIEnv *env, jclass cls); /* @@ -28,23 +59,23 @@ JNIEXPORT jint JNICALL JavaEnclave_TeeSDKSVMNativeSvmAttachIsolate(JNIEnv *, job /* * Class: com_alibaba_confidentialcomputing_host_TeeSdkEnclave * Method: nativeLoadService - * Signature: (JJ[B)Lcom/alibaba/confidentialcomputing/host/InnerNativeInvocationResult; + * Signature: (JJ[B)[B */ -JNIEXPORT jobject JNICALL JavaEnclave_TeeSDKSVMNativeLoadService(JNIEnv *, jobject, jlong, jlong, jbyteArray); +JNIEXPORT jbyteArray JNICALL JavaEnclave_TeeSDKSVMNativeLoadService(JNIEnv *, jobject, jlong, jlong, jbyteArray); /* * Class: com_alibaba_confidentialcomputing_host_TeeSdkEnclave * Method: nativeInvokeMethod - * Signature: (JJ[B)Lcom/alibaba/confidentialcomputing/host/InnerNativeInvocationResult; + * Signature: (JJ[B)[B */ -JNIEXPORT jobject JNICALL JavaEnclave_TeeSDKSVMNativeInvokeMethod(JNIEnv *, jobject, jlong, jlong, jbyteArray); +JNIEXPORT jbyteArray JNICALL JavaEnclave_TeeSDKSVMNativeInvokeMethod(JNIEnv *, jobject, jlong, jlong, jbyteArray); /* * Class: com_alibaba_confidentialcomputing_host_TeeSdkEnclave * Method: nativeUnloadService - * Signature: (JJ[B)Lcom/alibaba/confidentialcomputing/host/InnerNativeInvocationResult; + * Signature: (JJ[B)[B */ -JNIEXPORT jobject JNICALL JavaEnclave_TeeSDKSVMNativeUnloadService(JNIEnv *, jobject, jlong, jlong, jbyteArray); +JNIEXPORT jbyteArray JNICALL JavaEnclave_TeeSDKSVMNativeUnloadService(JNIEnv *, jobject, jlong, jlong, jbyteArray); /* * Class: com_alibaba_confidentialcomputing_host_TeeSdkEnclave @@ -60,6 +91,13 @@ JNIEXPORT jint JNICALL JavaEnclave_TeeSDKSVMNativeSvmDetachIsolate(JNIEnv *, job */ JNIEXPORT jint JNICALL JavaEnclave_TeeSDKSVMNativeDestroyEnclave(JNIEnv *, jobject, jlong); +/* + * Class: com_alibaba_confidentialcomputing_host_TeeSdkEnclave + * Method: nativeGenerateAttestationReport + * Signature: (J[B)Lcom/alibaba/confidentialcomputing/host/TeeSdkAttestationReport; + */ +JNIEXPORT jobject JNICALL JavaEnclave_TeeSDK_REMOTE_ATTESTATION_REPORT(JNIEnv *, jobject, jlong, jbyteArray); + #ifdef __cplusplus } #endif diff --git a/sdk/host/src/test/java/com/alibaba/confidentialcomputing/host/MockTestEnclave.java b/sdk/host/src/test/java/com/alibaba/confidentialcomputing/host/MockTestEnclave.java index e655e46..90df27e 100644 --- a/sdk/host/src/test/java/com/alibaba/confidentialcomputing/host/MockTestEnclave.java +++ b/sdk/host/src/test/java/com/alibaba/confidentialcomputing/host/MockTestEnclave.java @@ -2,8 +2,7 @@ package com.alibaba.confidentialcomputing.host; import com.alibaba.confidentialcomputing.common.*; import com.alibaba.confidentialcomputing.common.exception.ConfidentialComputingException; -import com.alibaba.confidentialcomputing.host.exception.EnclaveCreatingException; -import com.alibaba.confidentialcomputing.host.exception.RemoteAttestationException; +import com.alibaba.confidentialcomputing.host.exception.*; import static org.junit.jupiter.api.Assertions.*; @@ -65,7 +64,7 @@ class MockTestEnclave extends AbstractEnclave { } @Override - AttestationReport generateAttestationReport(byte[] userData) throws RemoteAttestationException { + AttestationReport generateAttestationReportNative(byte[] userData) throws RemoteAttestationException { throw new RemoteAttestationException("MockTestEnclave enclave doesn't support remote attestation generation."); } @@ -74,7 +73,7 @@ class MockTestEnclave extends AbstractEnclave { } @Override - InnerNativeInvocationResult loadServiceNative(byte[] payload) { + byte[] loadServiceNative(byte[] payload) throws ServicesLoadingException { List<ServiceHandler> handlers = new ArrayList<>(); Throwable exception = null; EnclaveInvocationResult result; @@ -97,14 +96,14 @@ class MockTestEnclave extends AbstractEnclave { } try { - return new InnerNativeInvocationResult(0, SerializationHelper.serialize(result)); + return SerializationHelper.serialize(result); } catch (IOException e) { - return new InnerNativeInvocationResult(-1, null); + throw new ServicesLoadingException(e); } } @Override - InnerNativeInvocationResult unloadServiceNative(byte[] payload) { + byte[] unloadServiceNative(byte[] payload) throws ServicesUnloadingException { ServiceHandler serviceHandler; Throwable exception = null; EnclaveInvocationResult result; @@ -118,14 +117,14 @@ class MockTestEnclave extends AbstractEnclave { } try { - return new InnerNativeInvocationResult(0, SerializationHelper.serialize(result)); + return SerializationHelper.serialize(result); } catch (IOException e) { - return new InnerNativeInvocationResult(-1, null); + throw new ServicesUnloadingException(e); } } @Override - InnerNativeInvocationResult invokeMethodNative(byte[] payload) { + byte[] invokeMethodNative(byte[] payload) throws EnclaveMethodInvokingException { EnclaveInvocationContext invocationContext; Throwable exception = null; Object invokeRet = null; @@ -150,14 +149,14 @@ class MockTestEnclave extends AbstractEnclave { } try { - return new InnerNativeInvocationResult(0, SerializationHelper.serialize(result)); + return SerializationHelper.serialize(result); } catch (IOException e) { - return new InnerNativeInvocationResult(-1, null); + throw new EnclaveMethodInvokingException(e); } } @Override - public void destroy() { + public void destroy() throws EnclaveDestroyingException { // destroyToken will wait for all ongoing enclave invocations finished. if (this.getEnclaveContext().getEnclaveToken().destroyToken()) { // interrupt enclave services' recycler firstly. diff --git a/sdk/host/src/test/java/com/alibaba/confidentialcomputing/host/TestRemoteAttestation.java b/sdk/host/src/test/java/com/alibaba/confidentialcomputing/host/TestRemoteAttestation.java index 4773b0c..d4b9a20 100644 --- a/sdk/host/src/test/java/com/alibaba/confidentialcomputing/host/TestRemoteAttestation.java +++ b/sdk/host/src/test/java/com/alibaba/confidentialcomputing/host/TestRemoteAttestation.java @@ -47,7 +47,7 @@ class TestRemoteAttestation { AttestationReport deserializedReport = AttestationReport.fromByteArray(serializedReport); assertEquals(EnclaveType.TEE_SDK, deserializedReport.getEnclaveType()); for (int index = 0; index < quote.length; index++) { - assertEquals(quote[index], (deserializedReport.getReport())[index]); + assertEquals(quote[index], (deserializedReport.getQuote())[index]); } } } diff --git a/sdk/native/bin/remote_attestation/sgx/jni/.gitkeep b/sdk/native/bin/remote_attestation/sgx/jni/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/sdk/native/config/platform/tee_sdk_svm/edl/tee_sdk_enclave.edl b/sdk/native/config/platform/tee_sdk_svm/edl/tee_sdk_enclave.edl index 6f61cee..4736611 100644 --- a/sdk/native/config/platform/tee_sdk_svm/edl/tee_sdk_enclave.edl +++ b/sdk/native/config/platform/tee_sdk_svm/edl/tee_sdk_enclave.edl @@ -1,5 +1,6 @@ enclave { include "sgx_report.h" + include "sgx_ql_lib_common.h" from "sgx_tstdc.edl" import *; from "sgx_pthread.edl" import *; @@ -16,6 +17,8 @@ enclave { public int unload_enclave_svm_service(uint64_t isolate, [in, size=len0] void* input, size_t len0, [out, size=8] void* output, [out, size=8] size_t* len1); // destroy a graal isolate; public int enclave_svm_isolate_destroy(uint64_t isolateThread); + // generate sgx enclave remote attestation report; + public int generate_remote_attestation_report([in, size=hash_length] void* hash, size_t hash_length, [out]sgx_report_t* ra_report); }; untrusted { @@ -23,5 +26,8 @@ enclave { int ocall_getrlimit(int resource, [out, size=16]void *rlim); // malloc memory buffer from host side to store an returned object's serialization result. int ocall_malloc(size_t size, [out, size=8]void *ptr); + + // get target info from host. + quote3_error_t ocall_get_target_info([out] sgx_target_info_t *qe_target_info); }; }; diff --git a/sdk/native/config/platform/tee_sdk_svm/jni/config.mk b/sdk/native/config/platform/tee_sdk_svm/jni/config.mk index 536f413..f54e623 100644 --- a/sdk/native/config/platform/tee_sdk_svm/jni/config.mk +++ b/sdk/native/config/platform/tee_sdk_svm/jni/config.mk @@ -2,6 +2,14 @@ CC = gcc CXX = g++ TEE_SDK_PATH = /opt/teesdk/sgxsdk +UBUNTU_OS = $(shell if [ -d "/usr/lib/x86_64-linux-gnu" ]; then echo "yes"; else echo "no"; fi;) +ifeq ("$(UBUNTU_OS)", "yes") + DCAP_LIB_PATH = /usr/lib/x86_64-linux-gnu +else + DCAP_LIB_PATH = /usr/lib64 +endif + +# SGX_MODE ?= SIM SGX_MODE ?= HW SGX_ARCH ?= x64 SGX_DEBUG ?= 1 @@ -46,7 +54,7 @@ SGX_COMMON_CXXFLAGS := $(SGX_COMMON_FLAGS) -Wnon-virtual-dtor -std=c++11 TS_HOST_INCDIR = -I$(TEE_SDK_PATH)/include TS_HOST_CFLAGS = $(TS_HOST_INCDIR) $(SGX_COMMON_CFLAGS) TS_HOST_CXXFLAGS = $(SGX_COMMON_CXXFLAGS) -TS_HOST_LDFLAGS = -L$(SGX_LIBRARY_PATH) -Wl,-z,noexecstack -lc -l$(Urts_Library_Name) -lpthread -lsgx_ustdc_ex +TS_HOST_LDFLAGS = -L$(SGX_LIBRARY_PATH) -L$(DCAP_LIB_PATH) -Wl,-z,noexecstack -lc -l$(Urts_Library_Name) -lpthread -lsgx_ustdc_ex -lsgx_dcap_quoteverify -lsgx_dcap_ql -lsgx_quote_ex Enclave_Security_Link_Flags = -Wl,-z,relro,-z,now,-z,noexecstack diff --git a/sdk/native/config/remote_attestation_verify/sgx/config.mk b/sdk/native/config/remote_attestation_verify/sgx/config.mk new file mode 100644 index 0000000..032c4fb --- /dev/null +++ b/sdk/native/config/remote_attestation_verify/sgx/config.mk @@ -0,0 +1,13 @@ +CC = gcc +CXX = g++ + +TEE_SDK_PATH = /opt/teesdk/sgxsdk +UBUNTU_OS = $(shell if [ -d "/usr/lib/x86_64-linux-gnu" ]; then echo "yes"; else echo "no"; fi;) +ifeq ("$(UBUNTU_OS)", "yes") + DCAP_LIB_PATH = /usr/lib/x86_64-linux-gnu +else + DCAP_LIB_PATH = /usr/lib64 +endif + +RA_VERIFY_INCDIR = -I$(TEE_SDK_PATH)/include +RA_VERIFY_LDFLAGS = -L$(DCAP_LIB_PATH) -lsgx_dcap_quoteverify -lsgx_dcap_ql \ No newline at end of file diff --git a/sdk/native/script/build_app/Makefile b/sdk/native/script/build_app/Makefile index 4130e8b..85d3a30 100644 --- a/sdk/native/script/build_app/Makefile +++ b/sdk/native/script/build_app/Makefile @@ -1,11 +1,10 @@ include /opt/javaenclave/config/config.mk include /opt/javaenclave/config/platform/tee_sdk_svm/jni/config.mk -.PHONY: all build sign keys clean +.PHONY: all build clean all: $(MAKE) build - $(MAKE) sign build: ifeq ($(TEE_SDK), TRUE) @@ -24,13 +23,16 @@ ifeq ($(TEE_SDK), TRUE) -L${ENCLAVE_BASE_DIR}/target/enclave_workspace \ -fpie -ljava -lzip -lnio -lnet -ljvm -lfdlibm -llibchelper \ $(TS_ENCLAVE_LDFLAGS) -Wl,--version-script=/opt/javaenclave/config/platform/tee_sdk_svm/edl/tee_sdk_enclave.lds -endif -sign: -ifeq ($(TEE_SDK), TRUE) - openssl genrsa -out private.pem -3 3072 - openssl rsa -in private.pem -pubout -out public.pem - $(SGX_ENCLAVE_SIGNER) sign -enclave ${ENCLAVE_BASE_DIR}/target/svm-output/lib_tee_sdk_svm_load \ - -out ${ENCLAVE_BASE_DIR}/target/svm-output/lib_tee_sdk_svm_load.signed \ - -config ${ENCLAVE_BASE_DIR}/src/main/resources/tee_sdk_svm.conf -key private.pem + # sign the enclave image + ifeq ($(ENCLAVE_PRIVATE_PEM_PATH), ) + openssl genrsa -out ${ENCLAVE_BASE_DIR}/target/enclave_workspace/private.pem -3 3072 + $(SGX_ENCLAVE_SIGNER) sign -enclave ${ENCLAVE_BASE_DIR}/target/svm-output/lib_tee_sdk_svm_load \ + -out ${ENCLAVE_BASE_DIR}/target/svm-output/lib_tee_sdk_svm_load.signed \ + -config ${ENCLAVE_BASE_DIR}/src/main/resources/tee_sdk_svm.conf -key ${ENCLAVE_BASE_DIR}/target/enclave_workspace/private.pem + else + $(SGX_ENCLAVE_SIGNER) sign -enclave ${ENCLAVE_BASE_DIR}/target/svm-output/lib_tee_sdk_svm_load \ + -out ${ENCLAVE_BASE_DIR}/target/svm-output/lib_tee_sdk_svm_load.signed \ + -config ${ENCLAVE_BASE_DIR}/src/main/resources/tee_sdk_svm.conf -key $(ENCLAVE_PRIVATE_PEM_PATH) + endif endif diff --git a/sdk/native/script/build_app/make.sh b/sdk/native/script/build_app/make.sh index 3c522dd..cf8bfb4 100644 --- a/sdk/native/script/build_app/make.sh +++ b/sdk/native/script/build_app/make.sh @@ -1,15 +1,19 @@ #!/bin/bash # shellcheck disable=SC2006 -this_script_dir=`dirname "$0"` +export BUILD_SCRIPT_DIR=`dirname "$0"` +# set enclave project's base dir path. export ENCLAVE_BASE_DIR="$1" +# set enclave platform, such as mock_in_svm and tee_sdk. enclave_platform_config=$2 +# get enclave private pem for making .signed file. +export ENCLAVE_PRIVATE_PEM_PATH=$3 # Create a native image building workspace in application's enclave submodule. mkdir -p "${ENCLAVE_BASE_DIR}"/target/enclave_workspace # copy Makefile script to enclave_workspace. -cp -r "${this_script_dir}"/Makefile "${ENCLAVE_BASE_DIR}"/target/enclave_workspace +cp -r "${BUILD_SCRIPT_DIR}"/Makefile "${ENCLAVE_BASE_DIR}"/target/enclave_workspace # cd to enclave workspace. cd "${ENCLAVE_BASE_DIR}"/target/enclave_workspace diff --git a/sdk/native/script/build_enclave_sdk/Makefile b/sdk/native/script/build_enclave_sdk/Makefile index 0154540..6098d52 100644 --- a/sdk/native/script/build_enclave_sdk/Makefile +++ b/sdk/native/script/build_enclave_sdk/Makefile @@ -8,10 +8,12 @@ build: ifeq ($(TEE_SDK), TRUE) $(MAKE) -C $(ENCLAVE_BASE_DIR)/src/main/native/cpp/platform/tee_sdk_svm/wrapper $(MAKE) -C $(ENCLAVE_BASE_DIR)/src/main/native/cpp/platform/tee_sdk_svm/edge_routines + $(MAKE) -C $(ENCLAVE_BASE_DIR)/src/main/native/cpp/platform/tee_sdk_svm/remote_attestation_generate endif clean: ifeq ($(TEE_SDK), TRUE) $(MAKE) -C $(ENCLAVE_BASE_DIR)/src/main/native/cpp/platform/tee_sdk_svm/wrapper clean $(MAKE) -C $(ENCLAVE_BASE_DIR)/src/main/native/cpp/platform/tee_sdk_svm/edge_routines clean + $(MAKE) -C $(ENCLAVE_BASE_DIR)/src/main/native/cpp/platform/tee_sdk_svm/remote_attestation_generate clean endif \ No newline at end of file diff --git a/sdk/native/script/build_host_sdk/Makefile b/sdk/native/script/build_host_sdk/Makefile index 9d65c19..ceff503 100644 --- a/sdk/native/script/build_host_sdk/Makefile +++ b/sdk/native/script/build_host_sdk/Makefile @@ -11,6 +11,7 @@ endif ifeq ($(TEE_SDK), TRUE) $(MAKE) -C $(HOST_BASE_DIR)/src/main/native/cpp/platform/tee_sdk_svm + $(MAKE) -C $(HOST_BASE_DIR)/src/main/native/cpp/attestation_verify/sgx/jni endif clean: @@ -20,4 +21,5 @@ endif ifeq ($(TEE_SDK), TRUE) $(MAKE) -C $(HOST_BASE_DIR)/src/main/native/cpp/platform/tee_sdk_svm clean + $(MAKE) -C $(HOST_BASE_DIR)/src/main/native/cpp/attestation_verify/sgx/jni clean endif \ No newline at end of file diff --git a/sdk/native/script/build_host_sdk/make.sh b/sdk/native/script/build_host_sdk/make.sh index c543036..70181db 100644 --- a/sdk/native/script/build_host_sdk/make.sh +++ b/sdk/native/script/build_host_sdk/make.sh @@ -48,6 +48,7 @@ then # copy jni.so to target/classes, which will be packed into a jar file. if [[ $TEE_SDK == TRUE ]]; then cp -r "$NATIVE_BASE_DIR"/bin/platform/tee_sdk_svm/jni "$HOST_BASE_DIR"/target/classes + cp -r "$NATIVE_BASE_DIR"/bin/remote_attestation "$HOST_BASE_DIR"/target/classes fi else echo "unsupported make command!!!" diff --git a/test/enclave/pom.xml b/test/enclave/pom.xml index 9300bd2..2bbb426 100644 --- a/test/enclave/pom.xml +++ b/test/enclave/pom.xml @@ -14,6 +14,7 @@ <url></url> <properties> <svm.maven.version>0.9.10</svm.maven.version> + <com.alibaba.enclave.privatePem.path></com.alibaba.enclave.privatePem.path> </properties> <profiles> <profile> @@ -94,6 +95,7 @@ <argument>/opt/javaenclave/build_app/make.sh</argument> <argument>${project.basedir}</argument> <argument>${com.alibaba.enclave.platform}</argument> + <argument>${com.alibaba.enclave.privatePem.path}</argument> </arguments> </configuration> </execution> diff --git a/test/host/src/test/java/com/alibaba/confidentialcomputing/test/host/TestJavaEnclaveService.java b/test/host/src/test/java/com/alibaba/confidentialcomputing/test/host/TestJavaEnclaveService.java index 4304ac9..c913318 100644 --- a/test/host/src/test/java/com/alibaba/confidentialcomputing/test/host/TestJavaEnclaveService.java +++ b/test/host/src/test/java/com/alibaba/confidentialcomputing/test/host/TestJavaEnclaveService.java @@ -1,17 +1,17 @@ package com.alibaba.confidentialcomputing.test.host; +import java.io.IOException; import java.util.Iterator; +import com.alibaba.confidentialcomputing.host.*; import com.alibaba.confidentialcomputing.host.exception.EnclaveCreatingException; import com.alibaba.confidentialcomputing.host.exception.EnclaveDestroyingException; +import com.alibaba.confidentialcomputing.host.exception.RemoteAttestationException; import com.alibaba.confidentialcomputing.host.exception.ServicesLoadingException; import com.alibaba.confidentialcomputing.test.common.EnclaveException; import com.alibaba.confidentialcomputing.test.common.JavaEnclaveException; import com.alibaba.confidentialcomputing.test.common.ReflectionCallService; import com.alibaba.confidentialcomputing.test.common.SayHelloService; -import com.alibaba.confidentialcomputing.host.Enclave; -import com.alibaba.confidentialcomputing.host.EnclaveFactory; -import com.alibaba.confidentialcomputing.host.EnclaveType; import org.junit.jupiter.api.Test; @@ -19,8 +19,16 @@ import static org.junit.jupiter.api.Assertions.*; public class TestJavaEnclaveService { private String sayHelloService(EnclaveType type, String plain) throws - EnclaveCreatingException, ServicesLoadingException, EnclaveDestroyingException { + EnclaveCreatingException, ServicesLoadingException, EnclaveDestroyingException, RemoteAttestationException, IOException { Enclave enclave = EnclaveFactory.create(type); + if (type == EnclaveType.TEE_SDK) { + TeeSdkAttestationReport report = (TeeSdkAttestationReport) RemoteAttestation.generateAttestationReport(enclave, null); + assertEquals(report.getEnclaveType(), EnclaveType.TEE_SDK); + assertNotNull(report.getQuote()); + assertEquals(0, RemoteAttestation.verifyAttestationReport(report)); + assertNotNull(report.getMeasurementEnclave()); + assertNotNull(report.getMeasurementSigner()); + } Iterator<SayHelloService> userServices = enclave.load(SayHelloService.class); assertNotNull(userServices); assertTrue(userServices.hasNext()); @@ -30,8 +38,16 @@ public class TestJavaEnclaveService { return result; } - private void reflectionCallService(EnclaveType type) throws EnclaveCreatingException, ServicesLoadingException, EnclaveDestroyingException { + private void reflectionCallService(EnclaveType type) throws EnclaveCreatingException, ServicesLoadingException, EnclaveDestroyingException, RemoteAttestationException { Enclave enclave = EnclaveFactory.create(type); + if (type == EnclaveType.TEE_SDK) { + TeeSdkAttestationReport report = (TeeSdkAttestationReport) RemoteAttestation.generateAttestationReport(enclave, null); + assertEquals(report.getEnclaveType(), EnclaveType.TEE_SDK); + assertNotNull(report.getQuote()); + assertEquals(0, RemoteAttestation.verifyAttestationReport(report)); + assertNotNull(report.getMeasurementEnclave()); + assertNotNull(report.getMeasurementSigner()); + } Iterator<ReflectionCallService> userServices = enclave.load(ReflectionCallService.class); assertNotNull(userServices); assertTrue(userServices.hasNext()); @@ -41,8 +57,16 @@ public class TestJavaEnclaveService { enclave.destroy(); } - private void javaEnclaveException(EnclaveType type) throws EnclaveCreatingException, ServicesLoadingException, EnclaveDestroyingException { + private void javaEnclaveException(EnclaveType type) throws EnclaveCreatingException, ServicesLoadingException, EnclaveDestroyingException, RemoteAttestationException { Enclave enclave = EnclaveFactory.create(type); + if (type == EnclaveType.TEE_SDK) { + TeeSdkAttestationReport report = (TeeSdkAttestationReport) RemoteAttestation.generateAttestationReport(enclave, null); + assertEquals(report.getEnclaveType(), EnclaveType.TEE_SDK); + assertNotNull(report.getQuote()); + assertEquals(0, RemoteAttestation.verifyAttestationReport(report)); + assertNotNull(report.getMeasurementEnclave()); + assertNotNull(report.getMeasurementSigner()); + } Iterator<EnclaveException> userServices = enclave.load(EnclaveException.class); assertNotNull(userServices); assertTrue(userServices.hasNext()); @@ -53,21 +77,21 @@ public class TestJavaEnclaveService { @Test public void testSayHelloService() throws - EnclaveCreatingException, EnclaveDestroyingException, ServicesLoadingException { + EnclaveCreatingException, EnclaveDestroyingException, ServicesLoadingException, RemoteAttestationException, IOException { assertEquals("Hello World", sayHelloService(EnclaveType.MOCK_IN_JVM, "Hello World")); assertEquals("Hello World", sayHelloService(EnclaveType.MOCK_IN_SVM, "Hello World")); assertEquals("Hello World", sayHelloService(EnclaveType.TEE_SDK, "Hello World")); } @Test - public void testReflectionCallService() throws ServicesLoadingException, EnclaveCreatingException, EnclaveDestroyingException { + public void testReflectionCallService() throws ServicesLoadingException, EnclaveCreatingException, EnclaveDestroyingException, RemoteAttestationException { reflectionCallService(EnclaveType.MOCK_IN_JVM); reflectionCallService(EnclaveType.MOCK_IN_SVM); reflectionCallService(EnclaveType.TEE_SDK); } @Test - public void testJavaEnclaveException() throws ServicesLoadingException, EnclaveCreatingException, EnclaveDestroyingException { + public void testJavaEnclaveException() throws ServicesLoadingException, EnclaveCreatingException, EnclaveDestroyingException, RemoteAttestationException { javaEnclaveException(EnclaveType.MOCK_IN_JVM); javaEnclaveException(EnclaveType.MOCK_IN_SVM); javaEnclaveException(EnclaveType.TEE_SDK); diff --git a/tools/cicd/make.sh b/tools/cicd/make.sh index 77f0311..f4667ea 100755 --- a/tools/cicd/make.sh +++ b/tools/cicd/make.sh @@ -1,7 +1,7 @@ #!/bin/bash BUILD_IMAGE=javaenclave_build -BUILD_TAG=v0.1.8 +BUILD_TAG=v0.1.9 SHELL_FOLDER=$(cd "$(dirname "$0")";pwd) @@ -25,11 +25,14 @@ if [[ "$(docker images -q ${BUILD_IMAGE}:${BUILD_TAG} 2> /dev/null)" == "" ]]; t rm -f sgx_linux_x64_sdk_2.17.100.0.bin fi +# Set PCCS for DCAP Remote Attestation. +PCCS_URL='https://sgx-dcap-server.cn-beijing.aliyuncs.com/sgx/certification/v3/' + # test JavaEnclave's unit test cases and samples docker run -i --rm --privileged --network host \ -w "${WORKDIR}" \ -v "${HOME}"/.m2:/root/.m2 -v "${WORKDIR}":"${WORKDIR}" \ +-e PCCS_URL=${PCCS_URL} \ -v /dev/sgx_enclave:/dev/sgx/enclave \ -v /dev/sgx_provision:/dev/sgx/provision \ ${BUILD_IMAGE}:${BUILD_TAG} /bin/bash build.sh - --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
