Skip to content
This repository was archived by the owner on Jan 27, 2022. It is now read-only.

Commit 4d5b698

Browse files
author
manju956
committed
Implementation of Enclave Key Refresh
This feature initiates refresh of enclave encryption key pair based on timer value set in the config file. A new pair of encryption key is generated in the enclave and the updated enclave signup details are stored in the KvStorage in workers table. Additioanlly, encryption key signature is also generated during enclave initialization and its made part of PublicEnclaveData. This encryption key signature is re-computed when encryption key gets refreshed. Signed-off-by: manju956 <[email protected]>
1 parent 213a433 commit 4d5b698

File tree

16 files changed

+421
-25
lines changed

16 files changed

+421
-25
lines changed

common/cpp/error.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ namespace tcf {
4646
) : Error(TCF_ERR_CRYPTO, msg) {}
4747
}; // class CryptoError
4848

49+
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
50+
class KeyRefreshError : public Error {
51+
public:
52+
explicit KeyRefreshError(
53+
const std::string& msg
54+
) : Error(TCF_ERR_KEY_REFRESH, msg) {}
55+
}; // class KeyRefreshError
4956

5057
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5158
class MemoryError : public Error {

common/cpp/tcf_error.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ typedef enum {
3535
a TCF_ERR_SYSTEM for reporting.
3636
*/
3737
TCF_ERR_CRYPTO = -11,
38-
TCF_ERR_INVALID_WORKLOAD = -12 /* Invalid workload id */
38+
TCF_ERR_INVALID_WORKLOAD = -12, /* Invalid workload id */
39+
TCF_ERR_KEY_REFRESH = -13 /* Enclave key refresh error */
3940
} tcf_err_t;
4041

4142
typedef enum {

common/cpp/utils.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,3 @@
2020
ByteArray StrToByteArray(std::string str);
2121

2222
std::string ByteArrayToStr(ByteArray ba);
23-

config/tcs_config.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,7 @@ DataEncryptionAlgorithm = "AES-GCM-256"
9999
# starting with tilde "~"
100100
workOrderPayloadFormats = "JSON-RPC"
101101

102+
[WorkerKeyRefresh]
103+
# Configure key refresh interval based on need.
104+
# By default, key refresh feature is disabled.
105+
key_refresh_interval = 0

enclave_manager/avalon_enclave_manager/avalon_enclave_bridge.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ def create_signup_info(originator_public_key_hash, nonce):
210210
signup_info = {
211211
'verifying_key': signup_data['verifying_key'],
212212
'encryption_key': signup_data['encryption_key'],
213+
'encryption_key_signature': signup_data['encryption_key_signature'],
213214
'proof_data': 'Not present',
214215
'enclave_persistent_id': 'Not present'
215216
}
@@ -263,3 +264,23 @@ def create_signup_info(originator_public_key_hash, nonce):
263264

264265
# Now we can return the real object
265266
return signup_info_obj
267+
268+
269+
def refresh_enclave_key(enclave_sealed_data):
270+
"""
271+
Refresh enclave encryption key pair
272+
"""
273+
# start enclave key refresh
274+
updated_signup_data = enclave.RefreshEnclaveKey(enclave_sealed_data)
275+
if updated_signup_data is None:
276+
return None
277+
signup_info = {
278+
'encryption_key':
279+
updated_signup_data['encryption_key'],
280+
'encryption_key_signature':
281+
updated_signup_data['encryption_key_signature'],
282+
'sealed_enclave_data':
283+
updated_signup_data['sealed_enclave_data']
284+
}
285+
286+
return signup_info

enclave_manager/avalon_enclave_manager/avalon_enclave_helper.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ def create_enclave_signup_data(cls, tcf_instance_keys=None):
6868
enclave_info['sealed_data'] = enclave_data.sealed_signup_data
6969
enclave_info['verifying_key'] = enclave_data.verifying_key
7070
enclave_info['encryption_key'] = enclave_data.encryption_key
71+
enclave_info['encryption_key_signature'] = \
72+
enclave_data.encryption_key_signature
7173
enclave_info['enclave_id'] = enclave_data.verifying_key
7274
enclave_info['proof_data'] = ''
7375
if not avalon_enclave.enclave.is_sgx_simulator():
@@ -87,6 +89,8 @@ def __init__(self, enclave_info, tcf_instance_keys):
8789
self.sealed_data = enclave_info['sealed_data']
8890
self.verifying_key = enclave_info['verifying_key']
8991
self.encryption_key = enclave_info['encryption_key']
92+
self.encryption_key_signature = \
93+
enclave_info['encryption_key_signature']
9094
self.proof_data = enclave_info['proof_data']
9195
self.enclave_id = enclave_info['enclave_id']
9296
except KeyError as ke:
@@ -96,6 +100,22 @@ def __init__(self, enclave_info, tcf_instance_keys):
96100
self.enclave_keys = \
97101
keys.EnclaveKeys(self.verifying_key, self.encryption_key)
98102

103+
# -------------------------------------------------------
104+
def initiate_refresh_enclave_key(self):
105+
"""
106+
Initiate worker encryption key refresh and update worker signup details
107+
"""
108+
try:
109+
updated_enclave_data = avalon_enclave.refresh_enclave_key(
110+
self.sealed_data)
111+
except Exception as err:
112+
raise Exception('failed to refresh enclave key; {}'
113+
.format(str(err)))
114+
self.encryption_key = updated_enclave_data["encryption_key"]
115+
self.encryption_key_signature = \
116+
updated_enclave_data["encryption_key_signature"]
117+
self.sealed_data = updated_enclave_data["sealed_enclave_data"]
118+
99119
# -------------------------------------------------------
100120
def send_to_sgx_worker(self, encrypted_request):
101121
"""

enclave_manager/avalon_enclave_manager/enclave_manager.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def __init__(self, config, signup_data, measurements):
5959
# Need to come up with a scheme to generate both for every unique
6060
# encryption key.
6161
self.encryption_key_nonce = ""
62-
self.encryption_key_signature = ""
62+
self.encryption_key_signature = signup_data.encryption_key_signature
6363
self.enclave_id = signup_data.enclave_id
6464
self.extended_measurements = measurements
6565

@@ -330,6 +330,20 @@ def create_enclave_signup_data():
330330
return enclave_signup_data
331331

332332

333+
# -----------------------------------------------------------------
334+
def initiate_key_refresh(enclave_data):
335+
"""
336+
Initiate worker encryption key refresh and update worker details
337+
and updates worker details to kv storage
338+
@param enclave_data - enclave signup data
339+
"""
340+
try:
341+
enclave_signup_data = enclave_data.initiate_refresh_enclave_key()
342+
except Exception as e:
343+
logger.error("failed to get signup data after key refresh: %s", str(e))
344+
return enclave_signup_data
345+
346+
333347
# -----------------------------------------------------------------
334348
def execute_work_order(enclave_data, input_json_str, indent=4):
335349
"""
@@ -430,6 +444,25 @@ def create_json_worker(enclave_data, config):
430444
return json_worker_info
431445

432446

447+
# -----------------------------------------------------------------
448+
def persist_worker(enclave_manager, kv_helper):
449+
"""
450+
Persists worker to KvStorage
451+
452+
@param enclave_manager - instance of EnclaveManager class
453+
@param kv_helper - instance of KvStorage
454+
"""
455+
worker_info = create_json_worker(enclave_manager, enclave_manager.config)
456+
logger.info("Persisting worker to workers table")
457+
worker_id = crypto_utils.strip_begin_end_public_key(
458+
enclave_manager.enclave_id).encode("UTF-8")
459+
# Calculate sha256 of worker id to get 32 bytes. The TC spec proxy
460+
# model contracts expect byte32. Then take a hexdigest for hex str.
461+
worker_id = hashlib.sha256(worker_id).hexdigest()
462+
463+
kv_helper.set("workers", worker_id, worker_info)
464+
465+
433466
# -----------------------------------------------------------------
434467
def start_enclave_manager(config):
435468
"""
@@ -475,17 +508,35 @@ def start_enclave_manager(config):
475508

476509
try:
477510
sleep_interval = int(config["EnclaveManager"]["sleep_interval"])
511+
key_refresh_interval = \
512+
int(config["WorkerKeyRefresh"]["key_refresh_interval"])
478513
except Exception as err:
479514
logger.error("Failed to get sleep interval from config file. " +
480515
"Setting sleep interval to 10 seconds: %s", str(err))
481516
sleep_interval = 10
482517

518+
# key_refresh_time is the time elapsed since last key refresh
519+
key_refresh_time = 0
483520
try:
484521
while True:
522+
if key_refresh_interval > 0 and \
523+
key_refresh_time >= key_refresh_interval:
524+
logger.info("Initiate Worker Key refresh based on timer")
525+
updated_enclave_signup_data = \
526+
initiate_key_refresh(enclave_manager.enclave_data)
527+
# Update Enclave Manager with updated signup data
528+
# after key refresh
529+
enclave_manager = EnclaveManager(
530+
config, enclave_signup_data, extended_measurements)
531+
# Persist updated worker to KV storage
532+
persist_worker(enclave_manager, kv_helper)
533+
key_refresh_time = 0
534+
485535
# Poll KV storage for new work-order requests and process
486536
enclave_manager.process_work_orders(kv_helper)
487537
logger.info("Enclave manager sleeping for %d secs", sleep_interval)
488538
time.sleep(sleep_interval)
539+
key_refresh_time = key_refresh_time + sleep_interval
489540
except Exception as inst:
490541
logger.error("Error while processing work-order; " +
491542
"shutting down enclave manager")

tc/sgx/trusted_worker_manager/enclave/enclave_data.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
#include "jsonvalue.h"
3333
#include "parson.h"
34+
#include "base64.h"
35+
#include "enclave_utils.h"
3436

3537
#include "enclave_data.h"
3638

@@ -57,6 +59,8 @@ EnclaveData::EnclaveData(void) {
5759
// Create the public encryption key
5860
public_encryption_key_ = private_encryption_key_.GetPublicKey();
5961

62+
// Create encryption key signature
63+
generate_encryption_key_signature();
6064
SerializePrivateData();
6165
SerializePublicData();
6266
}
@@ -74,15 +78,11 @@ EnclaveData::~EnclaveData(void) {
7478
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7579
EnclaveData::EnclaveData(const uint8_t* inSealedData) {
7680
tcf::error::ThrowIfNull(inSealedData, "Sealed sign up data pointer is NULL");
77-
7881
uint32_t decrypted_size =
7982
sgx_get_encrypt_txt_len(reinterpret_cast<const sgx_sealed_data_t*>(inSealedData));
8083

81-
// Need to check for error
82-
8384
std::vector<uint8_t> decrypted_data;
8485
decrypted_data.resize(decrypted_size);
85-
8686
// Unseal the data
8787
sgx_status_t ret = sgx_unseal_data(reinterpret_cast<const sgx_sealed_data_t*>(inSealedData),
8888
nullptr, 0, &decrypted_data[0], &decrypted_size);
@@ -95,6 +95,9 @@ EnclaveData::EnclaveData(const uint8_t* inSealedData) {
9595
decrypted_data.clear();
9696
decrypted_data_string.clear();
9797

98+
/* Create encryption key signature */
99+
generate_encryption_key_signature();
100+
98101
SerializePrivateData();
99102
SerializePublicData();
100103
}
@@ -263,6 +266,14 @@ void EnclaveData::SerializePublicData(void) {
263266
tcf::error::ThrowIf<tcf::error::RuntimeError>(
264267
jret != JSONSuccess, "enclave data serialization failed on public encryption key");
265268

269+
// Public encryption key signature
270+
jret =
271+
json_object_dotset_string(dataObject, "EncryptionKeySignature", \
272+
encryption_key_signature_.c_str());
273+
tcf::error::ThrowIf<tcf::error::RuntimeError>(
274+
jret != JSONSuccess, \
275+
"enclave data serialization failed on public encryption key signature");
276+
266277
size_t serializedSize = json_serialization_size(dataValue);
267278

268279
std::vector<char> serialized_buffer;

tc/sgx/trusted_worker_manager/enclave/enclave_data.h

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include <string>
2323

2424
#include "crypto.h"
25+
#include "utils.h"
26+
#include "base64.h"
2527

2628
// JSON format for private data:
2729
// {
@@ -41,21 +43,20 @@
4143
// JSON format for public data
4244
// {
4345
// "SigningKey" : "",
44-
// "EncryptionKey" : ""
46+
// "EncryptionKey" : "",
47+
// "EncryptionKeySignature" : ""
4548
// }
4649

4750
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4851
class EnclaveData {
4952
protected:
50-
void SerializePrivateData(void);
51-
void SerializePublicData(void);
52-
5353
void DeserializeSealedData(const std::string& inSerializedEnclaveData);
5454

5555
tcf::crypto::sig::PublicKey public_signing_key_;
5656
tcf::crypto::sig::PrivateKey private_signing_key_;
5757
tcf::crypto::pkenc::PublicKey public_encryption_key_;
5858
tcf::crypto::pkenc::PrivateKey private_encryption_key_;
59+
std::string encryption_key_signature_;
5960

6061
std::string serialized_private_data_;
6162
std::string serialized_public_data_;
@@ -65,13 +66,19 @@ class EnclaveData {
6566
// allocated storage for the sealed data. There are a number of ways
6667
// to do this; for now, the constant will be good enough.
6768
static const size_t cMaxSealedDataSize = 8192;
68-
static const size_t cMaxPublicDataSize = 4096;
69+
//static const size_t cMaxPublicDataSize = 4096;
70+
71+
// size of RSA key signature is 2048
72+
static const size_t cMaxPublicDataSize = 6144;
6973

7074
EnclaveData(void);
7175
EnclaveData(const uint8_t* inSealedData);
7276

7377
~EnclaveData(void);
7478

79+
void SerializePrivateData(void);
80+
void SerializePublicData(void);
81+
7582
ByteArray encrypt_message(const ByteArray& message) const {
7683
return public_encryption_key_.EncryptMessage(message);
7784
}
@@ -104,6 +111,18 @@ class EnclaveData {
104111

105112
size_t get_private_data_size(void) const { return serialized_private_data_.length(); }
106113

114+
void generate_new_encryption_key_pair(void) {
115+
private_encryption_key_.Generate();
116+
public_encryption_key_ = private_encryption_key_.GetPublicKey();
117+
}
118+
119+
void generate_encryption_key_signature() {
120+
std::string b64_pub_encr_key = public_encryption_key_.Serialize();
121+
ByteArray encr_key_sig_bytes = \
122+
private_signing_key_.SignMessage(StrToByteArray(b64_pub_encr_key));
123+
encryption_key_signature_ = base64_encode(encr_key_sig_bytes);
124+
}
125+
107126
size_t get_sealed_data_size(void) const {
108127
size_t sdsize = sgx_calc_sealed_data_size(0, get_private_data_size());
109128
assert(sdsize < cMaxSealedDataSize);

tc/sgx/trusted_worker_manager/enclave/signup.edl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ enclave {
3838
[out] size_t* outSealedEnclaveDataSize,
3939
[out] sgx_report_t* outEnclaveReport
4040
);
41+
public tcf_err_t ecall_RefreshEnclaveKey(
42+
[in, size=inSealedEnclaveDataSize] const uint8_t* inSealedEnclaveData,
43+
size_t inSealedEnclaveDataSize,
44+
[out, size=inAllocatedPublicEnclaveDataSize] char* outPublicEnclaveData,
45+
size_t inAllocatedPublicEnclaveDataSize,
46+
[out] size_t* outPublicEnclaveDataSize,
47+
[out, size=inAllocatedSealedEnclaveDataSize] uint8_t* outSealedEnclaveData,
48+
size_t inAllocatedSealedEnclaveDataSize,
49+
[out] size_t* outSealedEnclaveDataSize
50+
);
4151

4252
public tcf_err_t ecall_UnsealEnclaveData(
4353
[in, size=inSealedEnclaveDataSize] const uint8_t* inSealedEnclaveData,

0 commit comments

Comments
 (0)