diff --git a/gen_pubkey_header.sh b/gen_pubkey_header.sh new file mode 100755 index 0000000000..d3d059ec3f --- /dev/null +++ b/gen_pubkey_header.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# Copyright (c) Open Enclave SDK contributors. +# Licensed under the MIT License. + +destfile="$1" +pubkey_file="$2" + +cat > "$destfile" << EOF +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + +EOF + +printf 'static const char OTHER_ENCLAVE_PUBLIC_KEY[] =' >> "$destfile" +while IFS="" read -r p || [ -n "$p" ] +do + # Sometimes openssl can insert carriage returns into the PEM files. Let's remove those! + CR=$(printf "\r") + p=$(echo "$p" | tr -d "$CR") + printf '\n \"%s\\n\"' "$p" >> "$destfile" +done < "$pubkey_file" +printf ';\n' >> "$destfile" + +cat >> "$destfile" << EOF + +EOF diff --git a/src/enclave/Common/common.h b/src/enclave/Common/common.h index e69a0be099..80a5248a1f 100644 --- a/src/enclave/Common/common.h +++ b/src/enclave/Common/common.h @@ -84,6 +84,8 @@ typedef struct oe_report_msg_t { typedef struct oe_shared_key_msg_t { uint8_t shared_key_ciphertext[OE_SHARED_KEY_CIPHERTEXT_SIZE]; + size_t user_cert_len; + char user_cert[2000]; } oe_shared_key_msg_t; #endif // COMMON_H diff --git a/src/enclave/ServiceProvider/CMakeLists.txt b/src/enclave/ServiceProvider/CMakeLists.txt index 2047dc15f2..d01ef970d3 100644 --- a/src/enclave/ServiceProvider/CMakeLists.txt +++ b/src/enclave/ServiceProvider/CMakeLists.txt @@ -16,6 +16,8 @@ link_directories(${OE_LIBDIR}) link_directories(${OE_LIBDIR}/openenclave/enclave) include_directories(${OE_INCLUDEDIR}) include_directories(${OE_INCLUDEDIR}/openenclave/3rdparty) +include_directories(${CMAKE_SOURCE_DIR}/../Common) +include_directories(${CMAKE_SOURCE_DIR}/../Include) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -Wno-attributes") set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_CXX_FLAGS}") @@ -26,6 +28,9 @@ if ("$ENV{MODE}" STREQUAL "SIMULATE") target_compile_definitions(ra_jni PUBLIC -DSIMULATE) endif() +set(OE_MIN_VERSION 0.12.0) +find_package(OpenEnclave ${OE_MIN_VERSION} CONFIG REQUIRED) + find_library(CRYPTO_LIB crypto) find_library(SSL_LIB ssl) target_link_libraries(ra_jni ${CRYPTO_LIB} ${SSL_LIB} mbedcrypto mbedtls openenclave::oehost) diff --git a/src/enclave/ServiceProvider/SP.h b/src/enclave/ServiceProvider/SP.h index 0c5623e408..378219c72b 100644 --- a/src/enclave/ServiceProvider/SP.h +++ b/src/enclave/ServiceProvider/SP.h @@ -1,4 +1,7 @@ #include +#include + +#include "ServiceProvider.h" #ifndef _Included_SP #define _Included_SP @@ -18,6 +21,40 @@ JNIEXPORT jbyteArray JNICALL Java_edu_berkeley_cs_rise_opaque_execution_SP_SPPro jobject, jbyteArray); +JNIEXPORT jbyteArray JNICALL +Java_edu_berkeley_cs_rise_opaque_execution_SP_Decrypt(JNIEnv *, jobject, jstring); + +// Python wrapper functions +ServiceProvider* sp_new(){ + const std::string id("client"); + return new ServiceProvider(id, false, false); +} + +void +sp_init_wrapper(ServiceProvider * sp, uint8_t * provided_cert, size_t cert_len) { + sp->init_wrapper(provided_cert, cert_len); +} + +void +sp_process_enclave_report(ServiceProvider * sp, uint8_t * report, size_t * report_len, uint8_t ** ret_val, size_t * ret_len) { + sp->process_enclave_report_python_wrapper(report, report_len, ret_val, ret_len); +} + +void +sp_decrypt(ServiceProvider * sp, char * cipher, size_t * cipher_len, uint8_t ** plain, size_t * plain_len) { + sp->aes_gcm_decrypt(cipher, cipher_len, plain, plain_len); +} + +void +sp_free_array(ServiceProvider *sp, uint8_t ** array) { + sp->free_array(array); +} + +void +sp_clean(ServiceProvider *sp) { + sp->clean_up(); +} + #ifdef __cplusplus } #endif diff --git a/src/enclave/ServiceProvider/ServiceProvider.cpp b/src/enclave/ServiceProvider/ServiceProvider.cpp index 6ed9ba9e48..57135b8375 100644 --- a/src/enclave/ServiceProvider/ServiceProvider.cpp +++ b/src/enclave/ServiceProvider/ServiceProvider.cpp @@ -12,12 +12,16 @@ #include "ias_ra.h" #include "iasrequest.h" #include "json.hpp" +#include "sp_crypto.h" #include #include #include "ServiceProvider.h" +// For debugging +#include + // Your 16-byte Service Provider ID (SPID), assigned by Intel. const uint8_t spid[] = {0xA4, 0x62, 0x09, 0x2E, 0x1B, 0x59, 0x26, 0xDF, 0x44, 0x69, 0xD5, 0x61, 0xE2, 0x54, 0xB0, 0x1E}; @@ -52,6 +56,85 @@ void lc_check(lc_status_t ret) { } } +// TODO: Create shared key by reading from file. Currently key is hard-coded +void ServiceProvider::init_wrapper(uint8_t * provided_cert, size_t cert_len) { + // Initialize key + const char *new_key = (const char *)"01234567890123456789012345678901"; + + if (strlen(new_key) * sizeof(char) != LC_AESGCM_KEY_SIZE) { + std::cout << "size of provided key: " << sizeof(new_key) << std::endl; + throw std::runtime_error("new key not right size"); + } + + memcpy(this->shared_key, new_key, LC_AESGCM_KEY_SIZE); + + // Initialize user certificate + char * cert = (char *) malloc(cert_len * sizeof(char)); + memcpy(cert, provided_cert, cert_len); + this->user_cert = cert; +} + +void +ServiceProvider::process_enclave_report_python_wrapper(uint8_t * report, size_t * report_len, uint8_t ** ret_val, size_t * ret_len) { + + size_t report_size = *report_len; + uint8_t* report_bytes = new uint8_t[report_size]; + memcpy(report_bytes, report, report_size); + oe_report_msg_t *report_msg = reinterpret_cast(report_bytes); + + uint32_t shared_key_msg_size = 0; + std::unique_ptr shared_key_msg; + try { + shared_key_msg = this->process_enclave_report(report_msg, &shared_key_msg_size); + } catch (const std::runtime_error &e) { + throw std::runtime_error("Failed to process report."); + } + uint8_t * ret_msg = (uint8_t *) malloc(shared_key_msg_size); + + memcpy(ret_msg, reinterpret_cast(shared_key_msg.get()), shared_key_msg_size); + + *ret_len = shared_key_msg_size; + *ret_val = ret_msg; + +} + +void ServiceProvider::aes_gcm_decrypt(char * cipher, size_t * cipher_len, uint8_t ** plain, size_t * plain_len) { + + (void) cipher_len; + + size_t sz = 0; + char * cipher_decode = base64_decode(cipher, &sz); + + // Obtain the plaintext len + size_t plaintext_length = sz - (LC_AESGCM_IV_SIZE + LC_AESGCM_MAC_SIZE); + unsigned char * plaintext_msg = (unsigned char *) malloc(plaintext_length); + + unsigned char *iv_ptr = (unsigned char *)cipher_decode; + unsigned char *ciphertext_ptr = (unsigned char *)(cipher_decode + LC_AESGCM_IV_SIZE); + unsigned char *mac_ptr = (unsigned char *) (cipher_decode + LC_AESGCM_IV_SIZE + plaintext_length); + + int ret = decrypt(ciphertext_ptr, sz - LC_AESGCM_IV_SIZE - LC_AESGCM_MAC_SIZE, + this->shared_key, iv_ptr, + plaintext_msg, mac_ptr); + if (ret == 0) { + throw std::runtime_error("Failed to decrypt"); + } + + free(cipher_decode); + + *plain_len = plaintext_length; + *plain = plaintext_msg; +} + +// Free the malloced user certificate +void ServiceProvider::clean_up() { + free(this->user_cert); +} + +void ServiceProvider::free_array(uint8_t ** array) { + free(*array); +} + void ServiceProvider::load_private_key(const std::string &filename) { FILE *private_key_file = fopen(filename.c_str(), "r"); if (private_key_file == nullptr) { @@ -119,6 +202,14 @@ void ServiceProvider::set_shared_key(const uint8_t *shared_key) { memcpy(this->shared_key, shared_key, LC_AESGCM_KEY_SIZE); } +void ServiceProvider::set_user_cert(const std::string user_cert) { + const char * cert = user_cert.c_str(); + uint32_t cert_len = strlen(cert); + + this->user_cert = (char *) malloc(cert_len * sizeof(char)); + memcpy(this->user_cert, cert, cert_len); +} + void ServiceProvider::export_public_key_code(const std::string &filename) { std::ofstream file(filename.c_str()); @@ -235,9 +326,14 @@ std::unique_ptr ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, uint32_t *shared_key_msg_size) { + if (this->user_cert == NULL) { + throw std::runtime_error("SP not initialized with user cert"); + } + int ret; unsigned char encrypted_sharedkey[OE_SHARED_KEY_CIPHERTEXT_SIZE]; size_t encrypted_sharedkey_size = sizeof(encrypted_sharedkey); + std::unique_ptr shared_key_msg(new oe_shared_key_msg_t); EVP_PKEY *pkey = buffer_to_public_key((char *)report_msg->public_key, -1); @@ -286,7 +382,6 @@ ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, sizeof(parsed_report.identity.signer_id))) { throw std::runtime_error(std::string("failed: mrsigner not equal!")); } - // TODO missing the hash verification step // check the enclave's product id and security version @@ -314,6 +409,7 @@ ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, // Encrypt shared key ret = public_encrypt(pkey, this->shared_key, LC_AESGCM_KEY_SIZE, encrypted_sharedkey, &encrypted_sharedkey_size); + if (ret == 0) { throw std::runtime_error(std::string("public_encrypt: buffer too small")); } else if (ret < 0) { @@ -323,6 +419,11 @@ ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, // Prepare shared_key_msg memcpy_s(shared_key_msg->shared_key_ciphertext, OE_SHARED_KEY_CIPHERTEXT_SIZE, encrypted_sharedkey, encrypted_sharedkey_size); + + size_t cert_len = strlen(this->user_cert) + 1; + memcpy_s(shared_key_msg->user_cert, cert_len, this->user_cert, cert_len); + shared_key_msg->user_cert_len = cert_len; + *shared_key_msg_size = sizeof(oe_shared_key_msg_t); // clean up diff --git a/src/enclave/ServiceProvider/ServiceProvider.h b/src/enclave/ServiceProvider/ServiceProvider.h index ad582a0b9a..b112854c9a 100644 --- a/src/enclave/ServiceProvider/ServiceProvider.h +++ b/src/enclave/ServiceProvider/ServiceProvider.h @@ -13,6 +13,13 @@ class ServiceProvider { : spid(spid), is_production(is_production), linkable_signature(linkable_signature), ias_api_version(3), require_attestation(std::getenv("OPAQUE_REQUIRE_ATTESTATION")) {} + // TODO: Determine if want to use explicit call or deconstructor. + // Deconstructor might be called when user_cert not initialized yet + // Explicit call may give more control in comparison +// ~ServiceProvider() { +// free(this->user_cert); +// } + /** Load an OpenSSL private key from the specified file. */ void load_private_key(const std::string &filename); @@ -22,12 +29,29 @@ class ServiceProvider { */ void set_shared_key(const uint8_t *shared_key); + void set_user_cert(std::string user_cert); + /** * After calling load_private_key, write the corresponding public key as a C++ * header file. This file should be compiled into the enclave. */ void export_public_key_code(const std::string &filename); + void + init_wrapper(uint8_t * provided_cert, size_t cert_len); + + void + process_enclave_report_python_wrapper(uint8_t * report, size_t * report_len, uint8_t ** ret_val, size_t * ret_len); + + void + aes_gcm_decrypt(char * cipher, size_t * cipher_len, uint8_t ** plain, size_t * plain_len); + + void + clean_up(); + + void + free_array(uint8_t ** array); + /** * Process attestation report from an enclave, verify the report, and send the * shared key to the enclave @@ -42,8 +66,11 @@ class ServiceProvider { lc_ec256_private_t sp_priv_key; uint8_t shared_key[LC_AESGCM_KEY_SIZE]; + std::string spid; + char *user_cert = NULL; + std::unique_ptr ias; bool is_production; bool linkable_signature; diff --git a/src/enclave/ServiceProvider/ServiceProviderJNI.cpp b/src/enclave/ServiceProvider/ServiceProviderJNI.cpp index 6b6f0b7b69..e3c725bf62 100644 --- a/src/enclave/ServiceProvider/ServiceProviderJNI.cpp +++ b/src/enclave/ServiceProvider/ServiceProviderJNI.cpp @@ -19,23 +19,24 @@ void jni_throw(JNIEnv *env, const char *message) { JNIEXPORT void JNICALL Java_edu_berkeley_cs_rise_opaque_execution_SP_Init(JNIEnv *env, jobject obj, jbyteArray shared_key, - jstring intel_cert) { + jstring user_cert) { (void)env; (void)obj; jboolean if_copy = false; jbyte *shared_key_bytes = env->GetByteArrayElements(shared_key, &if_copy); - const char *intel_cert_str = env->GetStringUTFChars(intel_cert, nullptr); + const char *user_cert_str = env->GetStringUTFChars(user_cert, nullptr); try { service_provider.set_shared_key(reinterpret_cast(shared_key_bytes)); + service_provider.set_user_cert(user_cert_str); } catch (const std::runtime_error &e) { jni_throw(env, e.what()); } env->ReleaseByteArrayElements(shared_key, shared_key_bytes, 0); - env->ReleaseStringUTFChars(intel_cert, intel_cert_str); + env->ReleaseStringUTFChars(user_cert, user_cert_str); } JNIEXPORT jbyteArray JNICALL Java_edu_berkeley_cs_rise_opaque_execution_SP_ProcessEnclaveReport( @@ -62,3 +63,33 @@ JNIEXPORT jbyteArray JNICALL Java_edu_berkeley_cs_rise_opaque_execution_SP_Proce return array_ret; } + +JNIEXPORT jbyteArray JNICALL Java_edu_berkeley_cs_rise_opaque_execution_SP_Decrypt( + JNIEnv *env, jobject obj, jstring ciphertext) { + + (void)obj; + + char *cipher_bytes = (char *) env->GetStringUTFChars(ciphertext, nullptr); + size_t clength = (size_t) strlen(cipher_bytes); + + uint8_t *plaintext_copy = nullptr; + size_t plength = 0; + + if (cipher_bytes == nullptr) { + jni_throw(env, "Encrypt: JNI failed to get input byte array."); + } else { + plength = clength - LC_AESGCM_IV_SIZE - LC_AESGCM_MAC_SIZE; + plaintext_copy = new uint8_t[plength]; + + service_provider.aes_gcm_decrypt(cipher_bytes, &clength, &plaintext_copy, &plength); + } + + jbyteArray plaintext = env->NewByteArray((jsize) plength); + env->SetByteArrayRegion(plaintext, 0, plength, (jbyte *)plaintext_copy); + + env->ReleaseStringUTFChars(ciphertext, cipher_bytes); + + delete[] plaintext_copy; + + return plaintext; +} diff --git a/src/enclave/ServiceProvider/sp_crypto.cpp b/src/enclave/ServiceProvider/sp_crypto.cpp index f8ef40bbae..f55d6e3892 100644 --- a/src/enclave/ServiceProvider/sp_crypto.cpp +++ b/src/enclave/ServiceProvider/sp_crypto.cpp @@ -142,11 +142,115 @@ void lc_ssl2sgx(EC_KEY *ssl_key, lc_ec256_private_t *p_private, lc_ec256_public_ BN_free(y_ec); } -// This is a wrapper around the OpenSSL EVP AES-GCM encryption -lc_status_t lc_rijndael128GCM_encrypt(const lc_aes_gcm_128bit_key_t *p_key, const uint8_t *p_src, - uint32_t src_len, uint8_t *p_dst, const uint8_t *p_iv, - uint32_t iv_len, const uint8_t *p_aad, uint32_t aad_len, - lc_aes_gcm_128bit_tag_t *p_out_mac) { +int handleErrors() { + return LC_ERROR_UNEXPECTED; +} + +int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, + unsigned char *iv, unsigned char *ciphertext, unsigned char *tag) +{ + EVP_CIPHER_CTX *ctx; + + int len; + + int ciphertext_len; + + /* Create and initialise the context */ + if(!(ctx = EVP_CIPHER_CTX_new())) + handleErrors(); + + /* + * Initialise the encryption operation. IMPORTANT - ensure you use a key + * and IV size appropriate for your cipher + * In this example we are using 256 bit AES (i.e. a 256 bit key). The + * IV size for *most* modes is the same as the block size. For AES this + * is 128 bits + */ + if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL)) + handleErrors(); + + if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, key, iv)) + handleErrors(); + + /* + * Provide the message to be encrypted, and obtain the encrypted output. + * EVP_EncryptUpdate can be called multiple times if necessary + */ + if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) + handleErrors(); + ciphertext_len = len; + + /* + * Finalise the encryption. Further ciphertext bytes may be written at + * this stage. + */ + if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) + handleErrors(); + ciphertext_len += len; + + if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)) + handleErrors(); + + /* Clean up */ + EVP_CIPHER_CTX_free(ctx); + + return ciphertext_len; +} + +int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, + unsigned char *iv, unsigned char *plaintext, unsigned char * tag) +{ + EVP_CIPHER_CTX *ctx; + + int len; + + int plaintext_len; + + /* Create and initialise the context */ + if(!(ctx = EVP_CIPHER_CTX_new())) + handleErrors(); + + /* + * Initialise the decryption operation. IMPORTANT - ensure you use a key + * and IV size appropriate for your cipher + * In this example we are using 256 bit AES (i.e. a 256 bit key). The + * IV size for *most* modes is the same as the block size. For AES this + * is 128 bits + */ + if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, key, iv)) + handleErrors(); + + /* + * Provide the message to be decrypted, and obtain the plaintext output. + * EVP_DecryptUpdate can be called multiple times if necessary. + */ + if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) + handleErrors(); + plaintext_len = len; + + if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag)) + handleErrors(); + + /* + * Finalise the decryption. Further plaintext bytes may be written at + * this stage. + */ + if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) + handleErrors(); + plaintext_len += len; + + /* Clean up */ + EVP_CIPHER_CTX_free(ctx); + + return plaintext_len; +} + +int lc_rijndael128GCM_encrypt(unsigned char *plaintext, int plaintext_len, + unsigned char *aad, int aad_len, + unsigned char *key, + unsigned char *iv, int iv_len, + unsigned char *ciphertext, + unsigned char *tag) { EVP_CIPHER_CTX *ctx = NULL; int ret = 0; @@ -178,7 +282,7 @@ lc_status_t lc_rijndael128GCM_encrypt(const lc_aes_gcm_128bit_key_t *p_key, cons } /* Initialise key and IV */ - ret = EVP_EncryptInit_ex(ctx, NULL, NULL, (const unsigned char *)*p_key, p_iv); + ret = EVP_EncryptInit_ex(ctx, NULL, NULL, p_key, p_iv); if (ret != 1) { fprintf(stderr, "[%s] encryption init failure\n", __FUNCTION__); return LC_ERROR_UNEXPECTED; @@ -218,7 +322,7 @@ lc_status_t lc_rijndael128GCM_encrypt(const lc_aes_gcm_128bit_key_t *p_key, cons /* Get the tag */ ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, LC_AESGCM_MAC_SIZE, - (unsigned char *)*p_out_mac); + p_out_mac); if (ret != 1) { fprintf(stderr, "[%s] \n", __FUNCTION__); return LC_ERROR_UNEXPECTED; diff --git a/src/enclave/ServiceProvider/sp_crypto.h b/src/enclave/ServiceProvider/sp_crypto.h index f914e6b730..a83445e925 100644 --- a/src/enclave/ServiceProvider/sp_crypto.h +++ b/src/enclave/ServiceProvider/sp_crypto.h @@ -184,6 +184,11 @@ lc_status_t WARN_UNUSED lc_rijndael128GCM_decrypt(unsigned char *ciphertext, int unsigned char *iv, unsigned char *plaintext) __attribute__((warn_unused_result)); +int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, + unsigned char *iv, unsigned char *ciphertext, unsigned char *tag); +int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, + unsigned char *iv, unsigned char *plaintext, unsigned char *tag); + /* Message Authentication - Rijndael 128 CMAC * Parameters: * Return: lc_status_t - LC_SUCCESS on success, error code otherwise. diff --git a/src/main/scala/edu/berkeley/cs/rise/opaque/RA.scala b/src/main/scala/edu/berkeley/cs/rise/opaque/RA.scala index 4586ff3973..e3c69eae44 100644 --- a/src/main/scala/edu/berkeley/cs/rise/opaque/RA.scala +++ b/src/main/scala/edu/berkeley/cs/rise/opaque/RA.scala @@ -19,6 +19,7 @@ package edu.berkeley.cs.rise.opaque import org.apache.spark.{SparkContext, SparkEnv} import org.apache.spark.internal.Logging +import org.apache.spark.sql.SparkSession import edu.berkeley.cs.rise.opaque.execution.SP @@ -37,15 +38,23 @@ object RA extends Logging { } val rdd = sc.parallelize(Seq.fill(numExecutors) { () }, numExecutors) - val intelCert = Utils.findResource("AttestationReportSigningCACert.pem") +// val intelCert = Utils.findResource("AttestationReportSigningCACert.pem") + + // TODO: Hard-coded string path + val userCert = scala.io.Source.fromFile("/home/opaque/opaque/user1.crt").mkString val sp = new SP() + // TODO: Upon merging local attestion code, the shared key will be removed from the code + // and the following two lines of code should be used instead of current SP init code +// val fillerKey: Array[Byte] = Array.fill[Byte](GCM_KEY_LENGTH)(0) +// sp.Init(fillerKey, userCert) + Utils.sharedKey match { - case Some(sharedKey) => - sp.Init(sharedKey, intelCert) - case None => - throw new OpaqueException("Cannot begin attestation without sharedKey.") - } + case Some(sharedKey) => + sp.Init(sharedKey, intelCert) + case None => + throw new OpaqueException("Cannot begin attestation without sharedKey.") + } val numAttested = Utils.numAttested // Runs on executors @@ -107,6 +116,7 @@ object RA extends Logging { logInfo( s"RA.run: ${Utils.numEnclaves.value} unattested, ${Utils.numAttested.value} attested" ) + initRA(sc) } Thread.sleep(100) @@ -128,4 +138,68 @@ object RA extends Logging { Thread.sleep(5000) } +// Helper functions for grpc RA + + def printReport(): Unit = { + + val sc = SparkSession.active.sparkContext + if (!sc.isLocal) { + numExecutors = sc.getConf.getInt("spark.executor.instances", -1) + } + + val rdd = sc.parallelize(Seq.fill(numExecutors) {()}, numExecutors) + + // Runs on executors + val msg1s = rdd.mapPartitions { (_) => + // Need to reset attested boolean for client + Utils.attested = false + + val (eid, msg1) = Utils.generateReport() + Iterator((eid, msg1)) + }.collect.toMap + + // Prints out report + var raReport: String = "" + var eidReport: String = "" + + for ((eid, msg) <- msg1s) { + raReport = raReport + Utils.convertBytesToHex(msg) + eidReport = eidReport + eid.toString + " " + } + + print(eidReport) + print(raReport) + + // Need to add tail hex as newline character is causing issues + print("2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d") + } + + def grpcFinishAttestation(keys: String, eids: String): Unit = { + val sc = SparkSession.active.sparkContext + if (!sc.isLocal) { + numExecutors = sc.getConf.getInt("spark.executor.instances", -1) + } + + val rdd = sc.parallelize(Seq.fill(numExecutors) {()}, numExecutors) + + val eidArray = eids.split(" ").map{case eid => eid.toLong} + val keyArray = keys.split(" ").map{case hexString => DatatypeConverter.parseHexBinary(hexString)} + + // Runs on executors + val numAttested = Utils.numAttested + val eidToKeyMap = (eidArray zip keyArray).toMap + + // TODO: Fix to make it so that Utils.finishAttestation actually does something for remote client. + // Currently, since numAttested is full, nothing happens + val attestationResults = rdd.mapPartitions { (_) => + val (enclave, eid) = Utils.finishAttestation(numAttested, eidToKeyMap) + Iterator((eid, true)) + }.collect.toMap + + // -1 for failure, 0 for success + for ((_, ret) <- attestationResults) { + if (!ret) + throw new OpaqueException("Attestation failed") + } + } } diff --git a/src/main/scala/edu/berkeley/cs/rise/opaque/execution/SP.scala b/src/main/scala/edu/berkeley/cs/rise/opaque/execution/SP.scala index b22fac2ecd..24e64077aa 100644 --- a/src/main/scala/edu/berkeley/cs/rise/opaque/execution/SP.scala +++ b/src/main/scala/edu/berkeley/cs/rise/opaque/execution/SP.scala @@ -22,8 +22,11 @@ import ch.jodersky.jni.nativeLoader @nativeLoader("ra_jni") class SP extends java.io.Serializable { // Remote attestation, master side - @native def Init(sharedKey: Array[Byte], intelCert: String): Unit + @native def Init(sharedKey: Array[Byte], userCert: String): Unit @native def SPProcMsg0(msg0Input: Array[Byte]): Unit @native def ProcessEnclaveReport(msg1Input: Array[Byte]): Array[Byte] @native def SPProcMsg3(msg3Input: Array[Byte]): Array[Byte] + + // Decryption, client side + @native def Decrypt(cipher: String): Array[Byte] }