From 022c439fc07aacac91799cf1cf4ef2615c792c79 Mon Sep 17 00:00:00 2001 From: Eric Feng Date: Tue, 27 Apr 2021 03:05:45 +0000 Subject: [PATCH 1/4] gRPC ServiceProvider functions --- src/enclave/Common/common.h | 2 + src/enclave/ServiceProvider/SP.h | 42 +++ .../ServiceProvider/ServiceProvider.cpp | 119 ++++++ src/enclave/ServiceProvider/ServiceProvider.h | 25 ++ .../ServiceProvider/ServiceProviderJNI.cpp | 42 ++- src/enclave/ServiceProvider/sp_crypto.cpp | 340 ++++++++++++++---- src/enclave/ServiceProvider/sp_crypto.h | 20 +- .../cs/rise/opaque/execution/SP.scala | 5 +- 8 files changed, 514 insertions(+), 81 deletions(-) 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/SP.h b/src/enclave/ServiceProvider/SP.h index 0c5623e408..957f24f947 100644 --- a/src/enclave/ServiceProvider/SP.h +++ b/src/enclave/ServiceProvider/SP.h @@ -1,4 +1,8 @@ #include +#include +#include + +#include "ServiceProvider.h" #ifndef _Included_SP #define _Included_SP @@ -18,6 +22,44 @@ 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) { + +// std::cout << "Enter wrapper function" << std::endl; + sp->process_enclave_report_python_wrapper(report, report_len, ret_val, ret_len); +// std::cout << "Exit wrapper function" << std::endl; +} + +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..03f744f643 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,87 @@ 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 +// uint8_t * new_key = (uint8_t *) calloc(LC_AESGCM_KEY_SIZE, sizeof(uint8_t)); + 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); + +// free(new_key); + + // 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; +} + +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 +204,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,15 +328,24 @@ std::unique_ptr ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, uint32_t *shared_key_msg_size) { +// std::cout << "Enter process_enclave_report" << std::endl; + + 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); +// std::cout << "Before get public key" << std::endl; EVP_PKEY *pkey = buffer_to_public_key((char *)report_msg->public_key, -1); if (pkey == nullptr) { throw std::runtime_error("buffer_to_public_key failed."); } +// std::cout << "After get public key" << std::endl; #ifdef SIMULATE std::cerr << "Not running remote attestation because executing in simulation mode" << std::endl; @@ -254,11 +356,13 @@ ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, oe_result_t result = OE_FAILURE; uint8_t sha256[32]; +// std::cout << "Before oe verify" << std::endl; result = oe_verify_remote_report(report_msg->report, report_msg->report_size, NULL, 0, &parsed_report); if (result != OE_OK) { throw std::runtime_error(std::string("oe_verify_remote_report: ") + oe_result_str(result)); } +// std::cout << "After oe verify" << std::endl; // mrsigner verification // 2) validate the enclave identity's signed_id is the hash of the public @@ -267,6 +371,7 @@ ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, // 2a) Read in the public key as a string +// std::cout << "Before read public key from outside" << std::endl; std::string public_key_file = std::string(std::getenv("OPAQUE_HOME")); public_key_file.append("/public_key.pub"); @@ -281,14 +386,19 @@ ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, public_key.assign((std::istreambuf_iterator(t)), std::istreambuf_iterator()); public_key.replace(public_key_size, 1, "\0"); +// std::cout << "After read public key from outside" << std::endl; + +// std::cout << "Before verify mrsigner" << std::endl; if (!verify_mrsigner((char *)public_key.c_str(), public_key.size(), parsed_report.identity.signer_id, sizeof(parsed_report.identity.signer_id))) { throw std::runtime_error(std::string("failed: mrsigner not equal!")); } +// std::cout << "After verify mrsigner" << std::endl; // TODO missing the hash verification step +// std::cout << "Before rest of verification" << std::endl; // check the enclave's product id and security version if (parsed_report.identity.product_id[0] != 1) { throw std::runtime_error(std::string("identity.product_id checking failed.")); @@ -308,22 +418,31 @@ ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, if (memcmp(parsed_report.report_data, sha256, sizeof(sha256)) != 0) { throw std::runtime_error(std::string("SHA256 mismatch.")); } +// std::cout << "After rest of verification" << std::endl; #endif // 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) { throw std::runtime_error(std::string("public_encrypt failed")); } +// std::cout << "Before prepare shared_key_msg" << std::endl; // 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); +// std::cout << "After prepare shared_key_msg" << std::endl; // clean up EVP_PKEY_free(pkey); diff --git a/src/enclave/ServiceProvider/ServiceProvider.h b/src/enclave/ServiceProvider/ServiceProvider.h index ad582a0b9a..b511fe1800 100644 --- a/src/enclave/ServiceProvider/ServiceProvider.h +++ b/src/enclave/ServiceProvider/ServiceProvider.h @@ -13,6 +13,11 @@ class ServiceProvider { : spid(spid), is_production(is_production), linkable_signature(linkable_signature), ias_api_version(3), require_attestation(std::getenv("OPAQUE_REQUIRE_ATTESTATION")) {} + //TODO: Make sure this actually frees user_cert + ~ServiceProvider() { + free(this->user_cert); + } + /** Load an OpenSSL private key from the specified file. */ void load_private_key(const std::string &filename); @@ -22,12 +27,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 +64,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..700abcbb9e 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,38 @@ 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; + +// jboolean if_copy = false; +// char *cipher_bytes = (char *) env->GetByteArrayElements(ciphertext, &if_copy); +// size_t clength = (size_t)env->GetArrayLength(ciphertext); + + 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->ReleaseByteArrayElements(ciphertext, (jbyte *)cipher_bytes, 0); + 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..facdad180a 100644 --- a/src/enclave/ServiceProvider/sp_crypto.cpp +++ b/src/enclave/ServiceProvider/sp_crypto.cpp @@ -33,6 +33,9 @@ #include +// Debugging +#include + // print functions for debugging lc_status_t print_priv_key(lc_ec256_private_t p_private) { uint8_t *ptr = (uint8_t *)p_private.r; @@ -142,98 +145,280 @@ void lc_ssl2sgx(EC_KEY *ssl_key, lc_ec256_private_t *p_private, lc_ec256_public_ BN_free(y_ec); } +int handleErrors() { + return LC_ERROR_UNEXPECTED; +} + +/////////////////////////////////////// Test Encrypt Begin ///////////////////////////////////////////// + +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; +} + +/////////////////////////////////////// Test Decrypt End /////////////////////////////////////////////// + + + // 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) { +//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 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; +// int len = 0; +// uint32_t ciphertext_len; +// +// (void)p_aad; +// (void)aad_len; +// +// /* Create and initialise the context */ +// ctx = EVP_CIPHER_CTX_new(); +// if (!ctx) { +// fprintf(stderr, "[%s] EVP context init failure\n", __FUNCTION__); +// return LC_ERROR_UNEXPECTED; +// } +// +// /* Initialise the encryption operation. */ +// ret = EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL); +// if (ret != 1) { +// fprintf(stderr, "[%s] encryption init failure\n", __FUNCTION__); +// return LC_ERROR_UNEXPECTED; +// } +// +// /* Set IV length if default 12 bytes (96 bits) is not appropriate */ +// ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL); +// if (ret != 1) { +// fprintf(stderr, "[%s] encryption IV length init failure\n", __FUNCTION__); +// return LC_ERROR_UNEXPECTED; +// } +// +// /* Initialise key and 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; +// } +// +// /* Provide any AAD data. This can be called zero or more times as +// * required +// */ +// if (p_aad != NULL) { +// ret = EVP_EncryptUpdate(ctx, NULL, &len, p_aad, aad_len); +// if (ret != 1) { +// fprintf(stderr, "[%s] encryption AAD update failure\n", __FUNCTION__); +// return LC_ERROR_UNEXPECTED; +// } +// } +// +// /* Provide the message to be encrypted, and obtain the encrypted output. +// * EVP_EncryptUpdate can be called multiple times if necessary +// */ +// ret = EVP_EncryptUpdate(ctx, p_dst, &len, p_src, (int)src_len); +// if (ret != 1) { +// fprintf(stderr, "[%s] encryption update failure, ret is %u, len is %u\n", __FUNCTION__, ret, +// len); +// return LC_ERROR_UNEXPECTED; +// } +// ciphertext_len = len; +// +// /* Finalise the encryption. Normally ciphertext bytes may be written at +// * this stage, but this does not occur in GCM mode +// */ +// ret = EVP_EncryptFinal_ex(ctx, p_dst + len, &len); +// if (ret != 1) { +// fprintf(stderr, "[%s] encryption final failure\n", __FUNCTION__); +// return LC_ERROR_UNEXPECTED; +// } +// ciphertext_len += len; +// +// /* Get the tag */ +// ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, LC_AESGCM_MAC_SIZE, +// p_out_mac); +// if (ret != 1) { +// fprintf(stderr, "[%s] \n", __FUNCTION__); +// return LC_ERROR_UNEXPECTED; +// } +// +// /* Clean up */ +// EVP_CIPHER_CTX_free(ctx); +// +// return LC_SUCCESS; - EVP_CIPHER_CTX *ctx = NULL; - int ret = 0; - int len = 0; - uint32_t ciphertext_len; + EVP_CIPHER_CTX *ctx; - (void)p_aad; - (void)aad_len; + int len; - /* Create and initialise the context */ - ctx = EVP_CIPHER_CTX_new(); - if (!ctx) { - fprintf(stderr, "[%s] EVP context init failure\n", __FUNCTION__); - return LC_ERROR_UNEXPECTED; - } + int ciphertext_len; - /* Initialise the encryption operation. */ - ret = EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL); - if (ret != 1) { - fprintf(stderr, "[%s] encryption init failure\n", __FUNCTION__); - return LC_ERROR_UNEXPECTED; - } - /* Set IV length if default 12 bytes (96 bits) is not appropriate */ - ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL); - if (ret != 1) { - fprintf(stderr, "[%s] encryption IV length init failure\n", __FUNCTION__); - return LC_ERROR_UNEXPECTED; - } + /* Create and initialise the context */ + if(!(ctx = EVP_CIPHER_CTX_new())) + handleErrors(); - /* Initialise key and IV */ - ret = EVP_EncryptInit_ex(ctx, NULL, NULL, (const unsigned char *)*p_key, p_iv); - if (ret != 1) { - fprintf(stderr, "[%s] encryption init failure\n", __FUNCTION__); - return LC_ERROR_UNEXPECTED; - } + /* Initialise the encryption operation. */ + if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + handleErrors(); - /* Provide any AAD data. This can be called zero or more times as - * required - */ - if (p_aad != NULL) { - ret = EVP_EncryptUpdate(ctx, NULL, &len, p_aad, aad_len); - if (ret != 1) { - fprintf(stderr, "[%s] encryption AAD update failure\n", __FUNCTION__); - return LC_ERROR_UNEXPECTED; - } - } + /* + * Set IV length if default 12 bytes (96 bits) is not appropriate + */ + if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) + handleErrors(); - /* Provide the message to be encrypted, and obtain the encrypted output. - * EVP_EncryptUpdate can be called multiple times if necessary - */ - ret = EVP_EncryptUpdate(ctx, p_dst, &len, p_src, (int)src_len); - if (ret != 1) { - fprintf(stderr, "[%s] encryption update failure, ret is %u, len is %u\n", __FUNCTION__, ret, - len); - return LC_ERROR_UNEXPECTED; - } - ciphertext_len = len; + /* Initialise key and IV */ + if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) + handleErrors(); - /* Finalise the encryption. Normally ciphertext bytes may be written at - * this stage, but this does not occur in GCM mode - */ - ret = EVP_EncryptFinal_ex(ctx, p_dst + len, &len); - if (ret != 1) { - fprintf(stderr, "[%s] encryption final failure\n", __FUNCTION__); - return LC_ERROR_UNEXPECTED; - } - ciphertext_len += len; + /* + * Provide any AAD data. This can be called zero or more times as + * required + */ + if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len)) + handleErrors(); - /* Get the tag */ - ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, LC_AESGCM_MAC_SIZE, - (unsigned char *)*p_out_mac); - if (ret != 1) { - fprintf(stderr, "[%s] \n", __FUNCTION__); - return LC_ERROR_UNEXPECTED; - } + /* + * 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; - /* Clean up */ - EVP_CIPHER_CTX_free(ctx); + std::cout << "ciphertext: " << ciphertext << std::endl; - return LC_SUCCESS; + /* + * Finalise the encryption. Normally ciphertext bytes may be written at + * this stage, but this does not occur in GCM mode + */ + if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) + handleErrors(); + ciphertext_len += len; + + std::cout << "ciphertext len: " << ciphertext_len << std::endl; + + /* Get the tag */ + if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)) + handleErrors(); + + std::cout << "ciphertext tag: " << tag << std::endl; + + /* Clean up */ + EVP_CIPHER_CTX_free(ctx); + + return ciphertext_len; } lc_status_t lc_rijndael128GCM_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *aad, int aad_len, unsigned char *tag, unsigned char *key, unsigned char *iv, unsigned char *plaintext) { + std::cout << "Enter lc_decrypt" << std::endl; + std::cout << ciphertext_len << std::endl; + EVP_CIPHER_CTX *ctx; int len; int plaintext_len; @@ -244,22 +429,26 @@ lc_status_t lc_rijndael128GCM_decrypt(unsigned char *ciphertext, int ciphertext_ /* Create and initialise the context */ if (!(ctx = EVP_CIPHER_CTX_new())) { + std::cout << "error 0" << std::endl; printf("ctx not initialized correct\n"); } /* Initialise the decryption operation. */ if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) { + std::cout << "error 1" << std::endl; printf("evp decryption not initialized correct\n"); } /* Set IV length. Not necessary if this is 12 bytes (96 bits) */ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL)) { + std::cout << "error 2" << std::endl; printf("evp IV size not correctly set\n"); return LC_ERROR_UNEXPECTED; } /* Initialise key and IV */ if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) { + std::cout << "error 3" << std::endl; fprintf(stderr, "evp decryption init incorrect\n"); return LC_ERROR_UNEXPECTED; } @@ -268,6 +457,7 @@ lc_status_t lc_rijndael128GCM_decrypt(unsigned char *ciphertext, int ciphertext_ * required */ if (aad != NULL) { + std::cout << "error 4" << std::endl; if (!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len)) { fprintf(stderr, "evp decryption aad update failed\n"); return LC_ERROR_UNEXPECTED; @@ -279,6 +469,7 @@ lc_status_t lc_rijndael128GCM_decrypt(unsigned char *ciphertext, int ciphertext_ */ if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) { fprintf(stderr, "decryption update failed\n"); + std::cout << "error 5" << std::endl; return LC_ERROR_UNEXPECTED; } @@ -286,6 +477,7 @@ lc_status_t lc_rijndael128GCM_decrypt(unsigned char *ciphertext, int ciphertext_ /* Set expected tag value. Works in OpenSSL 1.0.1d and later */ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag)) { + std::cout << "error 6" << std::endl; fprintf(stderr, "decryption tag setting failed\n"); return LC_ERROR_UNEXPECTED; } @@ -293,7 +485,9 @@ lc_status_t lc_rijndael128GCM_decrypt(unsigned char *ciphertext, int ciphertext_ /* Finalise the decryption. A positive return value indicates success, * anything else is a failure - the plaintext is not trustworthy. */ + std::cout << "Before final decrypt" << std::endl; ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len); + std::cout << "End final decrypt" << std::endl; /* Clean up */ EVP_CIPHER_CTX_free(ctx); diff --git a/src/enclave/ServiceProvider/sp_crypto.h b/src/enclave/ServiceProvider/sp_crypto.h index f914e6b730..d2fc9bef52 100644 --- a/src/enclave/ServiceProvider/sp_crypto.h +++ b/src/enclave/ServiceProvider/sp_crypto.h @@ -173,10 +173,17 @@ EC_KEY *get_priv_key(lc_ec256_private_t *p_private); *buffer should be >= src_len. lc_aes_gcm_128bit_tag_t *p_out_mac - Pointer to *MAC generated from encryption process NOTE: Wrapper is responsible for *confirming decryption tag matches encryption tag */ -LC_LIBCRYPTO_API lc_status_t WARN_UNUSED 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); +//LC_LIBCRYPTO_API lc_status_t WARN_UNUSED 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); + +LC_LIBCRYPTO_API int WARN_UNUSED 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); lc_status_t WARN_UNUSED lc_rijndael128GCM_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *aad, int aad_len, @@ -184,6 +191,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/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] } From 0f3cb7fac2f1674ae13b93ccada53e2453e0431c Mon Sep 17 00:00:00 2001 From: Eric Feng Date: Tue, 27 Apr 2021 03:32:09 +0000 Subject: [PATCH 2/4] ServiceProvider cmake necessary files --- gen_pubkey_header.sh | 27 ++++++++++++++++++++++ src/enclave/ServiceProvider/CMakeLists.txt | 5 ++++ 2 files changed, 32 insertions(+) create mode 100755 gen_pubkey_header.sh 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/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) From 46418aae35f4e75eadccce087f244fd6d1063899 Mon Sep 17 00:00:00 2001 From: Eric Feng Date: Tue, 27 Apr 2021 03:49:41 +0000 Subject: [PATCH 3/4] gRPC RA functions --- .../edu/berkeley/cs/rise/opaque/RA.scala | 77 +++++++++++++++++-- 1 file changed, 71 insertions(+), 6 deletions(-) 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..2e7a0cab8d 100644 --- a/src/main/scala/edu/berkeley/cs/rise/opaque/RA.scala +++ b/src/main/scala/edu/berkeley/cs/rise/opaque/RA.scala @@ -17,8 +17,11 @@ package edu.berkeley.cs.rise.opaque +import javax.xml.bind.DatatypeConverter + 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 @@ -38,14 +41,10 @@ object RA extends Logging { val rdd = sc.parallelize(Seq.fill(numExecutors) { () }, numExecutors) val intelCert = Utils.findResource("AttestationReportSigningCACert.pem") + val userCert = scala.io.Source.fromFile("/home/opaque/opaque/user1.crt").mkString val sp = new SP() - Utils.sharedKey match { - case Some(sharedKey) => - sp.Init(sharedKey, intelCert) - case None => - throw new OpaqueException("Cannot begin attestation without sharedKey.") - } + sp.Init(Utils.sharedKey, userCert) val numAttested = Utils.numAttested // Runs on executors @@ -107,7 +106,9 @@ object RA extends Logging { logInfo( s"RA.run: ${Utils.numEnclaves.value} unattested, ${Utils.numAttested.value} attested" ) + initRA(sc) + LA.initLA(sc) } Thread.sleep(100) } @@ -128,4 +129,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") + } + } } From 731b4aada9163b8044223d203c11c750c38f46b8 Mon Sep 17 00:00:00 2001 From: Eric Feng Date: Thu, 13 May 2021 23:23:55 +0000 Subject: [PATCH 4/4] Clean code and update pr --- src/enclave/ServiceProvider/SP.h | 5 - .../ServiceProvider/ServiceProvider.cpp | 20 +- src/enclave/ServiceProvider/ServiceProvider.h | 10 +- .../ServiceProvider/ServiceProviderJNI.cpp | 5 - src/enclave/ServiceProvider/sp_crypto.cpp | 228 ++++++------------ src/enclave/ServiceProvider/sp_crypto.h | 15 +- .../edu/berkeley/cs/rise/opaque/RA.scala | 19 +- 7 files changed, 94 insertions(+), 208 deletions(-) diff --git a/src/enclave/ServiceProvider/SP.h b/src/enclave/ServiceProvider/SP.h index 957f24f947..378219c72b 100644 --- a/src/enclave/ServiceProvider/SP.h +++ b/src/enclave/ServiceProvider/SP.h @@ -1,6 +1,5 @@ #include #include -#include #include "ServiceProvider.h" @@ -38,15 +37,11 @@ sp_init_wrapper(ServiceProvider * sp, uint8_t * provided_cert, size_t cert_len) void sp_process_enclave_report(ServiceProvider * sp, uint8_t * report, size_t * report_len, uint8_t ** ret_val, size_t * ret_len) { - -// std::cout << "Enter wrapper function" << std::endl; sp->process_enclave_report_python_wrapper(report, report_len, ret_val, ret_len); -// std::cout << "Exit wrapper function" << std::endl; } 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); } diff --git a/src/enclave/ServiceProvider/ServiceProvider.cpp b/src/enclave/ServiceProvider/ServiceProvider.cpp index 03f744f643..57135b8375 100644 --- a/src/enclave/ServiceProvider/ServiceProvider.cpp +++ b/src/enclave/ServiceProvider/ServiceProvider.cpp @@ -59,7 +59,6 @@ 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 -// uint8_t * new_key = (uint8_t *) calloc(LC_AESGCM_KEY_SIZE, sizeof(uint8_t)); const char *new_key = (const char *)"01234567890123456789012345678901"; if (strlen(new_key) * sizeof(char) != LC_AESGCM_KEY_SIZE) { @@ -69,8 +68,6 @@ void ServiceProvider::init_wrapper(uint8_t * provided_cert, size_t cert_len) { memcpy(this->shared_key, new_key, LC_AESGCM_KEY_SIZE); -// free(new_key); - // Initialize user certificate char * cert = (char *) malloc(cert_len * sizeof(char)); memcpy(cert, provided_cert, cert_len); @@ -129,6 +126,7 @@ void ServiceProvider::aes_gcm_decrypt(char * cipher, size_t * cipher_len, uint8_ *plain = plaintext_msg; } +// Free the malloced user certificate void ServiceProvider::clean_up() { free(this->user_cert); } @@ -328,8 +326,6 @@ std::unique_ptr ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, uint32_t *shared_key_msg_size) { -// std::cout << "Enter process_enclave_report" << std::endl; - if (this->user_cert == NULL) { throw std::runtime_error("SP not initialized with user cert"); } @@ -340,12 +336,10 @@ ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, std::unique_ptr shared_key_msg(new oe_shared_key_msg_t); -// std::cout << "Before get public key" << std::endl; EVP_PKEY *pkey = buffer_to_public_key((char *)report_msg->public_key, -1); if (pkey == nullptr) { throw std::runtime_error("buffer_to_public_key failed."); } -// std::cout << "After get public key" << std::endl; #ifdef SIMULATE std::cerr << "Not running remote attestation because executing in simulation mode" << std::endl; @@ -356,13 +350,11 @@ ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, oe_result_t result = OE_FAILURE; uint8_t sha256[32]; -// std::cout << "Before oe verify" << std::endl; result = oe_verify_remote_report(report_msg->report, report_msg->report_size, NULL, 0, &parsed_report); if (result != OE_OK) { throw std::runtime_error(std::string("oe_verify_remote_report: ") + oe_result_str(result)); } -// std::cout << "After oe verify" << std::endl; // mrsigner verification // 2) validate the enclave identity's signed_id is the hash of the public @@ -371,7 +363,6 @@ ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, // 2a) Read in the public key as a string -// std::cout << "Before read public key from outside" << std::endl; std::string public_key_file = std::string(std::getenv("OPAQUE_HOME")); public_key_file.append("/public_key.pub"); @@ -386,19 +377,13 @@ ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, public_key.assign((std::istreambuf_iterator(t)), std::istreambuf_iterator()); public_key.replace(public_key_size, 1, "\0"); -// std::cout << "After read public key from outside" << std::endl; - -// std::cout << "Before verify mrsigner" << std::endl; if (!verify_mrsigner((char *)public_key.c_str(), public_key.size(), parsed_report.identity.signer_id, sizeof(parsed_report.identity.signer_id))) { throw std::runtime_error(std::string("failed: mrsigner not equal!")); } -// std::cout << "After verify mrsigner" << std::endl; - // TODO missing the hash verification step -// std::cout << "Before rest of verification" << std::endl; // check the enclave's product id and security version if (parsed_report.identity.product_id[0] != 1) { throw std::runtime_error(std::string("identity.product_id checking failed.")); @@ -418,7 +403,6 @@ ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, if (memcmp(parsed_report.report_data, sha256, sizeof(sha256)) != 0) { throw std::runtime_error(std::string("SHA256 mismatch.")); } -// std::cout << "After rest of verification" << std::endl; #endif @@ -432,7 +416,6 @@ ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, throw std::runtime_error(std::string("public_encrypt failed")); } -// std::cout << "Before prepare shared_key_msg" << std::endl; // Prepare shared_key_msg memcpy_s(shared_key_msg->shared_key_ciphertext, OE_SHARED_KEY_CIPHERTEXT_SIZE, encrypted_sharedkey, encrypted_sharedkey_size); @@ -442,7 +425,6 @@ ServiceProvider::process_enclave_report(oe_report_msg_t *report_msg, shared_key_msg->user_cert_len = cert_len; *shared_key_msg_size = sizeof(oe_shared_key_msg_t); -// std::cout << "After prepare shared_key_msg" << std::endl; // clean up EVP_PKEY_free(pkey); diff --git a/src/enclave/ServiceProvider/ServiceProvider.h b/src/enclave/ServiceProvider/ServiceProvider.h index b511fe1800..b112854c9a 100644 --- a/src/enclave/ServiceProvider/ServiceProvider.h +++ b/src/enclave/ServiceProvider/ServiceProvider.h @@ -13,10 +13,12 @@ class ServiceProvider { : spid(spid), is_production(is_production), linkable_signature(linkable_signature), ias_api_version(3), require_attestation(std::getenv("OPAQUE_REQUIRE_ATTESTATION")) {} - //TODO: Make sure this actually frees user_cert - ~ServiceProvider() { - free(this->user_cert); - } + // 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); diff --git a/src/enclave/ServiceProvider/ServiceProviderJNI.cpp b/src/enclave/ServiceProvider/ServiceProviderJNI.cpp index 700abcbb9e..e3c725bf62 100644 --- a/src/enclave/ServiceProvider/ServiceProviderJNI.cpp +++ b/src/enclave/ServiceProvider/ServiceProviderJNI.cpp @@ -69,10 +69,6 @@ JNIEXPORT jbyteArray JNICALL Java_edu_berkeley_cs_rise_opaque_execution_SP_Decry (void)obj; -// jboolean if_copy = false; -// char *cipher_bytes = (char *) env->GetByteArrayElements(ciphertext, &if_copy); -// size_t clength = (size_t)env->GetArrayLength(ciphertext); - char *cipher_bytes = (char *) env->GetStringUTFChars(ciphertext, nullptr); size_t clength = (size_t) strlen(cipher_bytes); @@ -91,7 +87,6 @@ JNIEXPORT jbyteArray JNICALL Java_edu_berkeley_cs_rise_opaque_execution_SP_Decry jbyteArray plaintext = env->NewByteArray((jsize) plength); env->SetByteArrayRegion(plaintext, 0, plength, (jbyte *)plaintext_copy); -// env->ReleaseByteArrayElements(ciphertext, (jbyte *)cipher_bytes, 0); env->ReleaseStringUTFChars(ciphertext, cipher_bytes); delete[] plaintext_copy; diff --git a/src/enclave/ServiceProvider/sp_crypto.cpp b/src/enclave/ServiceProvider/sp_crypto.cpp index facdad180a..f55d6e3892 100644 --- a/src/enclave/ServiceProvider/sp_crypto.cpp +++ b/src/enclave/ServiceProvider/sp_crypto.cpp @@ -33,9 +33,6 @@ #include -// Debugging -#include - // print functions for debugging lc_status_t print_priv_key(lc_ec256_private_t p_private) { uint8_t *ptr = (uint8_t *)p_private.r; @@ -149,8 +146,6 @@ int handleErrors() { return LC_ERROR_UNEXPECTED; } -/////////////////////////////////////// Test Encrypt Begin ///////////////////////////////////////////// - int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext, unsigned char *tag) { @@ -250,16 +245,6 @@ int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, return plaintext_len; } -/////////////////////////////////////// Test Decrypt End /////////////////////////////////////////////// - - - -// 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 lc_rijndael128GCM_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *aad, int aad_len, unsigned char *key, @@ -267,158 +252,92 @@ int lc_rijndael128GCM_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *ciphertext, unsigned char *tag) { -// EVP_CIPHER_CTX *ctx = NULL; -// int ret = 0; -// int len = 0; -// uint32_t ciphertext_len; -// -// (void)p_aad; -// (void)aad_len; -// -// /* Create and initialise the context */ -// ctx = EVP_CIPHER_CTX_new(); -// if (!ctx) { -// fprintf(stderr, "[%s] EVP context init failure\n", __FUNCTION__); -// return LC_ERROR_UNEXPECTED; -// } -// -// /* Initialise the encryption operation. */ -// ret = EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL); -// if (ret != 1) { -// fprintf(stderr, "[%s] encryption init failure\n", __FUNCTION__); -// return LC_ERROR_UNEXPECTED; -// } -// -// /* Set IV length if default 12 bytes (96 bits) is not appropriate */ -// ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL); -// if (ret != 1) { -// fprintf(stderr, "[%s] encryption IV length init failure\n", __FUNCTION__); -// return LC_ERROR_UNEXPECTED; -// } -// -// /* Initialise key and 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; -// } -// -// /* Provide any AAD data. This can be called zero or more times as -// * required -// */ -// if (p_aad != NULL) { -// ret = EVP_EncryptUpdate(ctx, NULL, &len, p_aad, aad_len); -// if (ret != 1) { -// fprintf(stderr, "[%s] encryption AAD update failure\n", __FUNCTION__); -// return LC_ERROR_UNEXPECTED; -// } -// } -// -// /* Provide the message to be encrypted, and obtain the encrypted output. -// * EVP_EncryptUpdate can be called multiple times if necessary -// */ -// ret = EVP_EncryptUpdate(ctx, p_dst, &len, p_src, (int)src_len); -// if (ret != 1) { -// fprintf(stderr, "[%s] encryption update failure, ret is %u, len is %u\n", __FUNCTION__, ret, -// len); -// return LC_ERROR_UNEXPECTED; -// } -// ciphertext_len = len; -// -// /* Finalise the encryption. Normally ciphertext bytes may be written at -// * this stage, but this does not occur in GCM mode -// */ -// ret = EVP_EncryptFinal_ex(ctx, p_dst + len, &len); -// if (ret != 1) { -// fprintf(stderr, "[%s] encryption final failure\n", __FUNCTION__); -// return LC_ERROR_UNEXPECTED; -// } -// ciphertext_len += len; -// -// /* Get the tag */ -// ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, LC_AESGCM_MAC_SIZE, -// p_out_mac); -// if (ret != 1) { -// fprintf(stderr, "[%s] \n", __FUNCTION__); -// return LC_ERROR_UNEXPECTED; -// } -// -// /* Clean up */ -// EVP_CIPHER_CTX_free(ctx); -// -// return LC_SUCCESS; - - 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. */ - if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) - handleErrors(); + EVP_CIPHER_CTX *ctx = NULL; + int ret = 0; + int len = 0; + uint32_t ciphertext_len; - /* - * Set IV length if default 12 bytes (96 bits) is not appropriate - */ - if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) - handleErrors(); + (void)p_aad; + (void)aad_len; - /* Initialise key and IV */ - if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) - handleErrors(); + /* Create and initialise the context */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) { + fprintf(stderr, "[%s] EVP context init failure\n", __FUNCTION__); + return LC_ERROR_UNEXPECTED; + } - /* - * Provide any AAD data. This can be called zero or more times as - * required - */ - if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len)) - handleErrors(); + /* Initialise the encryption operation. */ + ret = EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL); + if (ret != 1) { + fprintf(stderr, "[%s] encryption init failure\n", __FUNCTION__); + return LC_ERROR_UNEXPECTED; + } - /* - * 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; + /* Set IV length if default 12 bytes (96 bits) is not appropriate */ + ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL); + if (ret != 1) { + fprintf(stderr, "[%s] encryption IV length init failure\n", __FUNCTION__); + return LC_ERROR_UNEXPECTED; + } - std::cout << "ciphertext: " << ciphertext << std::endl; + /* Initialise key and 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; + } - /* - * Finalise the encryption. Normally ciphertext bytes may be written at - * this stage, but this does not occur in GCM mode - */ - if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) - handleErrors(); - ciphertext_len += len; + /* Provide any AAD data. This can be called zero or more times as + * required + */ + if (p_aad != NULL) { + ret = EVP_EncryptUpdate(ctx, NULL, &len, p_aad, aad_len); + if (ret != 1) { + fprintf(stderr, "[%s] encryption AAD update failure\n", __FUNCTION__); + return LC_ERROR_UNEXPECTED; + } + } - std::cout << "ciphertext len: " << ciphertext_len << std::endl; + /* Provide the message to be encrypted, and obtain the encrypted output. + * EVP_EncryptUpdate can be called multiple times if necessary + */ + ret = EVP_EncryptUpdate(ctx, p_dst, &len, p_src, (int)src_len); + if (ret != 1) { + fprintf(stderr, "[%s] encryption update failure, ret is %u, len is %u\n", __FUNCTION__, ret, + len); + return LC_ERROR_UNEXPECTED; + } + ciphertext_len = len; - /* Get the tag */ - if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)) - handleErrors(); + /* Finalise the encryption. Normally ciphertext bytes may be written at + * this stage, but this does not occur in GCM mode + */ + ret = EVP_EncryptFinal_ex(ctx, p_dst + len, &len); + if (ret != 1) { + fprintf(stderr, "[%s] encryption final failure\n", __FUNCTION__); + return LC_ERROR_UNEXPECTED; + } + ciphertext_len += len; - std::cout << "ciphertext tag: " << tag << std::endl; + /* Get the tag */ + ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, LC_AESGCM_MAC_SIZE, + p_out_mac); + if (ret != 1) { + fprintf(stderr, "[%s] \n", __FUNCTION__); + return LC_ERROR_UNEXPECTED; + } - /* Clean up */ - EVP_CIPHER_CTX_free(ctx); + /* Clean up */ + EVP_CIPHER_CTX_free(ctx); - return ciphertext_len; + return LC_SUCCESS; } lc_status_t lc_rijndael128GCM_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *aad, int aad_len, unsigned char *tag, unsigned char *key, unsigned char *iv, unsigned char *plaintext) { - std::cout << "Enter lc_decrypt" << std::endl; - std::cout << ciphertext_len << std::endl; - EVP_CIPHER_CTX *ctx; int len; int plaintext_len; @@ -429,26 +348,22 @@ lc_status_t lc_rijndael128GCM_decrypt(unsigned char *ciphertext, int ciphertext_ /* Create and initialise the context */ if (!(ctx = EVP_CIPHER_CTX_new())) { - std::cout << "error 0" << std::endl; printf("ctx not initialized correct\n"); } /* Initialise the decryption operation. */ if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) { - std::cout << "error 1" << std::endl; printf("evp decryption not initialized correct\n"); } /* Set IV length. Not necessary if this is 12 bytes (96 bits) */ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL)) { - std::cout << "error 2" << std::endl; printf("evp IV size not correctly set\n"); return LC_ERROR_UNEXPECTED; } /* Initialise key and IV */ if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) { - std::cout << "error 3" << std::endl; fprintf(stderr, "evp decryption init incorrect\n"); return LC_ERROR_UNEXPECTED; } @@ -457,7 +372,6 @@ lc_status_t lc_rijndael128GCM_decrypt(unsigned char *ciphertext, int ciphertext_ * required */ if (aad != NULL) { - std::cout << "error 4" << std::endl; if (!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len)) { fprintf(stderr, "evp decryption aad update failed\n"); return LC_ERROR_UNEXPECTED; @@ -469,7 +383,6 @@ lc_status_t lc_rijndael128GCM_decrypt(unsigned char *ciphertext, int ciphertext_ */ if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) { fprintf(stderr, "decryption update failed\n"); - std::cout << "error 5" << std::endl; return LC_ERROR_UNEXPECTED; } @@ -477,7 +390,6 @@ lc_status_t lc_rijndael128GCM_decrypt(unsigned char *ciphertext, int ciphertext_ /* Set expected tag value. Works in OpenSSL 1.0.1d and later */ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag)) { - std::cout << "error 6" << std::endl; fprintf(stderr, "decryption tag setting failed\n"); return LC_ERROR_UNEXPECTED; } @@ -485,9 +397,7 @@ lc_status_t lc_rijndael128GCM_decrypt(unsigned char *ciphertext, int ciphertext_ /* Finalise the decryption. A positive return value indicates success, * anything else is a failure - the plaintext is not trustworthy. */ - std::cout << "Before final decrypt" << std::endl; ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len); - std::cout << "End final decrypt" << std::endl; /* Clean up */ EVP_CIPHER_CTX_free(ctx); diff --git a/src/enclave/ServiceProvider/sp_crypto.h b/src/enclave/ServiceProvider/sp_crypto.h index d2fc9bef52..a83445e925 100644 --- a/src/enclave/ServiceProvider/sp_crypto.h +++ b/src/enclave/ServiceProvider/sp_crypto.h @@ -173,17 +173,10 @@ EC_KEY *get_priv_key(lc_ec256_private_t *p_private); *buffer should be >= src_len. lc_aes_gcm_128bit_tag_t *p_out_mac - Pointer to *MAC generated from encryption process NOTE: Wrapper is responsible for *confirming decryption tag matches encryption tag */ -//LC_LIBCRYPTO_API lc_status_t WARN_UNUSED 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); - -LC_LIBCRYPTO_API int WARN_UNUSED 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); +LC_LIBCRYPTO_API lc_status_t WARN_UNUSED 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); lc_status_t WARN_UNUSED lc_rijndael128GCM_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *aad, int aad_len, 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 2e7a0cab8d..e3c69eae44 100644 --- a/src/main/scala/edu/berkeley/cs/rise/opaque/RA.scala +++ b/src/main/scala/edu/berkeley/cs/rise/opaque/RA.scala @@ -17,8 +17,6 @@ package edu.berkeley.cs.rise.opaque -import javax.xml.bind.DatatypeConverter - import org.apache.spark.{SparkContext, SparkEnv} import org.apache.spark.internal.Logging import org.apache.spark.sql.SparkSession @@ -40,11 +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() - sp.Init(Utils.sharedKey, userCert) + // 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.") + } val numAttested = Utils.numAttested // Runs on executors @@ -108,7 +118,6 @@ object RA extends Logging { ) initRA(sc) - LA.initLA(sc) } Thread.sleep(100) }