Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grpc ServiceProvider #218

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions gen_pubkey_header.sh
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions src/enclave/Common/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
5 changes: 5 additions & 0 deletions src/enclave/ServiceProvider/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}")
Expand All @@ -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)
Expand Down
37 changes: 37 additions & 0 deletions src/enclave/ServiceProvider/SP.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#include <jni.h>
#include <string>

#include "ServiceProvider.h"

#ifndef _Included_SP
#define _Included_SP
Expand All @@ -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
Expand Down
103 changes: 102 additions & 1 deletion src/enclave/ServiceProvider/ServiceProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@
#include "ias_ra.h"
#include "iasrequest.h"
#include "json.hpp"
#include "sp_crypto.h"

#include <openenclave/host.h>
#include <openenclave/host_verify.h>

#include "ServiceProvider.h"

// For debugging
#include <iomanip>

// 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};
Expand Down Expand Up @@ -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<oe_report_msg_t *>(report_bytes);

uint32_t shared_key_msg_size = 0;
std::unique_ptr<oe_shared_key_msg_t> 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<uint8_t *>(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) {
Expand Down Expand Up @@ -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());

Expand Down Expand Up @@ -235,9 +326,14 @@ std::unique_ptr<oe_shared_key_msg_t>
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<oe_shared_key_msg_t> shared_key_msg(new oe_shared_key_msg_t);

EVP_PKEY *pkey = buffer_to_public_key((char *)report_msg->public_key, -1);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand All @@ -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
Expand Down
27 changes: 27 additions & 0 deletions src/enclave/ServiceProvider/ServiceProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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
Expand All @@ -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_Connection> ias;
bool is_production;
bool linkable_signature;
Expand Down
37 changes: 34 additions & 3 deletions src/enclave/ServiceProvider/ServiceProviderJNI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t *>(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(
Expand All @@ -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;
}
Loading