├── Application ├── isv_enclave │ ├── isv_enclave.lds │ ├── isv_enclave.config.xml │ ├── isv_enclave.edl │ ├── isv_enclave_private.pem │ └── isv_enclave.cpp ├── isv_app │ └── isv_app.cpp └── Makefile ├── ServiceProvider ├── sample_libcrypto │ ├── libsample_libcrypto.so │ └── sample_libcrypto.h ├── isv_app │ ├── isv_app.cpp │ ├── VerificationManager.h │ └── VerificationManager.cpp ├── service_provider │ ├── ecp.h │ ├── remote_attestation_result.h │ ├── ServiceProvider.h │ ├── ias_ra.h │ ├── ecp.cpp │ ├── ias_ra.cpp │ └── ServiceProvider.cpp └── Makefile ├── Util ├── Base64.h ├── LogBase.cpp ├── UtilityFunctions.h ├── LogBase.h ├── Base64.cpp └── UtilityFunctions.cpp ├── Networking ├── NetworkManagerServer.h ├── NetworkManager.cpp ├── Session.h ├── NetworkManagerClient.h ├── Client.h ├── NetworkManagerServer.cpp ├── Server.h ├── Session.cpp ├── Network_def.h ├── NetworkManager.h ├── AbstractNetworkOps.h ├── NetworkManagerClient.cpp ├── Server.cpp ├── Client.cpp ├── remote_attestation_result.h └── AbstractNetworkOps.cpp ├── GeneralSettings.h ├── Enclave ├── Enclave.h └── Enclave.cpp ├── LICENSE ├── MessageHandler ├── MessageHandler.h └── MessageHandler.cpp ├── WebService ├── WebService.h └── WebService.cpp ├── README.md └── GoogleMessages └── Messages.proto /Application/isv_enclave/isv_enclave.lds: -------------------------------------------------------------------------------- 1 | enclave.so { 2 | global: 3 | g_global_data_sim; 4 | g_global_data; 5 | enclave_entry; 6 | local: 7 | *; 8 | }; 9 | -------------------------------------------------------------------------------- /ServiceProvider/sample_libcrypto/libsample_libcrypto.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svartkanin/linux-sgx-remoteattestation/HEAD/ServiceProvider/sample_libcrypto/libsample_libcrypto.so -------------------------------------------------------------------------------- /Util/Base64.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE64_H 2 | #define BASE64_H 3 | 4 | #include 5 | 6 | std::string base64_encode(unsigned char const* , unsigned int len); 7 | std::string base64_decode(std::string const& s); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /Application/isv_enclave/isv_enclave.config.xml: -------------------------------------------------------------------------------- 1 | 2 | 0 3 | 0 4 | 0x40000 5 | 0x100000 6 | 1 7 | 1 8 | 0 9 | 0 10 | 0xFFFFFFFF 11 | 12 | -------------------------------------------------------------------------------- /Networking/NetworkManagerServer.h: -------------------------------------------------------------------------------- 1 | #include "NetworkManager.h" 2 | 3 | class NetworkManagerServer : public NetworkManager { 4 | 5 | public: 6 | static NetworkManagerServer* getInstance(int port); 7 | void Init(); 8 | void connectCallbackHandler(CallbackHandler cb); 9 | void startService(); 10 | 11 | private: 12 | NetworkManagerServer(); 13 | 14 | private: 15 | static NetworkManagerServer* instance; 16 | Server *server = NULL; 17 | 18 | }; 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Networking/NetworkManager.cpp: -------------------------------------------------------------------------------- 1 | #include "NetworkManager.h" 2 | 3 | NetworkManager::NetworkManager() {} 4 | 5 | NetworkManager::~NetworkManager() {} 6 | 7 | 8 | void NetworkManager::setPort(int port) { 9 | this->port = port; 10 | } 11 | 12 | 13 | void NetworkManager::printMsg(bool send, const char* msg) { 14 | string s(msg); 15 | replace(s.begin(), s.end(), '\n', '-'); 16 | if (send) 17 | Log("Send msg: '%s'", s); 18 | else 19 | Log("Received msg: '%s'", s); 20 | } 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Networking/Session.h: -------------------------------------------------------------------------------- 1 | #ifndef SESSION_H 2 | #define SESSION_H 3 | 4 | #include "AbstractNetworkOps.h" 5 | 6 | using namespace std; 7 | 8 | class Session : public AbstractNetworkOps { 9 | 10 | typedef boost::asio::ssl::stream ssl_socket; 11 | 12 | public: 13 | Session(boost::asio::io_service& io_service, boost::asio::ssl::context& context); 14 | virtual ~Session(); 15 | void start(); 16 | void handle_handshake(const boost::system::error_code& error); 17 | 18 | }; 19 | 20 | 21 | #endif 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Networking/NetworkManagerClient.h: -------------------------------------------------------------------------------- 1 | #include "NetworkManager.h" 2 | 3 | class NetworkManagerClient : public NetworkManager { 4 | 5 | public: 6 | static NetworkManagerClient* getInstance(int port, std::string host = "localhost"); 7 | void Init(); 8 | void connectCallbackHandler(CallbackHandler cb); 9 | void startService(); 10 | void setHost(std::string host); 11 | 12 | private: 13 | NetworkManagerClient(); 14 | 15 | private: 16 | static NetworkManagerClient* instance; 17 | std::string host; 18 | Client *client = NULL; 19 | }; 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Application/isv_app/isv_app.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "LogBase.h" 5 | 6 | using namespace util; 7 | 8 | #include "MessageHandler.h" 9 | 10 | int Main(int argc, char* argv[]) { 11 | LogBase::Inst(); 12 | 13 | int ret = 0; 14 | 15 | MessageHandler msg; 16 | msg.init(); 17 | msg.start(); 18 | 19 | return ret; 20 | } 21 | 22 | 23 | int main( int argc, char **argv ) { 24 | try { 25 | return Main(argc, argv); 26 | } catch (std::exception& e) { 27 | Log("exception: %s", e.what()); 28 | } catch (...) { 29 | Log("unexpected exception") ; 30 | } 31 | 32 | return -1; 33 | } 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /GeneralSettings.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERALSETTINGS_H 2 | #define GENERALSETTINGS_H 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | namespace Settings { 9 | static int rh_port = 22222; 10 | static string rh_host = "localhost"; 11 | 12 | static string server_crt = ""; //certificate for the HTTPS connection between the SP and the App 13 | static string server_key = ""; //private key for the HTTPS connection 14 | 15 | static string spid = ""; //SPID provided by Intel after registration for the IAS service 16 | static const char *ias_crt = ""; //location of the certificate send to Intel when registring for the IAS 17 | static string ias_url = "https://test-as.sgx.trustedservices.intel.com:443/attestation/sgx/v1/"; 18 | } 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /Networking/Client.h: -------------------------------------------------------------------------------- 1 | #ifndef CLIENT_H 2 | #define CLIENT_H 3 | 4 | #include "AbstractNetworkOps.h" 5 | 6 | using namespace std; 7 | 8 | class Client : public AbstractNetworkOps { 9 | 10 | public: 11 | Client(boost::asio::io_service& io_service, boost::asio::ssl::context& context, boost::asio::ip::tcp::resolver::iterator endpoint_iterator); 12 | 13 | virtual ~Client(); 14 | bool verify_certificate(bool preverified, boost::asio::ssl::verify_context& ctx); 15 | void handle_connect(const boost::system::error_code& error); 16 | void handle_handshake(const boost::system::error_code& error); 17 | 18 | void startConnection(); 19 | 20 | private: 21 | boost::asio::ip::tcp::resolver::iterator endpoint_iterator; 22 | 23 | }; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /ServiceProvider/isv_app/isv_app.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "LogBase.h" 5 | #include "NetworkManager.h" 6 | #include "VerificationManager.h" 7 | #include "UtilityFunctions.h" 8 | 9 | using namespace util; 10 | 11 | int Main(int argc, char *argv[]) { 12 | LogBase::Inst(); 13 | 14 | int ret = 0; 15 | 16 | VerificationManager *vm = VerificationManager::getInstance(); 17 | vm->init(); 18 | vm->start(); 19 | 20 | return ret; 21 | } 22 | 23 | 24 | int main( int argc, char **argv ) { 25 | try { 26 | int ret = Main(argc, argv); 27 | return ret; 28 | } catch (std::exception & e) { 29 | Log("exception: %s", e.what()); 30 | } catch (...) { 31 | Log("unexpected exception"); 32 | } 33 | 34 | return -1; 35 | } 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Networking/NetworkManagerServer.cpp: -------------------------------------------------------------------------------- 1 | #include "NetworkManagerServer.h" 2 | 3 | NetworkManagerServer* NetworkManagerServer::instance = NULL; 4 | 5 | NetworkManagerServer::NetworkManagerServer() {} 6 | 7 | 8 | void NetworkManagerServer::Init() { 9 | this->server = new Server(this->io_service, this->port); 10 | } 11 | 12 | 13 | NetworkManagerServer* NetworkManagerServer::getInstance(int port) { 14 | if (instance == NULL) { 15 | instance = new NetworkManagerServer(); 16 | instance->setPort(port); 17 | } 18 | 19 | return instance; 20 | } 21 | 22 | 23 | void NetworkManagerServer::startService() { 24 | this->server->start_accept(); 25 | this->io_service.run(); 26 | } 27 | 28 | 29 | void NetworkManagerServer::connectCallbackHandler(CallbackHandler cb) { 30 | this->server->connectCallbackHandler(cb); 31 | } 32 | 33 | 34 | -------------------------------------------------------------------------------- /Networking/Server.h: -------------------------------------------------------------------------------- 1 | #ifndef SERVER_H 2 | #define SERVER_H 3 | 4 | #include "Session.h" 5 | #include "LogBase.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | class Server { 15 | 16 | typedef boost::asio::ssl::stream ssl_socket; 17 | 18 | public: 19 | Server(boost::asio::io_service& io_service, int port); 20 | virtual ~Server(); 21 | std::string get_password() const; 22 | void handle_accept(Session* new_session, const boost::system::error_code& error); 23 | void start_accept(); 24 | void connectCallbackHandler(CallbackHandler cb); 25 | 26 | private: 27 | boost::asio::io_service& io_service_; 28 | boost::asio::ip::tcp::acceptor acceptor_; 29 | boost::asio::ssl::context context_; 30 | CallbackHandler callback_handler; 31 | }; 32 | 33 | 34 | #endif 35 | 36 | 37 | -------------------------------------------------------------------------------- /Networking/Session.cpp: -------------------------------------------------------------------------------- 1 | #include "Session.h" 2 | 3 | #include 4 | 5 | using namespace util; 6 | 7 | Session::Session(boost::asio::io_service& io_service, boost::asio::ssl::context& context) : AbstractNetworkOps(io_service, context) {} 8 | 9 | Session::~Session() {} 10 | 11 | 12 | void Session::start() { 13 | Log("Connection from %s", socket().remote_endpoint().address().to_string()); 14 | 15 | socket_.async_handshake(boost::asio::ssl::stream_base::server, 16 | boost::bind(&Session::handle_handshake, this, 17 | boost::asio::placeholders::error)); 18 | } 19 | 20 | 21 | void Session::handle_handshake(const boost::system::error_code& error) { 22 | if (!error) { 23 | Log("Handshake successful"); 24 | this->read(); 25 | } else { 26 | Log("Handshake was not successful: %s", error.message(), log::error); 27 | delete this; 28 | } 29 | } 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Enclave/Enclave.h: -------------------------------------------------------------------------------- 1 | #ifndef ENCLAVE_H 2 | #define ENCLAVE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "LogBase.h" 10 | #include "UtilityFunctions.h" 11 | #include "isv_enclave_u.h" 12 | 13 | // Needed to call untrusted key exchange library APIs, i.e. sgx_ra_proc_msg2. 14 | #include "sgx_ukey_exchange.h" 15 | 16 | // Needed to query extended epid group id. 17 | #include "sgx_uae_service.h" 18 | 19 | class Enclave { 20 | 21 | public: 22 | static Enclave* getInstance(); 23 | virtual ~Enclave(); 24 | sgx_status_t createEnclave(); 25 | sgx_enclave_id_t getID(); 26 | sgx_status_t getStatus(); 27 | sgx_ra_context_t getContext(); 28 | 29 | private: 30 | Enclave(); 31 | static Enclave *instance; 32 | const char *enclave_path = "isv_enclave.signed.so"; 33 | sgx_enclave_id_t enclave_id; 34 | sgx_status_t status; 35 | sgx_ra_context_t context; 36 | }; 37 | 38 | #endif 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Networking/Network_def.h: -------------------------------------------------------------------------------- 1 | #ifndef NETWORK_DEF_H 2 | #define NETWORK_DEF_H 3 | 4 | #define MAX_VERIFICATION_RESULT 2 5 | 6 | typedef enum _ra_msg_types { 7 | RA_MSG0, 8 | RA_MSG1, 9 | RA_MSG2, 10 | RA_MSG3, 11 | RA_ATT_RESULT, 12 | RA_VERIFICATION, 13 | RA_APP_ATT_OK 14 | } ra_msg_types; 15 | 16 | 17 | typedef enum _ra_msg { 18 | TYPE_OK, 19 | TYPE_TERMINATE 20 | } ra_msg; 21 | 22 | 23 | #pragma pack(1) 24 | typedef struct _ra_samp_request_header_t { 25 | uint8_t type; /* set to one of ra_msg_type_t*/ 26 | uint32_t size; /*size of request body*/ 27 | uint8_t align[3]; 28 | uint8_t body[]; 29 | } ra_samp_request_header_t; 30 | 31 | typedef struct _ra_samp_response_header_t { 32 | uint8_t type; /* set to one of ra_msg_type_t*/ 33 | uint8_t status[2]; 34 | uint32_t size; /*size of the response body*/ 35 | uint8_t align[1]; 36 | uint8_t body[]; 37 | } ra_samp_response_header_t; 38 | 39 | #pragma pack() 40 | 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /Application/isv_enclave/isv_enclave.edl: -------------------------------------------------------------------------------- 1 | enclave { 2 | from "sgx_tkey_exchange.edl" import *; 3 | 4 | include "sgx_key_exchange.h" 5 | include "sgx_trts.h" 6 | 7 | trusted { 8 | public sgx_status_t enclave_init_ra(int b_pse, [out] sgx_ra_context_t *p_context); 9 | 10 | public sgx_status_t enclave_ra_close(sgx_ra_context_t context); 11 | 12 | public sgx_status_t verify_att_result_mac(sgx_ra_context_t context, 13 | [in,size=message_size] uint8_t* message, 14 | size_t message_size, 15 | [in,size=mac_size] uint8_t* mac, 16 | size_t mac_size); 17 | 18 | public sgx_status_t verify_secret_data(sgx_ra_context_t context, 19 | [in,size=secret_size] uint8_t* p_secret, 20 | uint32_t secret_size, 21 | [in,count=16] uint8_t* gcm_mac, 22 | uint32_t max_verification_length, 23 | [out, count=16] uint8_t *p_ret); 24 | }; 25 | 26 | }; 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Blackrabbit 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ServiceProvider/isv_app/VerificationManager.h: -------------------------------------------------------------------------------- 1 | #ifndef VERIFICATIONMANAGER_H 2 | #define VERIFICATIONMANAGER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "ServiceProvider.h" 10 | #include "NetworkManagerClient.h" 11 | #include "LogBase.h" 12 | #include "Messages.pb.h" 13 | #include "WebService.h" 14 | 15 | using namespace std; 16 | 17 | class VerificationManager { 18 | 19 | public: 20 | static VerificationManager* getInstance(); 21 | virtual ~VerificationManager(); 22 | int init(); 23 | vector incomingHandler(string v, int type); 24 | void start(); 25 | 26 | private: 27 | VerificationManager(); 28 | string prepareVerificationRequest(); 29 | string handleMSG0(Messages::MessageMsg0 m); 30 | string handleMSG1(Messages::MessageMSG1 msg); 31 | string handleMSG3(Messages::MessageMSG3 msg); 32 | string createInitMsg(int type, string msg); 33 | string handleAppAttOk(); 34 | 35 | private: 36 | static VerificationManager* instance; 37 | NetworkManagerClient *nm = NULL; 38 | ServiceProvider *sp = NULL; 39 | WebService *ws = NULL; 40 | }; 41 | 42 | #endif 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Networking/NetworkManager.h: -------------------------------------------------------------------------------- 1 | #ifndef NETWORKMANAGER_H 2 | #define NETWORKMANAGER_H 3 | 4 | #include "Server.h" 5 | #include "Client.h" 6 | #include "LogBase.h" 7 | #include "Network_def.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | using namespace std; 18 | using namespace util; 19 | 20 | class NetworkManager { 21 | 22 | typedef boost::asio::ssl::stream ssl_socket; 23 | 24 | public: 25 | NetworkManager(); 26 | virtual ~NetworkManager(); 27 | void sendMsg(); 28 | void Init(); 29 | void setPort(int port); 30 | void printMsg(bool send, const char* msg); 31 | 32 | template 33 | string serialize(T msg) { 34 | string s; 35 | if (msg.SerializeToString(&s)) { 36 | Log("Serialization successful"); 37 | return s; 38 | } else { 39 | Log("Serialization failed", log::error); 40 | return ""; 41 | } 42 | } 43 | 44 | public: 45 | boost::asio::io_service io_service; 46 | int port; 47 | }; 48 | 49 | 50 | #endif 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /Networking/AbstractNetworkOps.h: -------------------------------------------------------------------------------- 1 | #ifndef ABSTRACTNETWORKOPS_H 2 | #define ABSTRACTNETWORKOPS_H 3 | 4 | #include "LogBase.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | using namespace std; 19 | 20 | typedef function(string, int)> CallbackHandler; 21 | 22 | class AbstractNetworkOps { 23 | 24 | typedef boost::asio::ssl::stream ssl_socket; 25 | 26 | public: 27 | AbstractNetworkOps(); 28 | AbstractNetworkOps(boost::asio::io_service& io_service, boost::asio::ssl::context& context); 29 | virtual ~AbstractNetworkOps(); 30 | ssl_socket::lowest_layer_type& socket(); 31 | void setCallbackHandler(CallbackHandler cb); 32 | 33 | protected: 34 | ssl_socket socket_; 35 | enum { max_length = 1024 }; 36 | CallbackHandler callback_handler = NULL; 37 | 38 | protected: 39 | void read(); 40 | void send(vector); 41 | void process_read(char* buffer, int size, int type); 42 | 43 | private: 44 | void saveCloseSocket(); 45 | 46 | }; 47 | 48 | 49 | #endif 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Networking/NetworkManagerClient.cpp: -------------------------------------------------------------------------------- 1 | #include "NetworkManagerClient.h" 2 | #include "../GeneralSettings.h" 3 | 4 | NetworkManagerClient* NetworkManagerClient::instance = NULL; 5 | 6 | NetworkManagerClient::NetworkManagerClient() {} 7 | 8 | 9 | void NetworkManagerClient::Init() { 10 | if (client) { 11 | delete client; 12 | client = NULL; 13 | } 14 | 15 | boost::asio::ip::tcp::resolver resolver(this->io_service); 16 | boost::asio::ip::tcp::resolver::query query(this->host, std::to_string(this->port).c_str()); 17 | boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); 18 | 19 | boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23); 20 | ctx.load_verify_file(Settings::server_crt); 21 | 22 | this->client = new Client(io_service, ctx, iterator); 23 | } 24 | 25 | 26 | NetworkManagerClient* NetworkManagerClient::getInstance(int port, std::string host) { 27 | if (instance == NULL) { 28 | instance = new NetworkManagerClient(); 29 | instance->setPort(port); 30 | instance->setHost(host); 31 | } 32 | 33 | return instance; 34 | } 35 | 36 | 37 | void NetworkManagerClient::startService() { 38 | this->client->startConnection(); 39 | } 40 | 41 | 42 | void NetworkManagerClient::setHost(std::string host) { 43 | this->host = host; 44 | } 45 | 46 | 47 | void NetworkManagerClient::connectCallbackHandler(CallbackHandler cb) { 48 | this->client->setCallbackHandler(cb); 49 | } 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /Networking/Server.cpp: -------------------------------------------------------------------------------- 1 | #include "Server.h" 2 | #include "../GeneralSettings.h" 3 | 4 | using namespace util; 5 | 6 | Server::Server(boost::asio::io_service& io_service, int port) : io_service_(io_service), acceptor_(io_service, 7 | boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)), 8 | context_(boost::asio::ssl::context::sslv23) { 9 | 10 | this->context_.set_options(boost::asio::ssl::context::default_workarounds 11 | | boost::asio::ssl::context::no_sslv2 12 | | boost::asio::ssl::context::single_dh_use); 13 | 14 | this->context_.use_certificate_chain_file(Settings::server_crt); 15 | this->context_.use_private_key_file(Settings::server_key, boost::asio::ssl::context::pem); 16 | 17 | Log("Certificate \"" + Settings::server_crt + "\" set"); 18 | Log("Server running on port: %d", port); 19 | } 20 | 21 | 22 | Server::~Server() {} 23 | 24 | 25 | void Server::start_accept() { 26 | Session *new_session = new Session(io_service_, context_); 27 | new_session->setCallbackHandler(this->callback_handler); 28 | acceptor_.async_accept(new_session->socket(), boost::bind(&Server::handle_accept, this, new_session, boost::asio::placeholders::error)); 29 | } 30 | 31 | 32 | void Server::handle_accept(Session* new_session, const boost::system::error_code& error) { 33 | if (!error) { 34 | Log("New accept request, starting new session"); 35 | new_session->start(); 36 | } else { 37 | delete new_session; 38 | } 39 | 40 | start_accept(); 41 | } 42 | 43 | void Server::connectCallbackHandler(CallbackHandler cb) { 44 | this->callback_handler = cb; 45 | } 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /MessageHandler/MessageHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef MESSAGEHANDLER_H 2 | #define MESSAGEHANDLER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "Enclave.h" 12 | #include "NetworkManagerServer.h" 13 | #include "Messages.pb.h" 14 | #include "UtilityFunctions.h" 15 | #include "remote_attestation_result.h" 16 | #include "LogBase.h" 17 | #include "../GeneralSettings.h" 18 | 19 | using namespace std; 20 | using namespace util; 21 | 22 | class MessageHandler { 23 | 24 | public: 25 | MessageHandler(int port = Settings::rh_port); 26 | virtual ~MessageHandler(); 27 | 28 | sgx_ra_msg3_t* getMSG3(); 29 | int init(); 30 | void start(); 31 | vector incomingHandler(string v, int type); 32 | 33 | private: 34 | sgx_status_t initEnclave(); 35 | uint32_t getExtendedEPID_GID(uint32_t *extended_epid_group_id); 36 | sgx_status_t getEnclaveStatus(); 37 | 38 | void assembleAttestationMSG(Messages::AttestationMessage msg, ra_samp_response_header_t **pp_att_msg); 39 | string handleAttestationResult(Messages::AttestationMessage msg); 40 | void assembleMSG2(Messages::MessageMSG2 msg, sgx_ra_msg2_t **pp_msg2); 41 | string handleMSG2(Messages::MessageMSG2 msg); 42 | string handleMSG0(Messages::MessageMsg0 msg); 43 | string generateMSG1(); 44 | string handleVerification(); 45 | string generateMSG0(); 46 | string createInitMsg(int type, string msg); 47 | 48 | protected: 49 | Enclave *enclave = NULL; 50 | 51 | private: 52 | int busy_retry_time = 4; 53 | NetworkManagerServer *nm = NULL; 54 | 55 | }; 56 | 57 | #endif 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /WebService/WebService.h: -------------------------------------------------------------------------------- 1 | #ifndef WEBSERVICE_H 2 | #define WEBSERVICE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "LogBase.h" 14 | #include "UtilityFunctions.h" 15 | 16 | using namespace std; 17 | using namespace util; 18 | 19 | enum IAS { 20 | sigrl, 21 | report 22 | }; 23 | 24 | struct attestation_verification_report_t { 25 | string report_id; 26 | string isv_enclave_quote_status; 27 | string timestamp; 28 | }; 29 | 30 | struct attestation_evidence_payload_t { 31 | string isv_enclave_quote; 32 | }; 33 | 34 | struct ias_response_header_t { 35 | int response_status; 36 | int content_length; 37 | std::string request_id; 38 | }; 39 | 40 | struct ias_response_container_t { 41 | char *p_response; 42 | size_t size; 43 | }; 44 | 45 | static int REQUEST_ID_MAX_LEN = 32; 46 | static vector> retrieved_sigrl; 47 | 48 | class WebService { 49 | 50 | public: 51 | static WebService* getInstance(); 52 | virtual ~WebService(); 53 | void init(); 54 | bool getSigRL(string gid, string *sigrl); 55 | bool verifyQuote(uint8_t *quote, uint8_t *pseManifest, uint8_t *nonce, vector> *result); 56 | 57 | private: 58 | WebService(); 59 | bool sendToIAS(string url, IAS type, string payload, 60 | struct curl_slist *headers, 61 | ias_response_container_t *ias_response_container, 62 | ias_response_header_t *response_header); 63 | 64 | string createJSONforIAS(uint8_t *quote, uint8_t *pseManifest, uint8_t *nonce); 65 | vector> parseJSONfromIAS(string json); 66 | 67 | private: 68 | static WebService* instance; 69 | CURL *curl; 70 | }; 71 | 72 | #endif 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /ServiceProvider/service_provider/ecp.h: -------------------------------------------------------------------------------- 1 | #ifndef _ECP_H 2 | #define _ECP_H 3 | 4 | #include 5 | #include 6 | 7 | #include "remote_attestation_result.h" 8 | 9 | #ifndef SAMPLE_FEBITSIZE 10 | #define SAMPLE_FEBITSIZE 256 11 | #endif 12 | 13 | #define SAMPLE_ECP_KEY_SIZE (SAMPLE_FEBITSIZE/8) 14 | 15 | typedef struct sample_ec_priv_t { 16 | uint8_t r[SAMPLE_ECP_KEY_SIZE]; 17 | } sample_ec_priv_t; 18 | 19 | typedef struct sample_ec_dh_shared_t { 20 | uint8_t s[SAMPLE_ECP_KEY_SIZE]; 21 | } sample_ec_dh_shared_t; 22 | 23 | typedef uint8_t sample_ec_key_128bit_t[16]; 24 | 25 | #define SAMPLE_EC_MAC_SIZE 16 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | 32 | #ifndef _ERRNO_T_DEFINED 33 | #define _ERRNO_T_DEFINED 34 | typedef int errno_t; 35 | #endif 36 | errno_t memcpy_s(void *dest, size_t numberOfElements, const void *src, 37 | size_t count); 38 | 39 | 40 | #ifdef SUPPLIED_KEY_DERIVATION 41 | 42 | typedef enum _sample_derive_key_type_t { 43 | SAMPLE_DERIVE_KEY_SMK_SK = 0, 44 | SAMPLE_DERIVE_KEY_MK_VK, 45 | } sample_derive_key_type_t; 46 | 47 | bool derive_key( 48 | const sample_ec_dh_shared_t *p_shared_key, 49 | uint8_t key_id, 50 | sample_ec_key_128bit_t *first_derived_key, 51 | sample_ec_key_128bit_t *second_derived_key); 52 | 53 | #else 54 | 55 | typedef enum _sample_derive_key_type_t { 56 | SAMPLE_DERIVE_KEY_SMK = 0, 57 | SAMPLE_DERIVE_KEY_SK, 58 | SAMPLE_DERIVE_KEY_MK, 59 | SAMPLE_DERIVE_KEY_VK, 60 | } sample_derive_key_type_t; 61 | 62 | bool derive_key( 63 | const sample_ec_dh_shared_t *p_shared_key, 64 | uint8_t key_id, 65 | sample_ec_key_128bit_t *derived_key); 66 | 67 | #endif 68 | 69 | bool verify_cmac128( 70 | sample_ec_key_128bit_t mac_key, 71 | const uint8_t *p_data_buf, 72 | uint32_t buf_size, 73 | const uint8_t *p_mac_buf); 74 | #ifdef __cplusplus 75 | } 76 | #endif 77 | 78 | #endif 79 | 80 | -------------------------------------------------------------------------------- /Util/LogBase.cpp: -------------------------------------------------------------------------------- 1 | #include "LogBase.h" 2 | #include 3 | 4 | namespace util { 5 | 6 | LogBase* LogBase::instance = NULL; 7 | 8 | LogBase* LogBase::Inst() { 9 | if (instance == NULL) { 10 | instance = new LogBase(); 11 | } 12 | 13 | return instance; 14 | } 15 | 16 | 17 | LogBase::LogBase() { 18 | m_enabled[log::verbose] = false; 19 | m_enabled[log::info] = true; 20 | m_enabled[log::warning] = true; 21 | m_enabled[log::error] = true; 22 | m_enabled[log::timer] = false; 23 | 24 | this->appender = new log4cpp::OstreamAppender("console", &std::cout); 25 | this->appender->setLayout(new log4cpp::BasicLayout()); 26 | 27 | root.setPriority(log4cpp::Priority::INFO); 28 | root.addAppender(this->appender); 29 | } 30 | 31 | 32 | LogBase::~LogBase() {} 33 | 34 | 35 | void LogBase::Log(const log::Fmt& msg, log::Severity s) { 36 | if (IsEnabled(s) && !IsEnabled(log::timer)) { 37 | switch (s) { 38 | case log::info: 39 | root.info(msg.str()); 40 | break; 41 | case log::error: 42 | root.error(msg.str()); 43 | break; 44 | case log::warning: 45 | root.warn(msg.str()); 46 | break; 47 | } 48 | } 49 | } 50 | 51 | 52 | bool LogBase::Enable(log::Severity s, bool enable) { 53 | bool prev = m_enabled[s]; 54 | m_enabled[s] = enable; 55 | 56 | return prev; 57 | } 58 | 59 | 60 | void LogBase::DisableAll(bool b) { 61 | m_enabled[log::verbose] = b; 62 | m_enabled[log::info] = b; 63 | m_enabled[log::warning] = b; 64 | m_enabled[log::error] = b; 65 | m_enabled[log::timer] = b; 66 | } 67 | 68 | 69 | bool LogBase::IsEnabled( log::Severity s ) const { 70 | return m_enabled[s]; 71 | } 72 | 73 | 74 | void Log(const string& str, log::Severity s) { 75 | LogBase::Inst()->Log(log::Fmt(str), s); 76 | } 77 | 78 | 79 | void DisableAllLogs(bool b) { 80 | LogBase::Inst()->DisableAll(b); 81 | } 82 | 83 | 84 | 85 | } 86 | -------------------------------------------------------------------------------- /Networking/Client.cpp: -------------------------------------------------------------------------------- 1 | #include "Client.h" 2 | #include "LogBase.h" 3 | #include "Network_def.h" 4 | #include "Messages.pb.h" 5 | 6 | #include 7 | 8 | using namespace util; 9 | 10 | Client::Client(boost::asio::io_service& io_service, 11 | boost::asio::ssl::context& context, 12 | boost::asio::ip::tcp::resolver::iterator endpoint_iterator) : AbstractNetworkOps(io_service, context) { 13 | socket_.set_verify_mode(boost::asio::ssl::verify_peer); 14 | socket_.set_verify_callback(boost::bind(&Client::verify_certificate, this, _1, _2)); 15 | 16 | this->endpoint_iterator = endpoint_iterator; 17 | } 18 | 19 | Client::~Client() {} 20 | 21 | 22 | void Client::startConnection() { 23 | Log("Start connecting..."); 24 | 25 | boost::system::error_code ec; 26 | boost::asio::connect(socket_.lowest_layer(), this->endpoint_iterator, ec); 27 | 28 | handle_connect(ec); 29 | } 30 | 31 | 32 | bool Client::verify_certificate(bool preverified, boost::asio::ssl::verify_context& ctx) { 33 | char subject_name[256]; 34 | X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); 35 | X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256); 36 | 37 | Log("Verifying certificate: %s", subject_name); 38 | 39 | return preverified; 40 | } 41 | 42 | 43 | void Client::handle_connect(const boost::system::error_code &error) { 44 | if (!error) { 45 | Log("Connection established"); 46 | 47 | boost::system::error_code ec; 48 | socket_.handshake(boost::asio::ssl::stream_base::client, ec); 49 | 50 | handle_handshake(ec); 51 | } else { 52 | Log("Connect failed: %s", error.message(), log::error); 53 | } 54 | } 55 | 56 | 57 | void Client::handle_handshake(const boost::system::error_code& error) { 58 | if (!error) { 59 | Log("Handshake successful"); 60 | 61 | auto ret = this->callback_handler("", -1); 62 | send(ret); 63 | } else { 64 | Log("Handshake failed: %s", error.message(), log::error); 65 | } 66 | } 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linux SGX remote attestation 2 | Example of a remote attestation with Intel's SGX including the communication with IAS. 3 | 4 | The code requires the installation of Intel SGX [here](https://github.com/01org/linux-sgx) and 5 | the SGX driver [here](https://github.com/01org/linux-sgx-driver). Furthermore, also a developer account 6 | for the usage of IAS has be registered [Deverloper account](https://software.intel.com/en-us/sgx). 7 | After the registration with a certificate (can be self-signed for development purposes), Intel will 8 | respond with a SPID which is needed to communicate with IAS. 9 | 10 | The code consists of two separate programs, the ServiceProvider and the Application. 11 | The message exchange over the network is performed using Google Protocol Buffers. 12 | 13 | ## Installation 14 | 15 | Before running the code, some settings have to be set in the ```GeneralSettings.h``` file: 16 | * The application port and IP 17 | * A server certificate and private key are required for the SSL communication between the SP and the Application (which can be self-signed)
18 | e.g. ```openssl req -x509 -nodes -newkey rsa:4096 -keyout server.key -out server.crt -days 365``` 19 | * The SPID provided by Intel when registering for the developer account 20 | * The certificate sent to Intel when registering for the developer account 21 | * IAS Rest API url (should stay the same) 22 | 23 | To be able to run the above code some external libraries are needed: 24 | 25 | * Google Protocol Buffers (should already be installed with the SGX SDK package) otherwise install ```libprotobuf-dev```, ```libprotobuf-c0-dev``` and ```protobuf-compiler``` 26 | 27 | All other required libraries can be installed with the following command 28 | ```sudo apt-get install libboost-thread-dev libboost-system-dev curl libcurl4-openssl-dev libssl-dev liblog4cpp5-dev libjsoncpp-dev``` 29 | 30 | 31 | After the installation of those dependencies, the code can be compiled with the following commands:
32 | ```cd ServiceProvider```
33 | ```make```
34 | ```cd ../Application```
35 | ```make SGX_MODE=HW SGX_PRERELEASE=1``` 36 | -------------------------------------------------------------------------------- /Util/UtilityFunctions.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILITY_FUNCTIONS_H 2 | #define UTILITY_FUNCTIONS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | // #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "LogBase.h" 24 | #include "sgx_urts.h" 25 | #include "Base64.h" 26 | 27 | using namespace std; 28 | using namespace boost::archive::iterators; 29 | using boost::lexical_cast; 30 | using boost::uuids::uuid; 31 | using boost::uuids::random_generator; 32 | 33 | #define FILE_UUID_LENGTH 32 34 | 35 | typedef struct _sgx_errlist_t { 36 | sgx_status_t err; 37 | const char *msg; 38 | const char *sug; /* Suggestion */ 39 | } sgx_errlist_t; 40 | 41 | void print_error_message(sgx_status_t ret); 42 | 43 | void SafeFree(void *ptr); 44 | 45 | string GetRandomString(); 46 | 47 | string ByteArrayToString(const uint8_t *arr, int size); 48 | string ByteArrayToStringNoFill(const uint8_t *arr, int size); 49 | int StringToByteArray(string str, uint8_t **arr); 50 | string ByteArrayToNoHexString(const uint8_t *arr, int size); 51 | string UIntToString(uint32_t *arr, int size); 52 | int HexStringToByteArray(string str, uint8_t **arr); 53 | 54 | int ReadFileToBuffer(string filePath, uint8_t **content); 55 | int ReadFileToBuffer(string filePath, char **content); 56 | int SaveBufferToFile(string filePath, string content); 57 | int RemoveFile(string filePath); 58 | 59 | string Base64encode(const string val); 60 | string Base64decode(const string val); 61 | string Base64encodeUint8(uint8_t *val, uint32_t len); 62 | 63 | #endif 64 | 65 | 66 | -------------------------------------------------------------------------------- /GoogleMessages/Messages.proto: -------------------------------------------------------------------------------- 1 | package Messages; 2 | 3 | message InitialMessage { 4 | required uint32 type = 1; 5 | optional uint32 size = 2; 6 | } 7 | 8 | message MessageMsg0 { 9 | required uint32 type = 1; 10 | required uint32 epid = 2; 11 | optional uint32 status = 3; 12 | } 13 | 14 | message MessageMSG1 { 15 | required uint32 type = 1; 16 | repeated uint32 GaX = 2 [packed=true]; 17 | repeated uint32 GaY = 3 [packed=true]; 18 | repeated uint32 GID = 4 [packed=true]; 19 | } 20 | 21 | message MessageMSG2 { 22 | required uint32 type = 1; 23 | optional uint32 size = 2; 24 | repeated uint32 public_key_gx = 3 [packed=true]; 25 | repeated uint32 public_key_gy = 4 [packed=true]; 26 | optional uint32 quote_type = 5; 27 | repeated uint32 spid = 6 [packed=true]; 28 | optional uint32 cmac_kdf_id = 7; 29 | repeated uint32 signature_x = 8 [packed=true]; 30 | repeated uint32 signature_y = 9 [packed=true]; 31 | repeated uint32 smac = 10 [packed=true]; 32 | optional uint32 size_sigrl = 11; 33 | repeated uint32 sigrl = 12 [packed=true]; 34 | } 35 | 36 | message MessageMSG3 { 37 | required uint32 type = 1; 38 | optional uint32 size = 2; 39 | repeated uint32 sgx_mac = 3 [packed=true]; 40 | repeated uint32 gax_msg3 = 4 [packed=true]; 41 | repeated uint32 gay_msg3 = 5 [packed=true]; 42 | repeated uint32 sec_property = 6 [packed=true]; 43 | repeated uint32 quote = 7 [packed=true]; 44 | } 45 | 46 | message AttestationMessage { 47 | required uint32 type = 1; 48 | required uint32 size = 2; 49 | 50 | optional uint32 epid_group_status = 3; 51 | optional uint32 tcb_evaluation_status = 4; 52 | optional uint32 pse_evaluation_status = 5; 53 | repeated uint32 latest_equivalent_tcb_psvn = 6 [packed=true]; 54 | repeated uint32 latest_pse_isvsvn = 7 [packed=true]; 55 | repeated uint32 latest_psda_svn = 8 [packed=true]; 56 | repeated uint32 performance_rekey_gid = 9 [packed=true]; 57 | repeated uint32 ec_sign256_x = 10 [packed=true]; 58 | repeated uint32 ec_sign256_y = 11 [packed=true]; 59 | repeated uint32 mac_smk = 12 [packed=true]; 60 | 61 | optional uint32 result_size = 13; 62 | repeated uint32 reserved = 14 [packed=true]; 63 | repeated uint32 payload_tag = 15 [packed=true]; 64 | repeated uint32 payload = 16 [packed=true]; 65 | } 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /Networking/remote_attestation_result.h: -------------------------------------------------------------------------------- 1 | #ifndef _REMOTE_ATTESTATION_RESULT_H_ 2 | #define _REMOTE_ATTESTATION_RESULT_H_ 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #define SAMPLE_MAC_SIZE 16 /* Message Authentication Code*/ 11 | /* - 16 bytes*/ 12 | typedef uint8_t sample_mac_t[SAMPLE_MAC_SIZE]; 13 | 14 | #ifndef SAMPLE_FEBITSIZE 15 | #define SAMPLE_FEBITSIZE 256 16 | #endif 17 | 18 | #define SAMPLE_NISTP256_KEY_SIZE (SAMPLE_FEBITSIZE/ 8 /sizeof(uint32_t)) 19 | 20 | typedef struct sample_ec_sign256_t { 21 | uint32_t x[SAMPLE_NISTP256_KEY_SIZE]; 22 | uint32_t y[SAMPLE_NISTP256_KEY_SIZE]; 23 | } sample_ec_sign256_t; 24 | 25 | #pragma pack(push,1) 26 | 27 | #define SAMPLE_SP_TAG_SIZE 16 28 | 29 | typedef struct sp_aes_gcm_data_t { 30 | uint32_t payload_size; /* 0: Size of the payload which is*/ 31 | /* encrypted*/ 32 | uint8_t reserved[12]; /* 4: Reserved bits*/ 33 | uint8_t payload_tag[SAMPLE_SP_TAG_SIZE]; 34 | /* 16: AES-GMAC of the plain text,*/ 35 | /* payload, and the sizes*/ 36 | uint8_t payload[]; /* 32: Ciphertext of the payload*/ 37 | /* followed by the plain text*/ 38 | } sp_aes_gcm_data_t; 39 | 40 | 41 | #define ISVSVN_SIZE 2 42 | #define PSDA_SVN_SIZE 4 43 | #define GID_SIZE 4 44 | #define PSVN_SIZE 18 45 | 46 | /* @TODO: Modify at production to use the values specified by an Production*/ 47 | /* attestation server API*/ 48 | typedef struct ias_platform_info_blob_t { 49 | uint8_t sample_epid_group_status; 50 | uint16_t sample_tcb_evaluation_status; 51 | uint16_t pse_evaluation_status; 52 | uint8_t latest_equivalent_tcb_psvn[PSVN_SIZE]; 53 | uint8_t latest_pse_isvsvn[ISVSVN_SIZE]; 54 | uint8_t latest_psda_svn[PSDA_SVN_SIZE]; 55 | uint8_t performance_rekey_gid[GID_SIZE]; 56 | sample_ec_sign256_t signature; 57 | } ias_platform_info_blob_t; 58 | 59 | 60 | typedef struct sample_ra_att_result_msg_t { 61 | ias_platform_info_blob_t platform_info_blob; 62 | sample_mac_t mac; /* mac_smk(attestation_status)*/ 63 | sp_aes_gcm_data_t secret; 64 | } sample_ra_att_result_msg_t; 65 | 66 | #pragma pack(pop) 67 | 68 | #ifdef __cplusplus 69 | } 70 | #endif 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /ServiceProvider/service_provider/remote_attestation_result.h: -------------------------------------------------------------------------------- 1 | #ifndef _REMOTE_ATTESTATION_RESULT_H_ 2 | #define _REMOTE_ATTESTATION_RESULT_H_ 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #define SAMPLE_MAC_SIZE 16 /* Message Authentication Code*/ 11 | /* - 16 bytes*/ 12 | typedef uint8_t sample_mac_t[SAMPLE_MAC_SIZE]; 13 | 14 | #ifndef SAMPLE_FEBITSIZE 15 | #define SAMPLE_FEBITSIZE 256 16 | #endif 17 | 18 | #define SAMPLE_NISTP256_KEY_SIZE (SAMPLE_FEBITSIZE/ 8 /sizeof(uint32_t)) 19 | 20 | typedef struct sample_ec_sign256_t { 21 | uint32_t x[SAMPLE_NISTP256_KEY_SIZE]; 22 | uint32_t y[SAMPLE_NISTP256_KEY_SIZE]; 23 | } sample_ec_sign256_t; 24 | 25 | #pragma pack(push,1) 26 | 27 | #define SAMPLE_SP_TAG_SIZE 16 28 | 29 | typedef struct sp_aes_gcm_data_t { 30 | uint32_t payload_size; /* 0: Size of the payload which is*/ 31 | /* encrypted*/ 32 | uint8_t reserved[12]; /* 4: Reserved bits*/ 33 | uint8_t payload_tag[SAMPLE_SP_TAG_SIZE]; 34 | /* 16: AES-GMAC of the plain text,*/ 35 | /* payload, and the sizes*/ 36 | uint8_t payload[]; /* 32: Ciphertext of the payload*/ 37 | /* followed by the plain text*/ 38 | } sp_aes_gcm_data_t; 39 | 40 | 41 | #define ISVSVN_SIZE 2 42 | #define PSDA_SVN_SIZE 4 43 | #define GID_SIZE 4 44 | #define PSVN_SIZE 18 45 | 46 | /* @TODO: Modify at production to use the values specified by an Production*/ 47 | /* attestation server API*/ 48 | typedef struct ias_platform_info_blob_t { 49 | uint8_t sample_epid_group_status; 50 | uint16_t sample_tcb_evaluation_status; 51 | uint16_t pse_evaluation_status; 52 | uint8_t latest_equivalent_tcb_psvn[PSVN_SIZE]; 53 | uint8_t latest_pse_isvsvn[ISVSVN_SIZE]; 54 | uint8_t latest_psda_svn[PSDA_SVN_SIZE]; 55 | uint8_t performance_rekey_gid[GID_SIZE]; 56 | sample_ec_sign256_t signature; 57 | } ias_platform_info_blob_t; 58 | 59 | 60 | typedef struct sample_ra_att_result_msg_t { 61 | ias_platform_info_blob_t platform_info_blob; 62 | sample_mac_t mac; /* mac_smk(attestation_status)*/ 63 | sp_aes_gcm_data_t secret; 64 | } sample_ra_att_result_msg_t; 65 | 66 | #pragma pack(pop) 67 | 68 | #ifdef __cplusplus 69 | } 70 | #endif 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /ServiceProvider/service_provider/ServiceProvider.h: -------------------------------------------------------------------------------- 1 | #ifndef SERVICE_PROVIDER_H 2 | #define SERVICE_PROVIDER_H 3 | 4 | #include 5 | #include 6 | #include // std::reverse 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "Messages.pb.h" 15 | #include "UtilityFunctions.h" 16 | #include "LogBase.h" 17 | #include "Network_def.h" 18 | #include "WebService.h" 19 | 20 | #include "remote_attestation_result.h" 21 | #include "sgx_key_exchange.h" 22 | #include "ias_ra.h" 23 | 24 | using namespace std; 25 | 26 | #define DH_HALF_KEY_LEN 32 27 | #define DH_SHARED_KEY_LEN 32 28 | #define SAMPLE_SP_IV_SIZE 12 29 | 30 | 31 | enum sp_ra_msg_status_t { 32 | SP_OK, 33 | SP_UNSUPPORTED_EXTENDED_EPID_GROUP, 34 | SP_INTEGRITY_FAILED, 35 | SP_QUOTE_VERIFICATION_FAILED, 36 | SP_IAS_FAILED, 37 | SP_INTERNAL_ERROR, 38 | SP_PROTOCOL_ERROR, 39 | SP_QUOTE_VERSION_ERROR, 40 | SP_RETRIEVE_SIGRL_ERROR 41 | }; 42 | 43 | typedef struct _sp_db_item_t { 44 | sgx_ec256_public_t g_a; 45 | sgx_ec256_public_t g_b; 46 | sgx_ec_key_128bit_t vk_key; // Shared secret key for the REPORT_DATA 47 | sgx_ec_key_128bit_t mk_key; // Shared secret key for generating MAC's 48 | sgx_ec_key_128bit_t sk_key; // Shared secret key for encryption 49 | sgx_ec_key_128bit_t smk_key; // Used only for SIGMA protocol 50 | sample_ec_priv_t b; 51 | sgx_ps_sec_prop_desc_t ps_sec_prop; 52 | } sp_db_item_t; 53 | 54 | 55 | class ServiceProvider { 56 | 57 | public: 58 | ServiceProvider(WebService *ws); 59 | virtual ~ServiceProvider(); 60 | int sp_ra_proc_msg0_req(const uint32_t extended_epid_group_id); 61 | int sp_ra_proc_msg1_req(Messages::MessageMSG1 msg1, Messages::MessageMSG2 *msg2); 62 | int sp_ra_proc_msg3_req(Messages::MessageMSG3 msg, Messages::AttestationMessage *att_msg); 63 | sgx_ra_msg3_t* assembleMSG3(Messages::MessageMSG3 msg); 64 | int sp_ra_proc_app_att_hmac(Messages::SecretMessage *new_msg, string hmac_key, string hmac_key_filename); 65 | 66 | private: 67 | WebService *ws = NULL; 68 | bool g_is_sp_registered = false; 69 | uint32_t extended_epid_group_id; 70 | sp_db_item_t g_sp_db; 71 | const uint16_t AES_CMAC_KDF_ID = 0x0001; 72 | uint8_t validation_result[MAX_VERIFICATION_RESULT]; 73 | }; 74 | 75 | #endif 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /Application/isv_enclave/isv_enclave_private.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIG4wIBAAKCAYEA0MvI9NpdP4GEqCvtlJQv00OybzTXzxBhPu/257VYt9cYw/ph 3 | BN1WRyxBBcrZs15xmcvlb3xNmFGWs4w5oUgrFBNgi6g+CUOCsj0cM8xw7P/y3K0H 4 | XaZUf+T3CXCp8NvlkZHzfdWAFA5lGGR9g6kmuk7SojE3h87Zm1KjPU/PvAe+BaMU 5 | trlRr4gPNVnu19Vho60xwuswPxfl/pBFUIk7qWEUR3l2hiqWMeLgf3Ays/WSnkXA 6 | uijwPt5g0hxsgIlyDrI3jKbf0zkFB56jvPwSykfU8aw4Gkbo5qSZxUAKnwH2L8Uf 7 | yM6inBaaYtM79icRwsu45Yt6X0GAt7CSb/1TKBrnm5exmK1sug3YSQ/YuK1FYawU 8 | vIaDD0YfzOndTNVBewA+Hr5xNPvqGJoRKHuGbyu2lI9jrKYpVxQWsmx38wnxF6kE 9 | zX6N4m7KZiLeLpDdBVQtLuOzIdIE4wT3t/ckeqElxO/1Ut9bj765GcTTrYwMKHRw 10 | ukWIH7ZtHtAjj0KzAgEDAoIBgQCLMoX4kZN/q63Fcp5jDXU3gnb0zeU0tZYp9U9F 11 | I5B6j2XX/ECt6OQvctYD3JEiPvZmh+5KUt5li7nNCCZrhXINYkBdGtQGLQHMKL13 12 | 3aCd//c9yK+TxDhVQ09boHFLPUO2YUz+jlVitENlmFOtG28m3zcWy3paieZnjGzT 13 | iop9Wn6ubLh50OEfsAojkUnlOOvCc3aB8iAqD+6ptYOLBifGQLgvpk8EHGQhQer/ 14 | oCHNTmG+2SsmxfV/Pus2vZ2rBkrUbZU0hwrnvKOIPhnt3Qwtmx9xsC67jF+MpWko 15 | UisJXC27FAGz2gpIGMhBp35HEppwG9hhCuMQdK2g62bvweyr1tC4qOVdQrKvhksN 16 | r6CMjS9eSXvmWdF7lU4oxStN0V56/LICSIsLbggUaxTPKhAVEgfTSqwEJoQuFA3Q 17 | 4GmgTydPhcRH1L/lhbWJqZQm7V1Gt+5i5J6iATD32uNQQ2iZi5GsUhr+jZC+WlE5 18 | 6lS813cRNiaK52HIk62bG7IXOksCgcEA+6RxZhQ5GaCPYZNsk7TqxqsKopXKoYAr 19 | 2R4KWuexJTd+1kcNMk0ETX8OSgpY2cYL2uPFWmdutxPpLfpr8S2u92Da/Wxs70Ti 20 | QSb0426ybTmnS5L7nOnGOHiddXILhW175liAszTeoR7nQ6vpr9YjfcnrXiB8bKIm 21 | akft2DQoxrBPzEe9tA8gfkyDTsSG2j7kncSbvYRtkKcJOmmypotVU6uhRPSrSXCc 22 | J59uBQkg6Bk4CKA1mz8ctG07MluFY0/ZAoHBANRpZlfIFl39gFmuEER7lb80GySO 23 | J190LbqOca3dGOvAMsDgEAi6juJyX7ZNpbHFHj++LvmTtw9+kxhVDBcswS7304kt 24 | 7J2EfnGdctEZtXif1wiq30YWAp1tjRpQENKtt9wssmgcwgK39rZNiEHmStHGv3l+ 25 | 5TnKPKeuFCDnsLvi5lQYoK2wTYvZtsjf+Rnt7H17q90IV54pMjTS8BkGskCkKf2A 26 | IYuaZkqX0T3cM6ovoYYDAU6rWL5rrYPLEwkbawKBwQCnwvZEDXtmawpBDPMNI0cv 27 | HLHBuTHBAB07aVw8mnYYz6nkL14hiK2I/17cBuXmhAfnQoORmknPYptz/Ef2HnSk 28 | 6zyo8vNKLewrb03s9Hbze8TdDKe98S7QUGj49rJY86fu5asiIz8WFJotHUZ1OWz+ 29 | hpzpav2dwW7xhUk6zXCEdYqIL9PNX2r+3azfLa88Ke2+gxJ+WEkLGgYm8SHEXOON 30 | HRYt+HIw9b1vv56uBhXwENAFwCO81L3Nnid2565CNTsCgcEAjZuZj9q5k/5VkR61 31 | gv0Of3gSGF7E6k1z0bRLyT4QnSrMgJVgBdG0lvbqeYkZIS4UKn7J+7fPX6m3ZY4I 32 | D3MrdKU3sMlIaQL+9mj3NhEjpb/ksHHqLrlXE55eEYq14cklPXMhmr3WrHqkeYkF 33 | gUQx4S8qUP9De9wob8liwJp10pdEOBBrHnWJB+Z52z/7Zp6dqP0dPgWPvsYheIyg 34 | EK8hgG1xU6rBB7xEMbqLfpLNHB/BBAIA3xzl1EfJAodiBhJHAoHAeTS2znDHYayI 35 | TvK86tBAPVORiBVTSdRUONdGF3dipo24hyeyrI5MtiOoMc3sKWXnSTkDQWa3WiPx 36 | qStBmmO/SbGTuz7T6+oOwGeMiYzYBe87Ayn8Y0KYYshFikieJbGusHjUlIGmCVPy 37 | UHrDMYGwFGUGBwW47gBsnZa+YPHtxWCPDe/U80et2Trx0RXJJQPmupAVMSiJWObI 38 | 9k5gRU+xDqkHanyD1gkGGwhFTUNX94EJEOdQEWw3hxLnVtePoke/ 39 | -----END RSA PRIVATE KEY----- 40 | -------------------------------------------------------------------------------- /Util/LogBase.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_H 2 | #define LOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | using namespace std; 19 | 20 | namespace util { 21 | 22 | namespace log { 23 | enum Severity { 24 | verbose, 25 | info, 26 | warning, 27 | error, 28 | timer, 29 | severity_count 30 | }; 31 | 32 | typedef boost::format Fmt; 33 | } 34 | 35 | 36 | class LogBase { 37 | 38 | public: 39 | static LogBase* Inst(); 40 | void Log(const log::Fmt& msg, log::Severity s = log::info); 41 | bool Enable(log::Severity s, bool enable = true); 42 | bool IsEnabled(log::Severity s) const; 43 | void DisableAll(bool b); 44 | virtual ~LogBase(); 45 | 46 | private: 47 | LogBase(); 48 | 49 | private: 50 | std::bitset m_enabled; 51 | static LogBase *instance; 52 | log4cpp::Appender *appender; 53 | log4cpp::Category &root = log4cpp::Category::getRoot(); 54 | 55 | struct timespec start; 56 | vector> measurements; 57 | }; 58 | 59 | void Log(const std::string& str, log::Severity s = log::info); 60 | void DisableAllLogs(bool b); 61 | 62 | template 63 | void Log(const std::string& fmt, const P1& p1, log::Severity s = log::info) { 64 | LogBase::Inst()->Log(log::Fmt(fmt) % p1, s); 65 | } 66 | 67 | template 68 | void Log(const std::string& fmt, const P1& p1, const P2& p2, log::Severity s = log::info) { 69 | LogBase::Inst()->Log( log::Fmt(fmt) % p1 % p2, s ) ; 70 | } 71 | 72 | template 73 | void Log(const std::string& fmt, const P1& p1, const P2& p2, const P3& p3, log::Severity s = log::info) { 74 | LogBase::Inst()->Log(log::Fmt(fmt) % p1 % p2 % p3, s); 75 | } 76 | 77 | template 78 | void Log(const std::string& fmt, const P1& p1, const P2& p2, const P3& p3, const P4& p4, log::Severity s = log::info) { 79 | LogBase::Inst()->Log(log::Fmt(fmt) % p1 % p2 % p3 % p4, s); 80 | } 81 | 82 | template 83 | void Log(const std::string& fmt, const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5, log::Severity s = log::info) { 84 | LogBase::Inst()->Log(log::Fmt(fmt) % p1 % p2 % p3 % p4 % p5, s); 85 | } 86 | 87 | } 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /Enclave/Enclave.cpp: -------------------------------------------------------------------------------- 1 | #include "Enclave.h" 2 | 3 | #include 4 | 5 | using namespace util; 6 | using namespace std; 7 | 8 | Enclave* Enclave::instance = NULL; 9 | 10 | Enclave::Enclave() {} 11 | 12 | Enclave* Enclave::getInstance() { 13 | if (instance == NULL) { 14 | instance = new Enclave(); 15 | } 16 | 17 | return instance; 18 | } 19 | 20 | 21 | Enclave::~Enclave() { 22 | int ret = -1; 23 | 24 | if (INT_MAX != context) { 25 | int ret_save = -1; 26 | ret = enclave_ra_close(enclave_id, &status, context); 27 | if (SGX_SUCCESS != ret || status) { 28 | ret = -1; 29 | Log("Error, call enclave_ra_close fail", log::error); 30 | } else { 31 | // enclave_ra_close was successful, let's restore the value that 32 | // led us to this point in the code. 33 | ret = ret_save; 34 | } 35 | 36 | Log("Call enclave_ra_close success"); 37 | } 38 | 39 | sgx_destroy_enclave(enclave_id); 40 | } 41 | 42 | 43 | 44 | sgx_status_t Enclave::createEnclave() { 45 | sgx_status_t ret; 46 | int launch_token_update = 0; 47 | int enclave_lost_retry_time = 1; 48 | sgx_launch_token_t launch_token = {0}; 49 | 50 | memset(&launch_token, 0, sizeof(sgx_launch_token_t)); 51 | 52 | do { 53 | ret = sgx_create_enclave(this->enclave_path, 54 | SGX_DEBUG_FLAG, 55 | &launch_token, 56 | &launch_token_update, 57 | &this->enclave_id, NULL); 58 | 59 | if (SGX_SUCCESS != ret) { 60 | Log("Error, call sgx_create_enclave fail", log::error); 61 | print_error_message(ret); 62 | break; 63 | } else { 64 | Log("Call sgx_create_enclave success"); 65 | 66 | ret = enclave_init_ra(this->enclave_id, 67 | &this->status, 68 | false, 69 | &this->context); 70 | } 71 | 72 | } while (SGX_ERROR_ENCLAVE_LOST == ret && enclave_lost_retry_time--); 73 | 74 | if (ret == SGX_SUCCESS) 75 | Log("Enclave created, ID: %llx", this->enclave_id); 76 | 77 | 78 | return ret; 79 | } 80 | 81 | 82 | sgx_enclave_id_t Enclave::getID() { 83 | return this->enclave_id; 84 | } 85 | 86 | sgx_status_t Enclave::getStatus() { 87 | return this->status; 88 | } 89 | 90 | sgx_ra_context_t Enclave::getContext() { 91 | return this->context; 92 | } 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /Util/Base64.cpp: -------------------------------------------------------------------------------- 1 | #include "Base64.h" 2 | #include 3 | 4 | static const std::string base64_chars = 5 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 6 | "abcdefghijklmnopqrstuvwxyz" 7 | "0123456789+/"; 8 | 9 | 10 | static inline bool is_base64(unsigned char c) { 11 | return (isalnum(c) || (c == '+') || (c == '/')); 12 | } 13 | 14 | std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { 15 | std::string ret; 16 | int i = 0; 17 | int j = 0; 18 | unsigned char char_array_3[3]; 19 | unsigned char char_array_4[4]; 20 | 21 | while (in_len--) { 22 | char_array_3[i++] = *(bytes_to_encode++); 23 | if (i == 3) { 24 | char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; 25 | char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); 26 | char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); 27 | char_array_4[3] = char_array_3[2] & 0x3f; 28 | 29 | for (i=0; i<4; i++) 30 | ret += base64_chars[char_array_4[i]]; 31 | i = 0; 32 | } 33 | } 34 | 35 | if (i) { 36 | for(j = i; j < 3; j++) 37 | char_array_3[j] = '\0'; 38 | 39 | char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; 40 | char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); 41 | char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); 42 | char_array_4[3] = char_array_3[2] & 0x3f; 43 | 44 | for (j=0; j> 4); 71 | char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); 72 | char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; 73 | 74 | for (i=0; i<3; i++) 75 | ret += char_array_3[i]; 76 | i = 0; 77 | } 78 | } 79 | 80 | if (i) { 81 | for (j=i; j<4; j++) 82 | char_array_4[j] = 0; 83 | 84 | for (j=0; j<4; j++) 85 | char_array_4[j] = base64_chars.find(char_array_4[j]); 86 | 87 | char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); 88 | char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); 89 | char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; 90 | 91 | for (j=0; j 3 | #include 4 | 5 | using namespace util; 6 | 7 | AbstractNetworkOps::AbstractNetworkOps(boost::asio::io_service& io_service, boost::asio::ssl::context& context) : socket_(io_service, context) {} 8 | 9 | AbstractNetworkOps::~AbstractNetworkOps() {} 10 | 11 | 12 | AbstractNetworkOps::ssl_socket::lowest_layer_type& AbstractNetworkOps::socket() { 13 | return socket_.lowest_layer(); 14 | } 15 | 16 | 17 | void AbstractNetworkOps::saveCloseSocket() { 18 | boost::system::error_code ec; 19 | 20 | socket_.lowest_layer().cancel(); 21 | 22 | if (ec) { 23 | stringstream ss; 24 | Log("Socket shutdown error: %s", ec.message()); 25 | } else { 26 | socket_.lowest_layer().close(); 27 | } 28 | } 29 | 30 | 31 | void AbstractNetworkOps::read() { 32 | char buffer_header[20]; 33 | memset(buffer_header, '\0', 20); 34 | 35 | boost::system::error_code ec; 36 | int read = boost::asio::read(socket_, boost::asio::buffer(buffer_header, 20), ec); 37 | 38 | if (ec) { 39 | if ((boost::asio::error::eof == ec) || (boost::asio::error::connection_reset == ec)) { 40 | Log("Connection has been closed by remote host"); 41 | } else { 42 | Log("Unknown socket error while reading occured!", log::error); 43 | } 44 | } else { 45 | vector incomming; 46 | boost::split(incomming, buffer_header, boost::is_any_of("@")); 47 | 48 | int msg_size = boost::lexical_cast(incomming[0]); 49 | int type = boost::lexical_cast(incomming[1]); 50 | 51 | char *buffer = (char*) malloc(sizeof(char) * msg_size); 52 | memset(buffer, '\0', sizeof(char)*msg_size); 53 | 54 | read = boost::asio::read(socket_, boost::asio::buffer(buffer, msg_size)); 55 | 56 | process_read(buffer, msg_size, type); 57 | } 58 | } 59 | 60 | 61 | void AbstractNetworkOps::send(vector v) { 62 | string type = v[0]; 63 | string msg = v[1]; 64 | 65 | if (msg.size() > 0) { 66 | const char *msg_c = msg.c_str(); 67 | int msg_length = msg.size(); 68 | 69 | string header = to_string(msg_length) + "@" + type; 70 | 71 | char buffer_header[20]; 72 | memset(buffer_header, '\0', 20); 73 | memcpy(buffer_header, header.c_str(), header.length()); 74 | 75 | boost::asio::write(socket_, boost::asio::buffer(buffer_header, 20)); 76 | 77 | char *buffer_msg = (char*) malloc(sizeof(char) * msg_length); 78 | 79 | memset(buffer_msg, '\0', sizeof(char) * msg_length); 80 | memcpy(buffer_msg, msg_c, msg_length); 81 | 82 | boost::asio::write(socket_, boost::asio::buffer(buffer_msg, msg_length)); 83 | 84 | free(buffer_msg); 85 | 86 | this->read(); 87 | } else { 88 | this->saveCloseSocket(); 89 | } 90 | } 91 | 92 | 93 | void AbstractNetworkOps::setCallbackHandler(CallbackHandler cb) { 94 | this->callback_handler = cb; 95 | } 96 | 97 | 98 | void AbstractNetworkOps::process_read(char* buffer, int msg_size, int type) { 99 | std::string str(reinterpret_cast(buffer), msg_size); 100 | 101 | free(buffer); 102 | 103 | auto msg = this->callback_handler(str, type); 104 | 105 | if (msg.size() == 2 && msg[0].size() > 0 && msg[1].size() > 0) { 106 | Log("Send to client"); 107 | send(msg); 108 | } else { 109 | Log("Close connection"); 110 | this->saveCloseSocket(); 111 | } 112 | } 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /ServiceProvider/service_provider/ias_ra.h: -------------------------------------------------------------------------------- 1 | #ifndef _IAS_RA_H 2 | #define _IAS_RA_H 3 | 4 | #include "ecp.h" 5 | #include "sgx_quote.h" 6 | 7 | #include "LogBase.h" 8 | #include "WebService.h" 9 | 10 | using namespace util; 11 | 12 | typedef enum { 13 | IAS_QUOTE_OK, 14 | IAS_QUOTE_SIGNATURE_INVALID, 15 | IAS_QUOTE_GROUP_REVOKED, 16 | IAS_QUOTE_SIGNATURE_REVOKED, 17 | IAS_QUOTE_KEY_REVOKED, 18 | IAS_QUOTE_SIGRL_VERSION_MISMATCH, 19 | IAS_QUOTE_GROUP_OUT_OF_DATE, 20 | } ias_quote_status_t; 21 | 22 | // These status should align with the definition in IAS API spec(rev 0.6) 23 | typedef enum { 24 | IAS_PSE_OK, 25 | IAS_PSE_DESC_TYPE_NOT_SUPPORTED, 26 | IAS_PSE_ISVSVN_OUT_OF_DATE, 27 | IAS_PSE_MISCSELECT_INVALID, 28 | IAS_PSE_ATTRIBUTES_INVALID, 29 | IAS_PSE_MRSIGNER_INVALID, 30 | IAS_PS_HW_GID_REVOKED, 31 | IAS_PS_HW_PRIVKEY_RLVER_MISMATCH, 32 | IAS_PS_HW_SIG_RLVER_MISMATCH, 33 | IAS_PS_HW_CA_ID_INVALID, 34 | IAS_PS_HW_SEC_INFO_INVALID, 35 | IAS_PS_HW_PSDA_SVN_OUT_OF_DATE, 36 | } ias_pse_status_t; 37 | 38 | // Revocation Reasons from RFC5280 39 | typedef enum { 40 | IAS_REVOC_REASON_NONE, 41 | IAS_REVOC_REASON_KEY_COMPROMISE, 42 | IAS_REVOC_REASON_CA_COMPROMISED, 43 | IAS_REVOC_REASON_SUPERCEDED, 44 | IAS_REVOC_REASON_CESSATION_OF_OPERATION, 45 | IAS_REVOC_REASON_CERTIFICATE_HOLD, 46 | IAS_REVOC_REASON_PRIVILEGE_WITHDRAWN, 47 | IAS_REVOC_REASON_AA_COMPROMISE, 48 | } ias_revoc_reason_t; 49 | 50 | // These status should align with the definition in IAS API spec(rev 0.6) 51 | #define IAS_EPID_GROUP_STATUS_REVOKED_BIT_POS 0x00 52 | #define IAS_EPID_GROUP_STATUS_REKEY_AVAILABLE_BIT_POS 0x01 53 | 54 | #define IAS_TCB_EVAL_STATUS_CPUSVN_OUT_OF_DATE_BIT_POS 0x00 55 | #define IAS_TCB_EVAL_STATUS_ISVSVN_OUT_OF_DATE_BIT_POS 0x01 56 | 57 | #define IAS_PSE_EVAL_STATUS_ISVSVN_OUT_OF_DATE_BIT_POS 0x00 58 | #define IAS_PSE_EVAL_STATUS_EPID_GROUP_REVOKED_BIT_POS 0x01 59 | #define IAS_PSE_EVAL_STATUS_PSDASVN_OUT_OF_DATE_BIT_POS 0x02 60 | #define IAS_PSE_EVAL_STATUS_SIGRL_OUT_OF_DATE_BIT_POS 0x03 61 | #define IAS_PSE_EVAL_STATUS_PRIVRL_OUT_OF_DATE_BIT_POS 0x04 62 | 63 | // These status should align with the definition in IAS API spec(rev 0.6) 64 | #define ISVSVN_SIZE 2 65 | #define PSDA_SVN_SIZE 4 66 | #define GID_SIZE 4 67 | #define PSVN_SIZE 18 68 | 69 | #define SAMPLE_HASH_SIZE 32 // SHA256 70 | #define SAMPLE_MAC_SIZE 16 // Message Authentication Code 71 | // - 16 bytes 72 | 73 | #define SAMPLE_REPORT_DATA_SIZE 64 74 | 75 | typedef uint8_t sample_measurement_t[SAMPLE_HASH_SIZE]; 76 | typedef uint8_t sample_mac_t[SAMPLE_MAC_SIZE]; 77 | typedef uint8_t sample_report_data_t[SAMPLE_REPORT_DATA_SIZE]; 78 | typedef uint16_t sample_prod_id_t; 79 | 80 | #define SAMPLE_CPUSVN_SIZE 16 81 | 82 | typedef uint8_t sample_cpu_svn_t[SAMPLE_CPUSVN_SIZE]; 83 | typedef uint16_t sample_isv_svn_t; 84 | 85 | typedef struct sample_attributes_t { 86 | uint64_t flags; 87 | uint64_t xfrm; 88 | } sample_attributes_t; 89 | 90 | typedef struct sample_report_body_t { 91 | sample_cpu_svn_t cpu_svn; // ( 0) Security Version of the CPU 92 | uint8_t reserved1[32]; // ( 16) 93 | sample_attributes_t attributes; // ( 48) Any special Capabilities 94 | // the Enclave possess 95 | sample_measurement_t mr_enclave; // ( 64) The value of the enclave's 96 | // ENCLAVE measurement 97 | uint8_t reserved2[32]; // ( 96) 98 | sample_measurement_t mr_signer; // (128) The value of the enclave's 99 | // SIGNER measurement 100 | uint8_t reserved3[32]; // (160) 101 | sample_measurement_t mr_reserved1; // (192) 102 | sample_measurement_t mr_reserved2; // (224) 103 | sample_prod_id_t isv_prod_id; // (256) Product ID of the Enclave 104 | sample_isv_svn_t isv_svn; // (258) Security Version of the 105 | // Enclave 106 | uint8_t reserved4[60]; // (260) 107 | sample_report_data_t report_data; // (320) Data provided by the user 108 | } sample_report_body_t; 109 | 110 | #pragma pack(push, 1) 111 | 112 | typedef struct _ias_att_report_t { 113 | char id[100]; 114 | ias_quote_status_t status; 115 | uint32_t revocation_reason; 116 | ias_platform_info_blob_t info_blob; 117 | ias_pse_status_t pse_status; 118 | uint32_t policy_report_size; 119 | uint8_t policy_report[];// IAS_Q: Why does it specify a list of reports? 120 | } ias_att_report_t; 121 | 122 | #define SAMPLE_QUOTE_UNLINKABLE_SIGNATURE 0 123 | #define SAMPLE_QUOTE_LINKABLE_SIGNATURE 1 124 | 125 | #pragma pack(pop) 126 | 127 | #ifdef __cplusplus 128 | extern "C" { 129 | #endif 130 | 131 | int ias_verify_attestation_evidence(uint8_t* p_isv_quote, uint8_t* pse_manifest, ias_att_report_t* attestation_verification_report, WebService *ws); 132 | 133 | #ifdef __cplusplus 134 | } 135 | #endif 136 | 137 | #endif 138 | -------------------------------------------------------------------------------- /ServiceProvider/Makefile: -------------------------------------------------------------------------------- 1 | ######## SGX SDK Settings ######## 2 | SGX_SDK ?= /opt/intel/sgxsdk 3 | SGX_MODE ?= SIM 4 | SGX_ARCH ?= x64 5 | 6 | ifeq ($(shell getconf LONG_BIT), 32) 7 | SGX_ARCH := x86 8 | else ifeq ($(findstring -m32, $(CXXFLAGS)), -m32) 9 | SGX_ARCH := x86 10 | endif 11 | 12 | ifeq ($(SGX_ARCH), x86) 13 | SGX_COMMON_CFLAGS := -m32 14 | SGX_LIBRARY_PATH := $(SGX_SDK)/lib 15 | SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x86/sgx_sign 16 | SGX_EDGER8R := $(SGX_SDK)/bin/x86/sgx_edger8r 17 | else 18 | SGX_COMMON_CFLAGS := -m64 19 | SGX_LIBRARY_PATH := $(SGX_SDK)/lib64 20 | SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x64/sgx_sign 21 | SGX_EDGER8R := $(SGX_SDK)/bin/x64/sgx_edger8r 22 | endif 23 | 24 | ifeq ($(SGX_DEBUG), 1) 25 | ifeq ($(SGX_PRERELEASE), 1) 26 | $(error Cannot set SGX_DEBUG and SGX_PRERELEASE at the same time!!) 27 | endif 28 | endif 29 | 30 | ifeq ($(SGX_DEBUG), 1) 31 | SGX_COMMON_CFLAGS += -O0 -g 32 | else 33 | SGX_COMMON_CFLAGS += -O2 34 | endif 35 | 36 | ifeq ($(SUPPLIED_KEY_DERIVATION), 1) 37 | SGX_COMMON_CFLAGS += -DSUPPLIED_KEY_DERIVATION 38 | endif 39 | 40 | 41 | ######## App Settings ######## 42 | ifneq ($(SGX_MODE), HW) 43 | Urts_Library_Name := sgx_urts_sim 44 | else 45 | Urts_Library_Name := sgx_urts 46 | endif 47 | 48 | App_Cpp_Files := isv_app/isv_app.cpp ../Util/LogBase.cpp ../Networking/NetworkManager.cpp \ 49 | ../Networking/Session.cpp ../Networking/Client.cpp ../Networking/Server.cpp isv_app/VerificationManager.cpp ../Networking/NetworkManagerClient.cpp \ 50 | ../GoogleMessages/Messages.pb.cpp ../Networking/AbstractNetworkOps.cpp ../Util/UtilityFunctions.cpp ../WebService/WebService.cpp \ 51 | ../Util/Base64.cpp 52 | 53 | App_Include_Paths := -Iservice_provider -I$(SGX_SDK)/include -Iheaders -I../Util -I../Networking -Iisv_app -I../GoogleMessages -I/usr/local/include -I../WebService 54 | 55 | App_C_Flags := $(SGX_COMMON_CFLAGS) -fPIC -Wno-attributes $(App_Include_Paths) 56 | 57 | # Three configuration modes - Debug, prerelease, release 58 | # Debug - Macro DEBUG enabled. 59 | # Prerelease - Macro NDEBUG and EDEBUG enabled. 60 | # Release - Macro NDEBUG enabled. 61 | ifeq ($(SGX_DEBUG), 1) 62 | App_C_Flags += -DDEBUG -UNDEBUG -UEDEBUG 63 | else ifeq ($(SGX_PRERELEASE), 1) 64 | App_C_Flags += -DNDEBUG -DEDEBUG -UDEBUG 65 | else 66 | App_C_Flags += -DNDEBUG -UEDEBUG -UDEBUG 67 | endif 68 | 69 | App_Cpp_Flags := $(App_C_Flags) -std=c++11 -DEnableClient 70 | App_Link_Flags := $(SGX_COMMON_CFLAGS) -L$(SGX_LIBRARY_PATH) -l$(Urts_Library_Name) -L. -lsgx_ukey_exchange -lpthread -lservice_provider \ 71 | -Wl,-rpath=$(CURDIR)/sample_libcrypto -Wl,-rpath=$(CURDIR) -llog4cpp -lboost_system -L/usr/lib -lssl -lcrypto -lboost_thread -lprotobuf -L /usr/local/lib -ljsoncpp -lcurl 72 | 73 | ifneq ($(SGX_MODE), HW) 74 | App_Link_Flags += -lsgx_uae_service_sim 75 | else 76 | App_Link_Flags += -lsgx_uae_service 77 | endif 78 | 79 | App_Cpp_Objects := $(App_Cpp_Files:.cpp=.o) 80 | 81 | App_Name := app 82 | 83 | 84 | 85 | ######## Service Provider Settings ######## 86 | ServiceProvider_Cpp_Files := service_provider/ecp.cpp ../Util/LogBase.cpp \ 87 | service_provider/ias_ra.cpp ../Util/UtilityFunctions.cpp ../WebService/WebService.cpp service_provider/ServiceProvider.cpp 88 | 89 | ServiceProvider_Include_Paths := -I$(SGX_SDK)/include -I$(SGX_SDK)/include/tlibc -I$(SGX_SDK)/include/stlport -Isample_libcrypto 90 | 91 | ServiceProvider_C_Flags := $(SGX_COMMON_CFLAGS) -fPIC -Wno-attributes -I$(SGX_SDK)/include -Isample_libcrypto -I/usr/local/include -I../GoogleMessages -I../Util \ 92 | -I../WebService -I../Networking 93 | 94 | ServiceProvider_Cpp_Flags := $(ServiceProvider_C_Flags) -std=c++11 95 | ServiceProvider_Link_Flags := -shared $(SGX_COMMON_CFLAGS) -L$(SGX_LIBRARY_PATH) -lsample_libcrypto -Lsample_libcrypto -llog4cpp 96 | 97 | ServiceProvider_Cpp_Objects := $(ServiceProvider_Cpp_Files:.cpp=.o) 98 | 99 | .PHONY: all run 100 | 101 | all: libservice_provider.so $(App_Name) 102 | 103 | 104 | 105 | ######## App Objects ######## 106 | isv_app/%.o: isv_app/%.cpp 107 | @$(CXX) $(App_Cpp_Flags) -c $< -o $@ 108 | @echo "CXX <= $<" 109 | 110 | ../Util/%.o: ../Util/%.cpp 111 | @$(CXX) $(App_Cpp_Flags) -c $< -o $@ 112 | @echo "CXX <= $<" 113 | 114 | ../Networking/%.o: ../Networking/%.cpp 115 | @$(CXX) $(App_Cpp_Flags) -c $< -o $@ 116 | @echo "CXX <= $<" 117 | 118 | ../GoogleMessages/%.o: ../GoogleMessages/%.cpp 119 | @$(CXX) $(App_Cpp_Flags) -c $< -o $@ 120 | @echo "CXX <= $<" 121 | 122 | ../WebService/%.o: ../WebService/%.cpp 123 | @$(CXX) $(App_Cpp_Flags) -c $< -o $@ 124 | @echo "CXX <= $<" 125 | 126 | CertificateHandler/%.o: CertificateHandler/%.cpp 127 | @$(CXX) $(App_Cpp_Flags) -c $< -o $@ 128 | @echo "CXX <= $<" 129 | 130 | $(App_Name): $(App_Cpp_Objects) 131 | @$(CXX) $^ -o $@ $(App_Link_Flags) 132 | @echo "LINK => $@" 133 | 134 | 135 | 136 | ######## Service Provider Objects ######## 137 | service_provider/%.o: service_provider/%.cpp 138 | @$(CXX) $(ServiceProvider_Cpp_Flags) -c $< -o $@ 139 | @echo "CXX <= $<" 140 | 141 | libservice_provider.so: $(ServiceProvider_Cpp_Objects) 142 | @$(CXX) $^ -o $@ $(ServiceProvider_Link_Flags) 143 | @echo "LINK => $@" 144 | 145 | .PHONY: clean 146 | 147 | clean: 148 | @rm -f $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) isv_app/isv_enclave_u.* $(Enclave_Cpp_Objects) isv_enclave/isv_enclave_t.* libservice_provider.* $(ServiceProvider_Cpp_Objects) 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /ServiceProvider/isv_app/VerificationManager.cpp: -------------------------------------------------------------------------------- 1 | #include "VerificationManager.h" 2 | #include "../GeneralSettings.h" 3 | 4 | #include 5 | 6 | using namespace util; 7 | using namespace std; 8 | 9 | VerificationManager* VerificationManager::instance = NULL; 10 | 11 | VerificationManager::VerificationManager() { 12 | this->nm = NetworkManagerClient::getInstance(Settings::rh_port, Settings::rh_host); 13 | this->ws = WebService::getInstance(); 14 | this->ws->init(); 15 | this->sp = new ServiceProvider(this->ws); 16 | } 17 | 18 | 19 | VerificationManager::~VerificationManager() {} 20 | 21 | 22 | VerificationManager* VerificationManager::getInstance() { 23 | if (instance == NULL) { 24 | instance = new VerificationManager(); 25 | } 26 | 27 | return instance; 28 | } 29 | 30 | 31 | int VerificationManager::init() { 32 | if (this->sp) { 33 | delete this->sp; 34 | this->sp = new ServiceProvider(this->ws); 35 | } 36 | 37 | this->nm->Init(); 38 | this->nm->connectCallbackHandler([this](string v, int type) { 39 | return this->incomingHandler(v, type); 40 | }); 41 | } 42 | 43 | 44 | void VerificationManager::start() { 45 | this->nm->startService(); 46 | Log("Remote attestation done"); 47 | } 48 | 49 | 50 | string VerificationManager::handleMSG0(Messages::MessageMsg0 msg) { 51 | Log("MSG0 received"); 52 | 53 | if (msg.status() != TYPE_TERMINATE) { 54 | uint32_t extended_epid_group_id = msg.epid(); 55 | int ret = this->sp->sp_ra_proc_msg0_req(extended_epid_group_id); 56 | 57 | if (ret == 0) { 58 | msg.set_status(TYPE_OK); 59 | return nm->serialize(msg); 60 | } 61 | } else { 62 | Log("Termination received!"); 63 | } 64 | 65 | return ""; 66 | } 67 | 68 | 69 | string VerificationManager::handleMSG1(Messages::MessageMSG1 msg1) { 70 | Log("MSG1 received"); 71 | 72 | Messages::MessageMSG2 msg2; 73 | msg2.set_type(RA_MSG2); 74 | 75 | int ret = this->sp->sp_ra_proc_msg1_req(msg1, &msg2); 76 | 77 | if (ret != 0) { 78 | Log("Error, processing MSG1 failed"); 79 | } else { 80 | Log("MSG1 processed correctly and MSG2 created"); 81 | return nm->serialize(msg2); 82 | } 83 | 84 | return ""; 85 | } 86 | 87 | 88 | string VerificationManager::handleMSG3(Messages::MessageMSG3 msg) { 89 | Log("MSG3 received"); 90 | 91 | Messages::AttestationMessage att_msg; 92 | att_msg.set_type(RA_ATT_RESULT); 93 | 94 | int ret = this->sp->sp_ra_proc_msg3_req(msg, &att_msg); 95 | 96 | if (ret == -1) { 97 | Log("Error, processing MSG3 failed"); 98 | } else { 99 | Log("MSG3 processed correctly and attestation result created"); 100 | return nm->serialize(att_msg); 101 | } 102 | 103 | return ""; 104 | } 105 | 106 | 107 | string VerificationManager::handleAppAttOk() { 108 | Log("APP attestation result received"); 109 | return ""; 110 | } 111 | 112 | 113 | string VerificationManager::prepareVerificationRequest() { 114 | Log("Prepare Verification request"); 115 | 116 | Messages::InitialMessage msg; 117 | msg.set_type(RA_VERIFICATION); 118 | 119 | return nm->serialize(msg); 120 | } 121 | 122 | 123 | string VerificationManager::createInitMsg(int type, string msg) { 124 | Messages::InitialMessage init_msg; 125 | init_msg.set_type(type); 126 | init_msg.set_size(msg.size()); 127 | 128 | return nm->serialize(init_msg); 129 | } 130 | 131 | 132 | vector VerificationManager::incomingHandler(string v, int type) { 133 | vector res; 134 | 135 | if (!v.empty()) { 136 | string s; 137 | bool ret; 138 | 139 | switch (type) { 140 | case RA_MSG0: { 141 | Messages::MessageMsg0 msg0; 142 | ret = msg0.ParseFromString(v); 143 | if (ret && (msg0.type() == RA_MSG0)) { 144 | s = this->handleMSG0(msg0); 145 | res.push_back(to_string(RA_MSG0)); 146 | } 147 | } 148 | break; 149 | case RA_MSG1: { 150 | Messages::MessageMSG1 msg1; 151 | ret = msg1.ParseFromString(v); 152 | if (ret && (msg1.type() == RA_MSG1)) { 153 | s = this->handleMSG1(msg1); 154 | res.push_back(to_string(RA_MSG2)); 155 | } 156 | } 157 | break; 158 | case RA_MSG3: { 159 | Messages::MessageMSG3 msg3; 160 | ret = msg3.ParseFromString(v); 161 | if (ret && (msg3.type() == RA_MSG3)) { 162 | s = this->handleMSG3(msg3); 163 | res.push_back(to_string(RA_ATT_RESULT)); 164 | } 165 | } 166 | break; 167 | case RA_APP_ATT_OK: { 168 | Messages::SecretMessage sec_msg; 169 | ret = sec_msg.ParseFromString(v); 170 | if (ret) { 171 | if (sec_msg.type() == RA_APP_ATT_OK) { 172 | this->handleAppAttOk(); 173 | } 174 | } 175 | } 176 | break; 177 | default: 178 | Log("Unknown type: %d", type, log::error); 179 | break; 180 | } 181 | 182 | res.push_back(s); 183 | } else { //after handshake 184 | res.push_back(to_string(RA_VERIFICATION)); 185 | res.push_back(this->prepareVerificationRequest()); 186 | } 187 | 188 | return res; 189 | } 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /Util/UtilityFunctions.cpp: -------------------------------------------------------------------------------- 1 | #include "UtilityFunctions.h" 2 | 3 | using namespace util; 4 | 5 | void SafeFree(void *ptr) { 6 | if (NULL != ptr) { 7 | free(ptr); 8 | ptr = NULL; 9 | } 10 | } 11 | 12 | 13 | string GetRandomString() { 14 | string str = lexical_cast((random_generator())()); 15 | str.erase(remove(str.begin(), str.end(), '-'), str.end()); 16 | 17 | return str; 18 | } 19 | 20 | 21 | string ByteArrayToString(const uint8_t *arr, int size) { 22 | ostringstream convert; 23 | 24 | for (int a = 0; a < size; a++) { 25 | convert << setfill('0') << setw(2) << hex << (unsigned int)arr[a]; 26 | } 27 | 28 | return convert.str(); 29 | } 30 | 31 | 32 | string ByteArrayToStringNoFill(const uint8_t *arr, int size) { 33 | ostringstream convert; 34 | 35 | for (int a = 0; a < size; a++) { 36 | convert << hex << (int)arr[a]; 37 | } 38 | 39 | return convert.str(); 40 | } 41 | 42 | 43 | int HexStringToByteArray(string str, uint8_t **arr) { 44 | vector bytes; 45 | 46 | for (unsigned int i=0; i vec(str.begin(), str.end()); 61 | 62 | *arr = (uint8_t*) malloc(sizeof(uint8_t) * vec.size()); 63 | copy(vec.begin(), vec.end(), *arr); 64 | 65 | return vec.size(); 66 | } 67 | 68 | 69 | string ByteArrayToNoHexString(const uint8_t *arr, int size) { 70 | std::ostringstream convert; 71 | 72 | for (int a = 0; a < size; a++) { 73 | convert << (uint8_t)arr[a]; 74 | } 75 | 76 | return convert.str(); 77 | } 78 | 79 | 80 | string UIntToString(uint32_t *arr, int size) { 81 | stringstream ss; 82 | 83 | for (int i=0; i(t)), istreambuf_iterator()); 102 | 103 | *content = (char*) malloc(sizeof(char) * (str.size()+1)); 104 | memset(*content, '\0', (str.size()+1)); 105 | str.copy(*content, str.size()); 106 | 107 | return str.size(); 108 | } 109 | 110 | 111 | int ReadFileToBuffer(string filePath, uint8_t **content) { 112 | ifstream file(filePath, ios::binary | ios::ate); 113 | streamsize file_size = file.tellg(); 114 | 115 | file.seekg(0, ios::beg); 116 | 117 | std::vector buffer(file_size); 118 | 119 | if (file.read(buffer.data(), file_size)) { 120 | string str(buffer.begin(), buffer.end()); 121 | 122 | vector vec(str.begin(), str.end()); 123 | 124 | *content = (uint8_t*) malloc(sizeof(uint8_t) * vec.size()); 125 | copy(vec.begin(), vec.end(), *content); 126 | 127 | return str.length(); 128 | } 129 | 130 | return -1; 131 | } 132 | 133 | 134 | int RemoveFile(string filePath) { 135 | if (remove(filePath.c_str()) != 0 ) { 136 | Log("Error deleting file: " + filePath); 137 | return 1; 138 | } else 139 | Log("File deleted successfully: " + filePath); 140 | 141 | return 0; 142 | } 143 | 144 | 145 | static sgx_errlist_t sgx_errlist[] = { 146 | { 147 | SGX_ERROR_UNEXPECTED, 148 | "Unexpected error occurred.", 149 | NULL 150 | }, 151 | { 152 | SGX_ERROR_INVALID_PARAMETER, 153 | "Invalid parameter.", 154 | NULL 155 | }, 156 | { 157 | SGX_ERROR_OUT_OF_MEMORY, 158 | "Out of memory.", 159 | NULL 160 | }, 161 | { 162 | SGX_ERROR_ENCLAVE_LOST, 163 | "Power transition occurred.", 164 | "Please refer to the sample \"PowerTransition\" for details." 165 | }, 166 | { 167 | SGX_ERROR_INVALID_ENCLAVE, 168 | "Invalid enclave image.", 169 | NULL 170 | }, 171 | { 172 | SGX_ERROR_INVALID_ENCLAVE_ID, 173 | "Invalid enclave identification.", 174 | NULL 175 | }, 176 | { 177 | SGX_ERROR_INVALID_SIGNATURE, 178 | "Invalid enclave signature.", 179 | NULL 180 | }, 181 | { 182 | SGX_ERROR_OUT_OF_EPC, 183 | "Out of EPC memory.", 184 | NULL 185 | }, 186 | { 187 | SGX_ERROR_NO_DEVICE, 188 | "Invalid SGX device.", 189 | "Please make sure SGX module is enabled in the BIOS, and install SGX driver afterwards." 190 | }, 191 | { 192 | SGX_ERROR_MEMORY_MAP_CONFLICT, 193 | "Memory map conflicted.", 194 | NULL 195 | }, 196 | { 197 | SGX_ERROR_INVALID_METADATA, 198 | "Invalid enclave metadata.", 199 | NULL 200 | }, 201 | { 202 | SGX_ERROR_DEVICE_BUSY, 203 | "SGX device was busy.", 204 | NULL 205 | }, 206 | { 207 | SGX_ERROR_INVALID_VERSION, 208 | "Enclave version was invalid.", 209 | NULL 210 | }, 211 | { 212 | SGX_ERROR_INVALID_ATTRIBUTE, 213 | "Enclave was not authorized.", 214 | NULL 215 | }, 216 | { 217 | SGX_ERROR_ENCLAVE_FILE_ACCESS, 218 | "Can't open enclave file.", 219 | NULL 220 | }, 221 | { 222 | SGX_ERROR_MODE_INCOMPATIBLE, 223 | "Target enclave mode is incompatible with the mode of the current RTS", 224 | NULL 225 | }, 226 | { 227 | SGX_ERROR_SERVICE_UNAVAILABLE, 228 | "sgx_create_enclave() needs the AE service to get a launch token", 229 | NULL 230 | }, 231 | { 232 | SGX_ERROR_SERVICE_TIMEOUT, 233 | "The request to the AE service timed out", 234 | NULL 235 | }, 236 | { 237 | SGX_ERROR_SERVICE_INVALID_PRIVILEGE, 238 | "The request requires some special attributes for the enclave, but is not privileged", 239 | NULL 240 | }, 241 | { 242 | SGX_ERROR_NDEBUG_ENCLAVE, 243 | "The enclave is signed as a product enclave and cannot be created as a debuggable enclave", 244 | NULL 245 | }, 246 | { 247 | SGX_ERROR_UNDEFINED_SYMBOL, 248 | "The enclave contains an import table", 249 | NULL 250 | }, 251 | { 252 | SGX_ERROR_INVALID_MISC, 253 | "The MiscSelct/MiscMask settings are not correct", 254 | NULL 255 | }, 256 | { 257 | SGX_ERROR_MAC_MISMATCH, 258 | "The input MAC does not match the MAC calculated", 259 | NULL 260 | } 261 | }; 262 | 263 | 264 | void print_error_message(sgx_status_t ret) { 265 | size_t idx = 0; 266 | size_t ttl = sizeof(sgx_errlist)/sizeof (sgx_errlist[0]); 267 | 268 | for (idx = 0; idx < ttl; idx++) { 269 | if (ret == sgx_errlist[idx].err) { 270 | if (NULL != sgx_errlist[idx].sug) 271 | Log("%s", sgx_errlist[idx].sug); 272 | 273 | Log("%s", sgx_errlist[idx].msg); 274 | break; 275 | } 276 | } 277 | 278 | if (idx == ttl) 279 | Log("Unexpected error occurred"); 280 | } 281 | 282 | 283 | string Base64decode(const string val) { 284 | return base64_decode(val); 285 | } 286 | 287 | 288 | string Base64encodeUint8(uint8_t *val, uint32_t len) { 289 | return base64_encode(val, len); 290 | } 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | -------------------------------------------------------------------------------- /ServiceProvider/service_provider/ecp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ecp.h" 4 | 5 | #include "sample_libcrypto.h" 6 | 7 | 8 | #define MAC_KEY_SIZE 16 9 | 10 | errno_t memcpy_s( 11 | void *dest, 12 | size_t numberOfElements, 13 | const void *src, 14 | size_t count) { 15 | if(numberOfElementss[sizeof(p_shared_key->s) - 1 - i]; 75 | } 76 | 77 | sample_ret = sample_sha256_init(&sha_context); 78 | if (sample_ret != SAMPLE_SUCCESS) { 79 | return false; 80 | } 81 | sample_ret = sample_sha256_update((uint8_t*)&hash_buffer, sizeof(hash_buffer_t), sha_context); 82 | if (sample_ret != SAMPLE_SUCCESS) { 83 | sample_sha256_close(sha_context); 84 | return false; 85 | } 86 | sample_ret = sample_sha256_update((uint8_t*)ID_U, sizeof(ID_U), sha_context); 87 | if (sample_ret != SAMPLE_SUCCESS) { 88 | sample_sha256_close(sha_context); 89 | return false; 90 | } 91 | sample_ret = sample_sha256_update((uint8_t*)ID_V, sizeof(ID_V), sha_context); 92 | if (sample_ret != SAMPLE_SUCCESS) { 93 | sample_sha256_close(sha_context); 94 | return false; 95 | } 96 | sample_ret = sample_sha256_get_hash(sha_context, &key_material); 97 | if (sample_ret != SAMPLE_SUCCESS) { 98 | sample_sha256_close(sha_context); 99 | return false; 100 | } 101 | sample_ret = sample_sha256_close(sha_context); 102 | 103 | static_assert(sizeof(sample_ec_key_128bit_t)* 2 == sizeof(sample_sha256_hash_t), "structure size mismatch."); 104 | memcpy(first_derived_key, &key_material, sizeof(sample_ec_key_128bit_t)); 105 | memcpy(second_derived_key, (uint8_t*)&key_material + sizeof(sample_ec_key_128bit_t), sizeof(sample_ec_key_128bit_t)); 106 | 107 | // memset here can be optimized away by compiler, so please use memset_s on 108 | // windows for production code and similar functions on other OSes. 109 | memset(&key_material, 0, sizeof(sample_sha256_hash_t)); 110 | 111 | return true; 112 | } 113 | 114 | #else 115 | 116 | #pragma message ("Default key derivation function is used.") 117 | 118 | #define EC_DERIVATION_BUFFER_SIZE(label_length) ((label_length) +4) 119 | 120 | const char str_SMK[] = "SMK"; 121 | const char str_SK[] = "SK"; 122 | const char str_MK[] = "MK"; 123 | const char str_VK[] = "VK"; 124 | 125 | // Derive key from shared key and key id. 126 | // key id should be sample_derive_key_type_t. 127 | bool derive_key( 128 | const sample_ec_dh_shared_t *p_shared_key, 129 | uint8_t key_id, 130 | sample_ec_key_128bit_t* derived_key) { 131 | sample_status_t sample_ret = SAMPLE_SUCCESS; 132 | uint8_t cmac_key[MAC_KEY_SIZE]; 133 | sample_ec_key_128bit_t key_derive_key; 134 | 135 | memset(&cmac_key, 0, MAC_KEY_SIZE); 136 | 137 | sample_ret = sample_rijndael128_cmac_msg( 138 | (sample_cmac_128bit_key_t *)&cmac_key, 139 | (uint8_t*)p_shared_key, 140 | sizeof(sample_ec_dh_shared_t), 141 | (sample_cmac_128bit_tag_t *)&key_derive_key); 142 | if (sample_ret != SAMPLE_SUCCESS) { 143 | // memset here can be optimized away by compiler, so please use memset_s on 144 | // windows for production code and similar functions on other OSes. 145 | memset(&key_derive_key, 0, sizeof(key_derive_key)); 146 | return false; 147 | } 148 | 149 | const char *label = NULL; 150 | uint32_t label_length = 0; 151 | switch (key_id) { 152 | case SAMPLE_DERIVE_KEY_SMK: 153 | label = str_SMK; 154 | label_length = sizeof(str_SMK) -1; 155 | break; 156 | case SAMPLE_DERIVE_KEY_SK: 157 | label = str_SK; 158 | label_length = sizeof(str_SK) -1; 159 | break; 160 | case SAMPLE_DERIVE_KEY_MK: 161 | label = str_MK; 162 | label_length = sizeof(str_MK) -1; 163 | break; 164 | case SAMPLE_DERIVE_KEY_VK: 165 | label = str_VK; 166 | label_length = sizeof(str_VK) -1; 167 | break; 168 | default: 169 | // memset here can be optimized away by compiler, so please use memset_s on 170 | // windows for production code and similar functions on other OSes. 171 | memset(&key_derive_key, 0, sizeof(key_derive_key)); 172 | return false; 173 | break; 174 | } 175 | /* derivation_buffer = counter(0x01) || label || 0x00 || output_key_len(0x0080) */ 176 | uint32_t derivation_buffer_length = EC_DERIVATION_BUFFER_SIZE(label_length); 177 | uint8_t *p_derivation_buffer = (uint8_t *)malloc(derivation_buffer_length); 178 | if (p_derivation_buffer == NULL) { 179 | // memset here can be optimized away by compiler, so please use memset_s on 180 | // windows for production code and similar functions on other OSes. 181 | memset(&key_derive_key, 0, sizeof(key_derive_key)); 182 | return false; 183 | } 184 | memset(p_derivation_buffer, 0, derivation_buffer_length); 185 | 186 | /*counter = 0x01 */ 187 | p_derivation_buffer[0] = 0x01; 188 | /*label*/ 189 | memcpy(&p_derivation_buffer[1], label, label_length); 190 | /*output_key_len=0x0080*/ 191 | uint16_t *key_len = (uint16_t *)(&(p_derivation_buffer[derivation_buffer_length - 2])); 192 | *key_len = 0x0080; 193 | 194 | 195 | sample_ret = sample_rijndael128_cmac_msg( 196 | (sample_cmac_128bit_key_t *)&key_derive_key, 197 | p_derivation_buffer, 198 | derivation_buffer_length, 199 | (sample_cmac_128bit_tag_t *)derived_key); 200 | free(p_derivation_buffer); 201 | // memset here can be optimized away by compiler, so please use memset_s on 202 | // windows for production code and similar functions on other OSes. 203 | memset(&key_derive_key, 0, sizeof(key_derive_key)); 204 | if (sample_ret != SAMPLE_SUCCESS) { 205 | return false; 206 | } 207 | return true; 208 | } 209 | #endif 210 | -------------------------------------------------------------------------------- /WebService/WebService.cpp: -------------------------------------------------------------------------------- 1 | #include "WebService.h" 2 | #include "../GeneralSettings.h" 3 | 4 | WebService* WebService::instance = NULL; 5 | 6 | WebService::WebService() {} 7 | 8 | WebService::~WebService() { 9 | if (curl) 10 | curl_easy_cleanup(curl); 11 | } 12 | 13 | 14 | WebService* WebService::getInstance() { 15 | if (instance == NULL) { 16 | instance = new WebService(); 17 | } 18 | 19 | return instance; 20 | } 21 | 22 | 23 | void WebService::init() { 24 | curl_global_init(CURL_GLOBAL_DEFAULT); 25 | 26 | curl = curl_easy_init(); 27 | 28 | if (curl) { 29 | Log("Curl initialized successfully"); 30 | // curl_easy_setopt( curl, CURLOPT_VERBOSE, 1L ); 31 | curl_easy_setopt( curl, CURLOPT_SSLCERTTYPE, "PEM"); 32 | curl_easy_setopt( curl, CURLOPT_SSLCERT, Settings::ias_crt); 33 | curl_easy_setopt( curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); 34 | curl_easy_setopt( curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); 35 | curl_easy_setopt( curl, CURLOPT_NOPROGRESS, 1L); 36 | } else 37 | Log("Curl init error", log::error); 38 | } 39 | 40 | 41 | vector> WebService::parseJSONfromIAS(string json) { 42 | Json::Value root; 43 | Json::Reader reader; 44 | bool parsingSuccessful = reader.parse(json.c_str(), root); 45 | 46 | if (!parsingSuccessful) { 47 | Log("Failed to parse JSON string from IAS", log::error); 48 | return vector>(); 49 | } 50 | 51 | vector> values; 52 | 53 | string id = root.get("id", "UTF-8" ).asString(); 54 | string timestamp = root.get("timestamp", "UTF-8" ).asString(); 55 | string epidPseudonym = root.get("epidPseudonym", "UTF-8" ).asString(); 56 | string isvEnclaveQuoteStatus = root.get("isvEnclaveQuoteStatus", "UTF-8" ).asString(); 57 | 58 | values.push_back({"id", id}); 59 | values.push_back({"timestamp", timestamp}); 60 | values.push_back({"epidPseudonym", epidPseudonym}); 61 | values.push_back({"isvEnclaveQuoteStatus", isvEnclaveQuoteStatus}); 62 | 63 | return values; 64 | } 65 | 66 | 67 | string WebService::createJSONforIAS(uint8_t *quote, uint8_t *pseManifest, uint8_t *nonce) { 68 | Json::Value request; 69 | 70 | request["isvEnclaveQuote"] = Base64encodeUint8(quote, 1116); 71 | // request["pseManifest"] = Base64encodeUint8(quote, 256); //only needed when enclave has been signed 72 | 73 | Json::FastWriter fastWriter; 74 | string output = fastWriter.write(request); 75 | 76 | return output; 77 | } 78 | 79 | 80 | size_t ias_response_header_parser(void *ptr, size_t size, size_t nmemb, void *userdata) { 81 | int parsed_fields = 0, response_status, content_length, ret = size * nmemb; 82 | 83 | char *x = (char*) calloc(size+1, nmemb); 84 | assert(x); 85 | memcpy(x, ptr, size * nmemb); 86 | parsed_fields = sscanf( x, "HTTP/1.1 %d", &response_status ); 87 | 88 | if (parsed_fields == 1) { 89 | ((ias_response_header_t *) userdata)->response_status = response_status; 90 | return ret; 91 | } 92 | 93 | parsed_fields = sscanf( x, "content-length: %d", &content_length ); 94 | if (parsed_fields == 1) { 95 | ((ias_response_header_t *) userdata)->content_length = content_length; 96 | return ret; 97 | } 98 | 99 | char *p_request_id = (char*) calloc(1, REQUEST_ID_MAX_LEN); 100 | parsed_fields = sscanf(x, "request-id: %s", p_request_id ); 101 | 102 | if (parsed_fields == 1) { 103 | std::string request_id_str( p_request_id ); 104 | ( ( ias_response_header_t * ) userdata )->request_id = request_id_str; 105 | return ret; 106 | } 107 | 108 | return ret; 109 | } 110 | 111 | 112 | size_t ias_reponse_body_handler( void *ptr, size_t size, size_t nmemb, void *userdata ) { 113 | size_t realsize = size * nmemb; 114 | ias_response_container_t *ias_response_container = ( ias_response_container_t * ) userdata; 115 | ias_response_container->p_response = (char *) realloc(ias_response_container->p_response, ias_response_container->size + realsize + 1); 116 | 117 | if (ias_response_container->p_response == NULL ) { 118 | Log("Unable to allocate extra memory", log::error); 119 | return 0; 120 | } 121 | 122 | memcpy( &( ias_response_container->p_response[ias_response_container->size]), ptr, realsize ); 123 | ias_response_container->size += realsize; 124 | ias_response_container->p_response[ias_response_container->size] = 0; 125 | 126 | return realsize; 127 | } 128 | 129 | 130 | bool WebService::sendToIAS(string url, 131 | IAS type, 132 | string payload, 133 | struct curl_slist *headers, 134 | ias_response_container_t *ias_response_container, 135 | ias_response_header_t *response_header) { 136 | 137 | CURLcode res = CURLE_OK; 138 | 139 | curl_easy_setopt( curl, CURLOPT_URL, url.c_str()); 140 | 141 | if (headers) { 142 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 143 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.c_str()); 144 | } 145 | 146 | ias_response_container->p_response = (char*) malloc(1); 147 | ias_response_container->size = 0; 148 | 149 | curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, ias_response_header_parser); 150 | curl_easy_setopt(curl, CURLOPT_HEADERDATA, response_header); 151 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ias_reponse_body_handler); 152 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, ias_response_container); 153 | 154 | res = curl_easy_perform(curl); 155 | if (res != CURLE_OK) { 156 | Log("curl_easy_perform() failed: %s", curl_easy_strerror(res)); 157 | return false; 158 | } 159 | 160 | return true; 161 | } 162 | 163 | 164 | bool WebService::getSigRL(string gid, string *sigrl) { 165 | Log("Retrieving SigRL from IAS"); 166 | 167 | //check if the sigrl for the gid has already been retrieved once -> to save time 168 | for (auto x : retrieved_sigrl) { 169 | if (x.first == gid) { 170 | *sigrl = x.second; 171 | return false; 172 | } 173 | } 174 | 175 | ias_response_container_t ias_response_container; 176 | ias_response_header_t response_header; 177 | 178 | string url = Settings::ias_url + "sigrl/" + gid; 179 | 180 | this->sendToIAS(url, IAS::sigrl, "", NULL, &ias_response_container, &response_header); 181 | 182 | Log("\tResponse status is: %d" , response_header.response_status); 183 | Log("\tContent-Length: %d", response_header.content_length); 184 | 185 | if (response_header.response_status == 200) { 186 | if (response_header.content_length > 0) { 187 | string response(ias_response_container.p_response); 188 | *sigrl = Base64decode(response); 189 | } 190 | retrieved_sigrl.push_back({gid, *sigrl}); 191 | } else 192 | return true; 193 | 194 | return false; 195 | } 196 | 197 | 198 | bool WebService::verifyQuote(uint8_t *quote, uint8_t *pseManifest, uint8_t *nonce, vector> *result) { 199 | string encoded_quote = this->createJSONforIAS(quote, pseManifest, nonce); 200 | 201 | ias_response_container_t ias_response_container; 202 | ias_response_header_t response_header; 203 | 204 | struct curl_slist *headers = NULL; 205 | headers = curl_slist_append(headers, "Content-Type: application/json"); 206 | 207 | string payload = encoded_quote; 208 | 209 | string url = Settings::ias_url + "report"; 210 | this->sendToIAS(url, IAS::report, payload, headers, &ias_response_container, &response_header); 211 | 212 | 213 | if (response_header.response_status == 201) { 214 | Log("Quote attestation successful, new report has been created"); 215 | 216 | string response(ias_response_container.p_response); 217 | 218 | auto res = parseJSONfromIAS(response); 219 | *result = res; 220 | } else { 221 | Log("Quote attestation returned status: %d", response_header.response_status); 222 | return true; 223 | } 224 | 225 | return false; 226 | } 227 | 228 | 229 | 230 | 231 | -------------------------------------------------------------------------------- /ServiceProvider/service_provider/ias_ra.cpp: -------------------------------------------------------------------------------- 1 | #include "ServiceProvider.h" 2 | #include "sample_libcrypto.h" 3 | #include "ecp.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "ias_ra.h" 10 | #include "UtilityFunctions.h" 11 | 12 | using namespace std; 13 | 14 | #if !defined(SWAP_ENDIAN_DW) 15 | #define SWAP_ENDIAN_DW(dw) ((((dw) & 0x000000ff) << 24) \ 16 | | (((dw) & 0x0000ff00) << 8) \ 17 | | (((dw) & 0x00ff0000) >> 8) \ 18 | | (((dw) & 0xff000000) >> 24)) 19 | #endif 20 | #if !defined(SWAP_ENDIAN_32B) 21 | #define SWAP_ENDIAN_32B(ptr) \ 22 | {\ 23 | unsigned int temp = 0; \ 24 | temp = SWAP_ENDIAN_DW(((unsigned int*)(ptr))[0]); \ 25 | ((unsigned int*)(ptr))[0] = SWAP_ENDIAN_DW(((unsigned int*)(ptr))[7]); \ 26 | ((unsigned int*)(ptr))[7] = temp; \ 27 | temp = SWAP_ENDIAN_DW(((unsigned int*)(ptr))[1]); \ 28 | ((unsigned int*)(ptr))[1] = SWAP_ENDIAN_DW(((unsigned int*)(ptr))[6]); \ 29 | ((unsigned int*)(ptr))[6] = temp; \ 30 | temp = SWAP_ENDIAN_DW(((unsigned int*)(ptr))[2]); \ 31 | ((unsigned int*)(ptr))[2] = SWAP_ENDIAN_DW(((unsigned int*)(ptr))[5]); \ 32 | ((unsigned int*)(ptr))[5] = temp; \ 33 | temp = SWAP_ENDIAN_DW(((unsigned int*)(ptr))[3]); \ 34 | ((unsigned int*)(ptr))[3] = SWAP_ENDIAN_DW(((unsigned int*)(ptr))[4]); \ 35 | ((unsigned int*)(ptr))[4] = temp; \ 36 | } 37 | #endif 38 | 39 | // This is the ECDSA NIST P-256 private key used to sign platform_info_blob. 40 | // This private 41 | // key and the public key in SDK untrusted KElibrary should be a temporary key 42 | // pair. For production parts an attestation server will sign the platform_info_blob with the 43 | // production private key and the SDK untrusted KE library will have the public 44 | // key for verifcation. 45 | 46 | static const sample_ec256_private_t g_rk_priv_key = { 47 | { 48 | 0x63,0x2c,0xd4,0x02,0x7a,0xdc,0x56,0xa5, 49 | 0x59,0x6c,0x44,0x3e,0x43,0xca,0x4e,0x0b, 50 | 0x58,0xcd,0x78,0xcb,0x3c,0x7e,0xd5,0xb9, 51 | 0xf2,0x91,0x5b,0x39,0x0d,0xb3,0xb5,0xfb 52 | } 53 | }; 54 | 55 | 56 | // Simulates the attestation server function for verifying the quote produce by 57 | // the ISV enclave. It doesn't decrypt or verify the quote in 58 | // the simulation. Just produces the attestaion verification 59 | // report with the platform info blob. 60 | // 61 | // @param p_isv_quote Pointer to the quote generated by the ISV 62 | // enclave. 63 | // @param pse_manifest Pointer to the PSE manifest if used. 64 | // @param p_attestation_verification_report Pointer the outputed 65 | // verification report. 66 | // 67 | // @return int 68 | 69 | int ias_verify_attestation_evidence( 70 | uint8_t *p_isv_quote, 71 | uint8_t* pse_manifest, 72 | ias_att_report_t* p_attestation_verification_report, 73 | WebService *ws) { 74 | int ret = 0; 75 | sample_ecc_state_handle_t ecc_state = NULL; 76 | 77 | vector> result; 78 | bool error = ws->verifyQuote(p_isv_quote, pse_manifest, NULL, &result); 79 | 80 | 81 | if (error || (NULL == p_isv_quote) || (NULL == p_attestation_verification_report)) { 82 | return -1; 83 | } 84 | 85 | string report_id; 86 | uintmax_t test; 87 | ias_quote_status_t quoteStatus; 88 | string timestamp, epidPseudonym, isvEnclaveQuoteStatus; 89 | 90 | for (auto x : result) { 91 | if (x.first == "id") { 92 | report_id = x.second; 93 | } else if (x.first == "timestamp") { 94 | timestamp = x.second; 95 | } else if (x.first == "epidPseudonym") { 96 | epidPseudonym = x.second; 97 | } else if (x.first == "isvEnclaveQuoteStatus") { 98 | if (x.second == "OK") 99 | quoteStatus = IAS_QUOTE_OK; 100 | else if (x.second == "SIGNATURE_INVALID") 101 | quoteStatus = IAS_QUOTE_SIGNATURE_INVALID; 102 | else if (x.second == "GROUP_REVOKED") 103 | quoteStatus = IAS_QUOTE_GROUP_REVOKED; 104 | else if (x.second == "SIGNATURE_REVOKED") 105 | quoteStatus = IAS_QUOTE_SIGNATURE_REVOKED; 106 | else if (x.second == "KEY_REVOKED") 107 | quoteStatus = IAS_QUOTE_KEY_REVOKED; 108 | else if (x.second == "SIGRL_VERSION_MISMATCH") 109 | quoteStatus = IAS_QUOTE_SIGRL_VERSION_MISMATCH; 110 | else if (x.second == "GROUP_OUT_OF_DATE") 111 | quoteStatus = IAS_QUOTE_GROUP_OUT_OF_DATE; 112 | } 113 | } 114 | 115 | report_id.copy(p_attestation_verification_report->id, report_id.size()); 116 | p_attestation_verification_report->status = quoteStatus; 117 | p_attestation_verification_report->revocation_reason = IAS_REVOC_REASON_NONE; 118 | 119 | //this is only sent back from the IAS if something bad happened for reference please see 120 | //https://software.intel.com/sites/default/files/managed/3d/c8/IAS_1_0_API_spec_1_1_Final.pdf 121 | //for testing purposes we assume the world is nice and sunny 122 | p_attestation_verification_report->info_blob.sample_epid_group_status = 123 | 0 << IAS_EPID_GROUP_STATUS_REVOKED_BIT_POS 124 | | 0 << IAS_EPID_GROUP_STATUS_REKEY_AVAILABLE_BIT_POS; 125 | p_attestation_verification_report->info_blob.sample_tcb_evaluation_status = 126 | 0 << IAS_TCB_EVAL_STATUS_CPUSVN_OUT_OF_DATE_BIT_POS 127 | | 0 << IAS_TCB_EVAL_STATUS_ISVSVN_OUT_OF_DATE_BIT_POS; 128 | p_attestation_verification_report->info_blob.pse_evaluation_status = 129 | 0 << IAS_PSE_EVAL_STATUS_ISVSVN_OUT_OF_DATE_BIT_POS 130 | | 0 << IAS_PSE_EVAL_STATUS_EPID_GROUP_REVOKED_BIT_POS 131 | | 0 << IAS_PSE_EVAL_STATUS_PSDASVN_OUT_OF_DATE_BIT_POS 132 | | 0 << IAS_PSE_EVAL_STATUS_SIGRL_OUT_OF_DATE_BIT_POS 133 | | 0 << IAS_PSE_EVAL_STATUS_PRIVRL_OUT_OF_DATE_BIT_POS; 134 | 135 | memset(p_attestation_verification_report->info_blob.latest_equivalent_tcb_psvn, 0, PSVN_SIZE); 136 | memset(p_attestation_verification_report->info_blob.latest_pse_isvsvn, 0, ISVSVN_SIZE); 137 | memset(p_attestation_verification_report->info_blob.latest_psda_svn, 0, PSDA_SVN_SIZE); 138 | memset(p_attestation_verification_report->info_blob.performance_rekey_gid, 0, GID_SIZE); 139 | 140 | // Generate the Service providers ECCDH key pair. 141 | do { 142 | ret = sample_ecc256_open_context(&ecc_state); 143 | if (SAMPLE_SUCCESS != ret) { 144 | Log("Error, cannot get ECC context", log::error); 145 | ret = -1; 146 | break; 147 | } 148 | // Sign 149 | ret = sample_ecdsa_sign((uint8_t *)&p_attestation_verification_report->info_blob.sample_epid_group_status, 150 | sizeof(ias_platform_info_blob_t) - sizeof(sample_ec_sign256_t), 151 | (sample_ec256_private_t *)&g_rk_priv_key, 152 | (sample_ec256_signature_t *)&p_attestation_verification_report->info_blob.signature, 153 | ecc_state); 154 | 155 | if (SAMPLE_SUCCESS != ret) { 156 | Log("Error, sign ga_gb fail", log::error); 157 | ret = SP_INTERNAL_ERROR; 158 | break; 159 | } 160 | 161 | SWAP_ENDIAN_32B(p_attestation_verification_report->info_blob.signature.x); 162 | SWAP_ENDIAN_32B(p_attestation_verification_report->info_blob.signature.y); 163 | 164 | } while (0); 165 | 166 | if (ecc_state) { 167 | sample_ecc256_close_context(ecc_state); 168 | } 169 | 170 | p_attestation_verification_report->pse_status = IAS_PSE_OK; 171 | 172 | // For now, don't simulate the policy reports. 173 | p_attestation_verification_report->policy_report_size = 0; 174 | 175 | return ret; 176 | } 177 | 178 | -------------------------------------------------------------------------------- /Application/Makefile: -------------------------------------------------------------------------------- 1 | ######## SGX SDK Settings ######## 2 | SGX_SDK ?= /opt/intel/sgxsdk 3 | SGX_MODE ?= SIM 4 | SGX_ARCH ?= x64 5 | 6 | ifeq ($(shell getconf LONG_BIT), 32) 7 | SGX_ARCH := x86 8 | else ifeq ($(findstring -m32, $(CXXFLAGS)), -m32) 9 | SGX_ARCH := x86 10 | endif 11 | 12 | ifeq ($(SGX_ARCH), x86) 13 | SGX_COMMON_CFLAGS := -m32 14 | SGX_LIBRARY_PATH := $(SGX_SDK)/lib 15 | SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x86/sgx_sign 16 | SGX_EDGER8R := $(SGX_SDK)/bin/x86/sgx_edger8r 17 | else 18 | SGX_COMMON_CFLAGS := -m64 19 | SGX_LIBRARY_PATH := $(SGX_SDK)/lib64 20 | SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x64/sgx_sign 21 | SGX_EDGER8R := $(SGX_SDK)/bin/x64/sgx_edger8r 22 | endif 23 | 24 | ifeq ($(SGX_DEBUG), 1) 25 | ifeq ($(SGX_PRERELEASE), 1) 26 | $(error Cannot set SGX_DEBUG and SGX_PRERELEASE at the same time!!) 27 | endif 28 | endif 29 | 30 | ifeq ($(SGX_DEBUG), 1) 31 | SGX_COMMON_CFLAGS += -O0 -g 32 | else 33 | SGX_COMMON_CFLAGS += -O2 34 | endif 35 | 36 | ifeq ($(SUPPLIED_KEY_DERIVATION), 1) 37 | SGX_COMMON_CFLAGS += -DSUPPLIED_KEY_DERIVATION 38 | endif 39 | 40 | ######## App Settings ######## 41 | 42 | ifneq ($(SGX_MODE), HW) 43 | Urts_Library_Name := sgx_urts_sim 44 | else 45 | Urts_Library_Name := sgx_urts 46 | endif 47 | 48 | 49 | App_Cpp_Files := isv_app/isv_app.cpp ../Util/LogBase.cpp ../Networking/NetworkManager.cpp ../Networking/Session.cpp ../Networking/Server.cpp \ 50 | ../Networking/Client.cpp ../Networking/NetworkManagerServer.cpp ../GoogleMessages/Messages.pb.cpp ../Networking/AbstractNetworkOps.cpp \ 51 | ../Util/UtilityFunctions.cpp ../Enclave/Enclave.cpp ../MessageHandler/MessageHandler.cpp ../Util/Base64.cpp 52 | 53 | App_Include_Paths := -I../Util -Iservice_provider -I$(SGX_SDK)/include -Iheaders -I../Networking -Iisv_app -I../GoogleMessages -I/usr/local/include -I../Enclave \ 54 | -I../MessageHandler 55 | 56 | App_C_Flags := $(SGX_COMMON_CFLAGS) -fPIC -Wno-attributes $(App_Include_Paths) 57 | 58 | # Three configuration modes - Debug, prerelease, release 59 | # Debug - Macro DEBUG enabled. 60 | # Prerelease - Macro NDEBUG and EDEBUG enabled. 61 | # Release - Macro NDEBUG enabled. 62 | ifeq ($(SGX_DEBUG), 1) 63 | App_C_Flags += -DDEBUG -UNDEBUG -UEDEBUG 64 | else ifeq ($(SGX_PRERELEASE), 1) 65 | App_C_Flags += -DNDEBUG -DEDEBUG -UDEBUG 66 | else 67 | App_C_Flags += -DNDEBUG -UEDEBUG -UDEBUG 68 | endif 69 | 70 | App_Cpp_Flags := $(App_C_Flags) -std=c++11 -DEnableServer 71 | App_Link_Flags := $(SGX_COMMON_CFLAGS) -L$(SGX_LIBRARY_PATH) -l$(Urts_Library_Name) -L. -lsgx_ukey_exchange -lpthread -Wl,-rpath=$(CURDIR)/../sample_libcrypto -Wl,-rpath=$(CURDIR) -llog4cpp -lboost_system -lssl -lcrypto -lboost_thread -lprotobuf -L /usr/local/lib -ljsoncpp 72 | 73 | ifneq ($(SGX_MODE), HW) 74 | App_Link_Flags += -lsgx_uae_service_sim 75 | else 76 | App_Link_Flags += -lsgx_uae_service 77 | endif 78 | 79 | App_Cpp_Objects := $(App_Cpp_Files:.cpp=.o) 80 | 81 | App_Name := app 82 | 83 | 84 | ######## Enclave Settings ######## 85 | ifneq ($(SGX_MODE), HW) 86 | Trts_Library_Name := sgx_trts_sim 87 | Service_Library_Name := sgx_tservice_sim 88 | else 89 | Trts_Library_Name := sgx_trts 90 | Service_Library_Name := sgx_tservice 91 | endif 92 | Crypto_Library_Name := sgx_tcrypto 93 | 94 | Enclave_Cpp_Files := isv_enclave/isv_enclave.cpp 95 | Enclave_Include_Paths := -I$(SGX_SDK)/include -I$(SGX_SDK)/include/tlibc -I$(SGX_SDK)/include/stlport -I$(SGX_SDK)/include/crypto_px/include -I../Enclave/ 96 | 97 | Enclave_C_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Enclave_Include_Paths) 98 | Enclave_Cpp_Flags := $(Enclave_C_Flags) -std=c++11 -nostdinc++ 99 | 100 | # To generate a proper enclave, it is recommended to follow below guideline to link the trusted libraries: 101 | # 1. Link sgx_trts with the `--whole-archive' and `--no-whole-archive' options, 102 | # so that the whole content of trts is included in the enclave. 103 | # 2. For other libraries, you just need to pull the required symbols. 104 | # Use `--start-group' and `--end-group' to link these libraries. 105 | # Do NOT move the libraries linked with `--start-group' and `--end-group' within `--whole-archive' and `--no-whole-archive' options. 106 | # Otherwise, you may get some undesirable errors. 107 | Enclave_Link_Flags := $(SGX_COMMON_CFLAGS) -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ 108 | -Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \ 109 | -Wl,--start-group -lsgx_tstdc -lsgx_tstdcxx -lsgx_tkey_exchange -l$(Crypto_Library_Name) -l$(Service_Library_Name) -Wl,--end-group \ 110 | -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ 111 | -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ 112 | -Wl,--defsym,__ImageBase=0 \ 113 | -Wl,--version-script=isv_enclave/isv_enclave.lds 114 | 115 | Enclave_Cpp_Objects := $(Enclave_Cpp_Files:.cpp=.o) 116 | 117 | Enclave_Name := isv_enclave.so 118 | Signed_Enclave_Name := isv_enclave.signed.so 119 | Enclave_Config_File := isv_enclave/isv_enclave.config.xml 120 | 121 | ifeq ($(SGX_MODE), HW) 122 | ifneq ($(SGX_DEBUG), 1) 123 | ifneq ($(SGX_PRERELEASE), 1) 124 | Build_Mode = HW_RELEASE 125 | endif 126 | endif 127 | endif 128 | 129 | 130 | .PHONY: all run 131 | 132 | ifeq ($(Build_Mode), HW_RELEASE) 133 | all: $(App_Name) $(Enclave_Name) 134 | @echo "The project has been built in release hardware mode." 135 | @echo "Please sign the $(Enclave_Name) first with your signing key before you run the $(App_Name) to launch and access the enclave." 136 | @echo "To sign the enclave use the command:" 137 | @echo " $(SGX_ENCLAVE_SIGNER) sign -key -enclave $(Enclave_Name) -out <$(Signed_Enclave_Name)> -config $(Enclave_Config_File)" 138 | @echo "You can also sign the enclave using an external signing tool." 139 | @echo "To build the project in simulation mode set SGX_MODE=SIM. To build the project in prerelease mode set SGX_PRERELEASE=1 and SGX_MODE=HW." 140 | else 141 | all: $(App_Name) $(Signed_Enclave_Name) 142 | endif 143 | 144 | run: all 145 | ifneq ($(Build_Mode), HW_RELEASE) 146 | @$(CURDIR)/$(App_Name) 147 | @echo "RUN => $(App_Name) [$(SGX_MODE)|$(SGX_ARCH), OK]" 148 | endif 149 | 150 | 151 | ######## App Objects ######## 152 | 153 | isv_app/isv_enclave_u.c: $(SGX_EDGER8R) isv_enclave/isv_enclave.edl 154 | @cd isv_app && $(SGX_EDGER8R) --untrusted ../isv_enclave/isv_enclave.edl --search-path ../isv_enclave --search-path $(SGX_SDK)/include 155 | @echo "GEN => $@" 156 | 157 | isv_app/isv_enclave_u.o: isv_app/isv_enclave_u.c 158 | @$(CC) $(App_C_Flags) -c $< -o $@ 159 | @echo "CC <= $<" 160 | 161 | isv_app/%.o: isv_app/%.cpp 162 | @$(CXX) $(App_Cpp_Flags) -c $< -o $@ 163 | @echo "CXX <= $<" 164 | 165 | ../MessageHandler/%.o: ../MessageHandler/%.cpp 166 | @$(CXX) $(App_Cpp_Flags) -c $< -o $@ 167 | @echo "CXX <= $<" 168 | 169 | ../Util/%.o: ../Util/%.cpp 170 | @$(CXX) $(App_Cpp_Flags) -c $< -o $@ 171 | @echo "CXX <= $<" 172 | 173 | ../Networking/%.o: ../Networking/%.cpp 174 | @$(CXX) $(App_Cpp_Flags) -c $< -o $@ 175 | @echo "CXX <= $<" 176 | 177 | ../Enclave/%.o: ../Enclave/%.cpp 178 | @$(CXX) $(App_Cpp_Flags) -c $< -o $@ 179 | @echo "CXX <= $<" 180 | 181 | $(App_Name): isv_app/isv_enclave_u.o $(App_Cpp_Objects) 182 | @$(CXX) $^ -o $@ $(App_Link_Flags) 183 | @echo "LINK => $@" 184 | 185 | 186 | ######## Enclave Objects ######## 187 | 188 | isv_enclave/isv_enclave_t.c: $(SGX_EDGER8R) isv_enclave/isv_enclave.edl 189 | @cd isv_enclave && $(SGX_EDGER8R) --trusted ../isv_enclave/isv_enclave.edl --search-path ../isv_enclave --search-path $(SGX_SDK)/include 190 | @echo "GEN => $@" 191 | 192 | isv_enclave/isv_enclave_t.o: isv_enclave/isv_enclave_t.c 193 | @$(CC) $(Enclave_C_Flags) -c $< -o $@ 194 | @echo "CC <= $<" 195 | 196 | isv_enclave/%.o: isv_enclave/%.cpp 197 | @$(CXX) $(Enclave_Cpp_Flags) -c $< -o $@ 198 | @echo "CXX <= $<" 199 | 200 | $(Enclave_Name): isv_enclave/isv_enclave_t.o $(Enclave_Cpp_Objects) 201 | @$(CXX) $^ -o $@ $(Enclave_Link_Flags) 202 | @echo "LINK => $@" 203 | 204 | $(Signed_Enclave_Name): $(Enclave_Name) 205 | @$(SGX_ENCLAVE_SIGNER) sign -key isv_enclave/isv_enclave_private.pem -enclave $(Enclave_Name) -out $@ -config $(Enclave_Config_File) 206 | @echo "SIGN => $@" 207 | 208 | .PHONY: clean 209 | 210 | clean: 211 | @rm -f $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) isv_app/isv_enclave_u.* $(Enclave_Cpp_Objects) isv_enclave/isv_enclave_t.* libservice_provider.* $(ServiceProvider_Cpp_Objects) 212 | -------------------------------------------------------------------------------- /Application/isv_enclave/isv_enclave.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "isv_enclave_t.h" 6 | #include "sgx_tkey_exchange.h" 7 | #include "sgx_tcrypto.h" 8 | #include "string.h" 9 | 10 | // This is the public EC key of the SP. The corresponding private EC key is 11 | // used by the SP to sign data used in the remote attestation SIGMA protocol 12 | // to sign channel binding data in MSG2. A successful verification of the 13 | // signature confirms the identity of the SP to the ISV app in remote 14 | // attestation secure channel binding. The public EC key should be hardcoded in 15 | // the enclave or delivered in a trustworthy manner. The use of a spoofed public 16 | // EC key in the remote attestation with secure channel binding session may lead 17 | // to a security compromise. Every different SP the enlcave communicates to 18 | // must have a unique SP public key. Delivery of the SP public key is 19 | // determined by the ISV. The TKE SIGMA protocl expects an Elliptical Curve key 20 | // based on NIST P-256 21 | static const sgx_ec256_public_t g_sp_pub_key = { 22 | { 23 | 0x72, 0x12, 0x8a, 0x7a, 0x17, 0x52, 0x6e, 0xbf, 24 | 0x85, 0xd0, 0x3a, 0x62, 0x37, 0x30, 0xae, 0xad, 25 | 0x3e, 0x3d, 0xaa, 0xee, 0x9c, 0x60, 0x73, 0x1d, 26 | 0xb0, 0x5b, 0xe8, 0x62, 0x1c, 0x4b, 0xeb, 0x38 27 | }, 28 | { 29 | 0xd4, 0x81, 0x40, 0xd9, 0x50, 0xe2, 0x57, 0x7b, 30 | 0x26, 0xee, 0xb7, 0x41, 0xe7, 0xc6, 0x14, 0xe2, 31 | 0x24, 0xb7, 0xbd, 0xc9, 0x03, 0xf2, 0x9a, 0x28, 32 | 0xa8, 0x3c, 0xc8, 0x10, 0x11, 0x14, 0x5e, 0x06 33 | } 34 | 35 | }; 36 | 37 | 38 | #ifdef SUPPLIED_KEY_DERIVATION 39 | 40 | #pragma message ("Supplied key derivation function is used.") 41 | 42 | typedef struct _hash_buffer_t { 43 | uint8_t counter[4]; 44 | sgx_ec256_dh_shared_t shared_secret; 45 | uint8_t algorithm_id[4]; 46 | } hash_buffer_t; 47 | 48 | const char ID_U[] = "SGXRAENCLAVE"; 49 | const char ID_V[] = "SGXRASERVER"; 50 | 51 | // Derive two keys from shared key and key id. 52 | bool derive_key( 53 | const sgx_ec256_dh_shared_t *p_shared_key, 54 | uint8_t key_id, 55 | sgx_ec_key_128bit_t *first_derived_key, 56 | sgx_ec_key_128bit_t *second_derived_key) { 57 | sgx_status_t sgx_ret = SGX_SUCCESS; 58 | hash_buffer_t hash_buffer; 59 | sgx_sha_state_handle_t sha_context; 60 | sgx_sha256_hash_t key_material; 61 | 62 | memset(&hash_buffer, 0, sizeof(hash_buffer_t)); 63 | /* counter in big endian */ 64 | hash_buffer.counter[3] = key_id; 65 | 66 | /*convert from little endian to big endian */ 67 | for (size_t i = 0; i < sizeof(sgx_ec256_dh_shared_t); i++) { 68 | hash_buffer.shared_secret.s[i] = p_shared_key->s[sizeof(p_shared_key->s)-1 - i]; 69 | } 70 | 71 | sgx_ret = sgx_sha256_init(&sha_context); 72 | if (sgx_ret != SGX_SUCCESS) { 73 | return false; 74 | } 75 | sgx_ret = sgx_sha256_update((uint8_t*)&hash_buffer, sizeof(hash_buffer_t), sha_context); 76 | if (sgx_ret != SGX_SUCCESS) { 77 | sgx_sha256_close(sha_context); 78 | return false; 79 | } 80 | sgx_ret = sgx_sha256_update((uint8_t*)&ID_U, sizeof(ID_U), sha_context); 81 | if (sgx_ret != SGX_SUCCESS) { 82 | sgx_sha256_close(sha_context); 83 | return false; 84 | } 85 | sgx_ret = sgx_sha256_update((uint8_t*)&ID_V, sizeof(ID_V), sha_context); 86 | if (sgx_ret != SGX_SUCCESS) { 87 | sgx_sha256_close(sha_context); 88 | return false; 89 | } 90 | sgx_ret = sgx_sha256_get_hash(sha_context, &key_material); 91 | if (sgx_ret != SGX_SUCCESS) { 92 | sgx_sha256_close(sha_context); 93 | return false; 94 | } 95 | sgx_ret = sgx_sha256_close(sha_context); 96 | 97 | assert(sizeof(sgx_ec_key_128bit_t)* 2 == sizeof(sgx_sha256_hash_t)); 98 | memcpy(first_derived_key, &key_material, sizeof(sgx_ec_key_128bit_t)); 99 | memcpy(second_derived_key, (uint8_t*)&key_material + sizeof(sgx_ec_key_128bit_t), sizeof(sgx_ec_key_128bit_t)); 100 | 101 | // memset here can be optimized away by compiler, so please use memset_s on 102 | // windows for production code and similar functions on other OSes. 103 | memset(&key_material, 0, sizeof(sgx_sha256_hash_t)); 104 | 105 | return true; 106 | } 107 | 108 | //isv defined key derivation function id 109 | #define ISV_KDF_ID 2 110 | 111 | typedef enum _derive_key_type_t { 112 | DERIVE_KEY_SMK_SK = 0, 113 | DERIVE_KEY_MK_VK, 114 | } derive_key_type_t; 115 | 116 | sgx_status_t key_derivation(const sgx_ec256_dh_shared_t* shared_key, 117 | uint16_t kdf_id, 118 | sgx_ec_key_128bit_t* smk_key, 119 | sgx_ec_key_128bit_t* sk_key, 120 | sgx_ec_key_128bit_t* mk_key, 121 | sgx_ec_key_128bit_t* vk_key) { 122 | bool derive_ret = false; 123 | 124 | if (NULL == shared_key) { 125 | return SGX_ERROR_INVALID_PARAMETER; 126 | } 127 | 128 | if (ISV_KDF_ID != kdf_id) { 129 | //fprintf(stderr, "\nError, key derivation id mismatch in [%s].", __FUNCTION__); 130 | return SGX_ERROR_KDF_MISMATCH; 131 | } 132 | 133 | derive_ret = derive_key(shared_key, DERIVE_KEY_SMK_SK, 134 | smk_key, sk_key); 135 | if (derive_ret != true) { 136 | //fprintf(stderr, "\nError, derive key fail in [%s].", __FUNCTION__); 137 | return SGX_ERROR_UNEXPECTED; 138 | } 139 | 140 | derive_ret = derive_key(shared_key, DERIVE_KEY_MK_VK, 141 | mk_key, vk_key); 142 | if (derive_ret != true) { 143 | //fprintf(stderr, "\nError, derive key fail in [%s].", __FUNCTION__); 144 | return SGX_ERROR_UNEXPECTED; 145 | } 146 | return SGX_SUCCESS; 147 | } 148 | #else 149 | #pragma message ("Default key derivation function is used.") 150 | #endif 151 | 152 | // This ecall is a wrapper of sgx_ra_init to create the trusted 153 | // KE exchange key context needed for the remote attestation 154 | // SIGMA API's. Input pointers aren't checked since the trusted stubs 155 | // copy them into EPC memory. 156 | // 157 | // @param b_pse Indicates whether the ISV app is using the 158 | // platform services. 159 | // @param p_context Pointer to the location where the returned 160 | // key context is to be copied. 161 | // 162 | // @return Any error return from the create PSE session if b_pse 163 | // is true. 164 | // @return Any error returned from the trusted key exchange API 165 | // for creating a key context. 166 | 167 | sgx_status_t enclave_init_ra( 168 | int b_pse, 169 | sgx_ra_context_t *p_context) { 170 | // isv enclave call to trusted key exchange library. 171 | sgx_status_t ret; 172 | if(b_pse) { 173 | int busy_retry_times = 2; 174 | do { 175 | ret = sgx_create_pse_session(); 176 | } while (ret == SGX_ERROR_BUSY && busy_retry_times--); 177 | if (ret != SGX_SUCCESS) 178 | return ret; 179 | } 180 | #ifdef SUPPLIED_KEY_DERIVATION 181 | ret = sgx_ra_init_ex(&g_sp_pub_key, b_pse, key_derivation, p_context); 182 | #else 183 | ret = sgx_ra_init(&g_sp_pub_key, b_pse, p_context); 184 | #endif 185 | if(b_pse) { 186 | sgx_close_pse_session(); 187 | return ret; 188 | } 189 | return ret; 190 | } 191 | 192 | 193 | // Closes the tKE key context used during the SIGMA key 194 | // exchange. 195 | // 196 | // @param context The trusted KE library key context. 197 | // 198 | // @return Return value from the key context close API 199 | 200 | sgx_status_t SGXAPI enclave_ra_close( 201 | sgx_ra_context_t context) { 202 | sgx_status_t ret; 203 | ret = sgx_ra_close(context); 204 | return ret; 205 | } 206 | 207 | 208 | // Verify the mac sent in att_result_msg from the SP using the 209 | // MK key. Input pointers aren't checked since the trusted stubs 210 | // copy them into EPC memory. 211 | // 212 | // 213 | // @param context The trusted KE library key context. 214 | // @param p_message Pointer to the message used to produce MAC 215 | // @param message_size Size in bytes of the message. 216 | // @param p_mac Pointer to the MAC to compare to. 217 | // @param mac_size Size in bytes of the MAC 218 | // 219 | // @return SGX_ERROR_INVALID_PARAMETER - MAC size is incorrect. 220 | // @return Any error produced by tKE API to get SK key. 221 | // @return Any error produced by the AESCMAC function. 222 | // @return SGX_ERROR_MAC_MISMATCH - MAC compare fails. 223 | 224 | sgx_status_t verify_att_result_mac(sgx_ra_context_t context, 225 | uint8_t* p_message, 226 | size_t message_size, 227 | uint8_t* p_mac, 228 | size_t mac_size) { 229 | sgx_status_t ret; 230 | sgx_ec_key_128bit_t mk_key; 231 | 232 | if(mac_size != sizeof(sgx_mac_t)) { 233 | ret = SGX_ERROR_INVALID_PARAMETER; 234 | return ret; 235 | } 236 | if(message_size > UINT32_MAX) { 237 | ret = SGX_ERROR_INVALID_PARAMETER; 238 | return ret; 239 | } 240 | 241 | do { 242 | uint8_t mac[SGX_CMAC_MAC_SIZE] = {0}; 243 | 244 | ret = sgx_ra_get_keys(context, SGX_RA_KEY_MK, &mk_key); 245 | if(SGX_SUCCESS != ret) { 246 | break; 247 | } 248 | ret = sgx_rijndael128_cmac_msg(&mk_key, 249 | p_message, 250 | (uint32_t)message_size, 251 | &mac); 252 | if(SGX_SUCCESS != ret) { 253 | break; 254 | } 255 | if(0 == consttime_memequal(p_mac, mac, sizeof(mac))) { 256 | ret = SGX_ERROR_MAC_MISMATCH; 257 | break; 258 | } 259 | 260 | } while(0); 261 | 262 | return ret; 263 | } 264 | 265 | 266 | sgx_status_t verify_secret_data ( 267 | sgx_ra_context_t context, 268 | uint8_t *p_secret, 269 | uint32_t secret_size, 270 | uint8_t *p_gcm_mac, 271 | uint32_t max_verification_length, 272 | uint8_t *p_ret) { 273 | sgx_status_t ret = SGX_SUCCESS; 274 | sgx_ec_key_128bit_t sk_key; 275 | 276 | do { 277 | ret = sgx_ra_get_keys(context, SGX_RA_KEY_SK, &sk_key); 278 | if (SGX_SUCCESS != ret) { 279 | break; 280 | } 281 | 282 | uint8_t *decrypted = (uint8_t*) malloc(sizeof(uint8_t) * secret_size); 283 | uint8_t aes_gcm_iv[12] = {0}; 284 | 285 | ret = sgx_rijndael128GCM_decrypt(&sk_key, 286 | p_secret, 287 | secret_size, 288 | decrypted, 289 | &aes_gcm_iv[0], 290 | 12, 291 | NULL, 292 | 0, 293 | (const sgx_aes_gcm_128bit_tag_t *) (p_gcm_mac)); 294 | 295 | if (SGX_SUCCESS == ret) { 296 | if (decrypted[0] == 0) { 297 | if (decrypted[1] != 1) { 298 | ret = SGX_ERROR_INVALID_SIGNATURE; 299 | } 300 | } else { 301 | ret = SGX_ERROR_UNEXPECTED; 302 | } 303 | } 304 | 305 | } while(0); 306 | 307 | return ret; 308 | } 309 | 310 | 311 | 312 | -------------------------------------------------------------------------------- /ServiceProvider/sample_libcrypto/sample_libcrypto.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2016 Intel Corporation. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in 12 | * the documentation and/or other materials provided with the 13 | * distribution. 14 | * * Neither the name of Intel Corporation nor the names of its 15 | * contributors may be used to endorse or promote products derived 16 | * from this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | /** 33 | * File: sample_libcrypto.h 34 | * Description: 35 | * Interface for generic crypto library APIs. 36 | * Do NOT use this library in your actual product. 37 | * The purpose of this sample library is to aid the debugging of a 38 | * remote attestation service. 39 | * To achieve that goal, the sample remote attestation application 40 | * will use this sample library to generate reproducible messages. 41 | */ 42 | 43 | #ifndef SAMPLE_LIBCRYPTO_H 44 | #define SAMPLE_LIBCRYPTO_H 45 | 46 | #include 47 | 48 | typedef enum sample_status_t 49 | { 50 | SAMPLE_SUCCESS = 0, 51 | 52 | SAMPLE_ERROR_UNEXPECTED , // Unexpected error 53 | SAMPLE_ERROR_INVALID_PARAMETER , // The parameter is incorrect 54 | SAMPLE_ERROR_OUT_OF_MEMORY , // Not enough memory is available to complete this operation 55 | 56 | } sample_status_t; 57 | 58 | #define SAMPLE_SHA256_HASH_SIZE 32 59 | #define SAMPLE_ECP256_KEY_SIZE 32 60 | #define SAMPLE_NISTP_ECP256_KEY_SIZE (SAMPLE_ECP256_KEY_SIZE/sizeof(uint32_t)) 61 | #define SAMPLE_AESGCM_IV_SIZE 12 62 | #define SAMPLE_AESGCM_KEY_SIZE 16 63 | #define SAMPLE_AESGCM_MAC_SIZE 16 64 | #define SAMPLE_CMAC_KEY_SIZE 16 65 | #define SAMPLE_CMAC_MAC_SIZE 16 66 | #define SAMPLE_AESCTR_KEY_SIZE 16 67 | 68 | typedef struct sample_ec256_dh_shared_t 69 | { 70 | uint8_t s[SAMPLE_ECP256_KEY_SIZE]; 71 | } sample_ec256_dh_shared_t; 72 | 73 | typedef struct sample_ec256_private_t 74 | { 75 | uint8_t r[SAMPLE_ECP256_KEY_SIZE]; 76 | } sample_ec256_private_t; 77 | 78 | typedef struct sample_ec256_public_t 79 | { 80 | uint8_t gx[SAMPLE_ECP256_KEY_SIZE]; 81 | uint8_t gy[SAMPLE_ECP256_KEY_SIZE]; 82 | } sample_ec256_public_t; 83 | 84 | typedef struct sample_ec256_signature_t 85 | { 86 | uint32_t x[SAMPLE_NISTP_ECP256_KEY_SIZE]; 87 | uint32_t y[SAMPLE_NISTP_ECP256_KEY_SIZE]; 88 | } sample_ec256_signature_t; 89 | 90 | typedef void* sample_sha_state_handle_t; 91 | typedef void* sample_cmac_state_handle_t; 92 | typedef void* sample_ecc_state_handle_t; 93 | 94 | typedef uint8_t sample_sha256_hash_t[SAMPLE_SHA256_HASH_SIZE]; 95 | 96 | typedef uint8_t sample_aes_gcm_128bit_key_t[SAMPLE_AESGCM_KEY_SIZE]; 97 | typedef uint8_t sample_aes_gcm_128bit_tag_t[SAMPLE_AESGCM_MAC_SIZE]; 98 | typedef uint8_t sample_cmac_128bit_key_t[SAMPLE_CMAC_KEY_SIZE]; 99 | typedef uint8_t sample_cmac_128bit_tag_t[SAMPLE_CMAC_MAC_SIZE]; 100 | typedef uint8_t sample_aes_ctr_128bit_key_t[SAMPLE_AESCTR_KEY_SIZE]; 101 | 102 | #ifdef __cplusplus 103 | #define EXTERN_C extern "C" 104 | #else 105 | #define EXTERN_C 106 | #endif 107 | 108 | #define SAMPLE_LIBCRYPTO_API EXTERN_C 109 | 110 | /* Rijndael AES-GCM 111 | * Parameters: 112 | * Return: sample_status_t - SAMPLE_SUCCESS on success, error code otherwise. 113 | * Inputs: sample_aes_gcm_128bit_key_t *p_key - Pointer to key used in encryption/decryption operation 114 | * uint8_t *p_src - Pointer to input stream to be encrypted/decrypted 115 | * uint32_t src_len - Length of input stream to be encrypted/decrypted 116 | * uint8_t *p_iv - Pointer to initialization vector to use 117 | * uint32_t iv_len - Length of initialization vector 118 | * uint8_t *p_aad - Pointer to input stream of additional authentication data 119 | * uint32_t aad_len - Length of additional authentication data stream 120 | * sample_aes_gcm_128bit_tag_t *p_in_mac - Pointer to expected MAC in decryption process 121 | * Output: uint8_t *p_dst - Pointer to cipher text. Size of buffer should be >= src_len. 122 | * sample_aes_gcm_128bit_tag_t *p_out_mac - Pointer to MAC generated from encryption process 123 | * NOTE: Wrapper is responsible for confirming decryption tag matches encryption tag */ 124 | SAMPLE_LIBCRYPTO_API sample_status_t sample_rijndael128GCM_encrypt(const sample_aes_gcm_128bit_key_t *p_key, const uint8_t *p_src, uint32_t src_len, 125 | uint8_t *p_dst, const uint8_t *p_iv, uint32_t iv_len, const uint8_t *p_aad, uint32_t aad_len, 126 | sample_aes_gcm_128bit_tag_t *p_out_mac); 127 | 128 | /* Message Authentication - Rijndael 128 CMAC 129 | * Parameters: 130 | * Return: sample_status_t - SAMPLE_SUCCESS on success, error code otherwise. 131 | * Inputs: sample_cmac_128bit_key_t *p_key - Pointer to key used in encryption/decryption operation 132 | * uint8_t *p_src - Pointer to input stream to be MAC 133 | * uint32_t src_len - Length of input stream to be MAC 134 | * Output: sample_cmac_gcm_128bit_tag_t *p_mac - Pointer to resultant MAC */ 135 | SAMPLE_LIBCRYPTO_API sample_status_t sample_rijndael128_cmac_msg(const sample_cmac_128bit_key_t *p_key, const uint8_t *p_src, 136 | uint32_t src_len, sample_cmac_128bit_tag_t *p_mac); 137 | 138 | 139 | 140 | /* 141 | * Elliptic Curve Crytpography - Based on GF(p), 256 bit 142 | */ 143 | /* Allocates and initializes ecc context 144 | * Parameters: 145 | * Return: sample_status_t - SAMPLE_SUCCESS or failure as defined SAMPLE_Error.h. 146 | * Output: sample_ecc_state_handle_t ecc_handle - Handle to ECC crypto system */ 147 | SAMPLE_LIBCRYPTO_API sample_status_t sample_ecc256_open_context(sample_ecc_state_handle_t* ecc_handle); 148 | 149 | /* Cleans up ecc context 150 | * Parameters: 151 | * Return: sample_status_t - SAMPLE_SUCCESS or failure as defined SAMPLE_Error.h. 152 | * Output: sample_ecc_state_handle_t ecc_handle - Handle to ECC crypto system */ 153 | SAMPLE_LIBCRYPTO_API sample_status_t sample_ecc256_close_context(sample_ecc_state_handle_t ecc_handle); 154 | 155 | /* Populates private/public key pair - caller code allocates memory 156 | * Parameters: 157 | * Return: sample_status_t - SAMPLE_SUCCESS on success, error code otherwise. 158 | * Inputs: sample_ecc_state_handle_t ecc_handle - Handle to ECC crypto system 159 | * Outputs: sample_ec256_private_t *p_private - Pointer to the private key 160 | * sample_ec256_public_t *p_public - Pointer to the public key */ 161 | SAMPLE_LIBCRYPTO_API sample_status_t sample_ecc256_create_key_pair(sample_ec256_private_t *p_private, 162 | sample_ec256_public_t *p_public, 163 | sample_ecc_state_handle_t ecc_handle); 164 | 165 | /* Computes DH shared key based on private B key (local) and remote public Ga Key 166 | * Parameters: 167 | * Return: sample_status_t - SAMPLE_SUCCESS on success, error code otherwise. 168 | * Inputs: sample_ecc_state_handle_t ecc_handle - Handle to ECC crypto system 169 | * sample_ec256_private_t *p_private_b - Pointer to the local private key - LITTLE ENDIAN 170 | * sample_ec256_public_t *p_public_ga - Pointer to the remote public key - LITTLE ENDIAN 171 | * Output: sample_ec256_dh_shared_t *p_shared_key - Pointer to the shared DH key - LITTLE ENDIAN 172 | x-coordinate of (privKeyB - pubKeyA) */ 173 | SAMPLE_LIBCRYPTO_API sample_status_t sample_ecc256_compute_shared_dhkey(sample_ec256_private_t *p_private_b, 174 | sample_ec256_public_t *p_public_ga, 175 | sample_ec256_dh_shared_t *p_shared_key, 176 | sample_ecc_state_handle_t ecc_handle); 177 | 178 | 179 | /* Computes signature for data based on private key 180 | * 181 | * A message digest is a fixed size number derived from the original message with 182 | * an applied hash function over the binary code of the message. (SHA256 in this case) 183 | * The signer's private key and the message digest are used to create a signature. 184 | * 185 | * A digital signature over a message consists of a pair of large numbers, 256-bits each, 186 | * which the given function computes. 187 | * 188 | * The scheme used for computing a digital signature is of the ECDSA scheme, 189 | * an elliptic curve of the DSA scheme. 190 | * 191 | * The keys can be generated and set up by the function: sgx_ecc256_create_key_pair. 192 | * 193 | * The elliptic curve domain parameters must be created by function: 194 | * sample_ecc256_open_context 195 | * 196 | * Return: If context, private key, signature or data pointer is NULL, 197 | * SAMPLE_ERROR_INVALID_PARAMETER is returned. 198 | * If the signature creation process fails then SAMPLE_ERROR_UNEXPECTED is returned. 199 | * 200 | * Parameters: 201 | * Return: sample_status_t - SAMPLE_SUCCESS, success, error code otherwise. 202 | * Inputs: sample_ecc_state_handle_t ecc_handle - Handle to the ECC crypto system 203 | * sample_ec256_private_t *p_private - Pointer to the private key - LITTLE ENDIAN 204 | * uint8_t *p_data - Pointer to the data to be signed 205 | * uint32_t data_size - Size of the data to be signed 206 | * Output: ec256_signature_t *p_signature - Pointer to the signature - LITTLE ENDIAN */ 207 | SAMPLE_LIBCRYPTO_API sample_status_t sample_ecdsa_sign(const uint8_t *p_data, 208 | uint32_t data_size, 209 | sample_ec256_private_t *p_private, 210 | sample_ec256_signature_t *p_signature, 211 | sample_ecc_state_handle_t ecc_handle); 212 | 213 | /* Allocates and initializes sha256 state 214 | * Parameters: 215 | * Return: sample_status_t - SAMPLE_SUCCESS on success, error code otherwise. 216 | * Output: sample_sha_state_handle_t sha_handle - Handle to the SHA256 state */ 217 | SAMPLE_LIBCRYPTO_API sample_status_t sample_sha256_init(sample_sha_state_handle_t* p_sha_handle); 218 | 219 | /* Updates sha256 has calculation based on the input message 220 | * Parameters: 221 | * Return: sample_status_t - SAMPLE_SUCCESS or failure. 222 | * Input: sample_sha_state_handle_t sha_handle - Handle to the SHA256 state 223 | * uint8_t *p_src - Pointer to the input stream to be hashed 224 | * uint32_t src_len - Length of the input stream to be hashed */ 225 | SAMPLE_LIBCRYPTO_API sample_status_t sample_sha256_update(const uint8_t *p_src, uint32_t src_len, sample_sha_state_handle_t sha_handle); 226 | 227 | /* Returns Hash calculation 228 | * Parameters: 229 | * Return: sample_status_t - SAMPLE_SUCCESS on success, error code otherwise. 230 | * Input: sample_sha_state_handle_t sha_handle - Handle to the SHA256 state 231 | * Output: sample_sha256_hash_t *p_hash - Resultant hash from operation */ 232 | SAMPLE_LIBCRYPTO_API sample_status_t sample_sha256_get_hash(sample_sha_state_handle_t sha_handle, sample_sha256_hash_t *p_hash); 233 | 234 | /* Cleans up sha state 235 | * Parameters: 236 | * Return: sample_status_t - SAMPLE_SUCCESS on success, error code otherwise. 237 | * Input: sample_sha_state_handle_t sha_handle - Handle to the SHA256 state */ 238 | SAMPLE_LIBCRYPTO_API sample_status_t sample_sha256_close(sample_sha_state_handle_t sha_handle); 239 | 240 | #endif 241 | -------------------------------------------------------------------------------- /MessageHandler/MessageHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "MessageHandler.h" 2 | 3 | using namespace util; 4 | 5 | MessageHandler::MessageHandler(int port) { 6 | this->nm = NetworkManagerServer::getInstance(port); 7 | } 8 | 9 | MessageHandler::~MessageHandler() { 10 | delete this->enclave; 11 | } 12 | 13 | 14 | int MessageHandler::init() { 15 | this->nm->Init(); 16 | this->nm->connectCallbackHandler([this](string v, int type) { 17 | return this->incomingHandler(v, type); 18 | }); 19 | } 20 | 21 | 22 | void MessageHandler::start() { 23 | this->nm->startService(); 24 | } 25 | 26 | 27 | sgx_status_t MessageHandler::initEnclave() { 28 | this->enclave = Enclave::getInstance(); 29 | return this->enclave->createEnclave(); 30 | } 31 | 32 | 33 | sgx_status_t MessageHandler::getEnclaveStatus() { 34 | return this->enclave->getStatus(); 35 | } 36 | 37 | 38 | uint32_t MessageHandler::getExtendedEPID_GID(uint32_t *extended_epid_group_id) { 39 | int ret = sgx_get_extended_epid_group_id(extended_epid_group_id); 40 | 41 | if (SGX_SUCCESS != ret) { 42 | Log("Error, call sgx_get_extended_epid_group_id fail: 0x%x", ret); 43 | print_error_message((sgx_status_t)ret); 44 | return ret; 45 | } else 46 | Log("Call sgx_get_extended_epid_group_id success"); 47 | 48 | return ret; 49 | } 50 | 51 | 52 | string MessageHandler::generateMSG0() { 53 | Log("Call MSG0 generate"); 54 | 55 | uint32_t extended_epid_group_id; 56 | int ret = this->getExtendedEPID_GID(&extended_epid_group_id); 57 | 58 | Messages::MessageMsg0 msg; 59 | msg.set_type(RA_MSG0); 60 | 61 | if (ret == SGX_SUCCESS) { 62 | msg.set_epid(extended_epid_group_id); 63 | } else { 64 | msg.set_status(TYPE_TERMINATE); 65 | msg.set_epid(0); 66 | } 67 | return nm->serialize(msg); 68 | } 69 | 70 | 71 | string MessageHandler::generateMSG1() { 72 | int retGIDStatus = 0; 73 | int count = 0; 74 | sgx_ra_msg1_t sgxMsg1Obj; 75 | 76 | while (1) { 77 | retGIDStatus = sgx_ra_get_msg1(this->enclave->getContext(), 78 | this->enclave->getID(), 79 | sgx_ra_get_ga, 80 | &sgxMsg1Obj); 81 | 82 | if (retGIDStatus == SGX_SUCCESS) { 83 | break; 84 | } else if (retGIDStatus == SGX_ERROR_BUSY) { 85 | if (count == 5) { //retried 5 times, so fail out 86 | Log("Error, sgx_ra_get_msg1 is busy - 5 retries failed", log::error); 87 | break;; 88 | } else { 89 | sleep(3); 90 | count++; 91 | } 92 | } else { //error other than busy 93 | Log("Error, failed to generate MSG1", log::error); 94 | break; 95 | } 96 | } 97 | 98 | 99 | if (SGX_SUCCESS == retGIDStatus) { 100 | Log("MSG1 generated Successfully"); 101 | 102 | Messages::MessageMSG1 msg; 103 | msg.set_type(RA_MSG1); 104 | 105 | for (auto x : sgxMsg1Obj.g_a.gx) 106 | msg.add_gax(x); 107 | 108 | for (auto x : sgxMsg1Obj.g_a.gy) 109 | msg.add_gay(x); 110 | 111 | for (auto x : sgxMsg1Obj.gid) { 112 | msg.add_gid(x); 113 | } 114 | 115 | return nm->serialize(msg); 116 | } 117 | 118 | return ""; 119 | } 120 | 121 | 122 | void MessageHandler::assembleMSG2(Messages::MessageMSG2 msg, sgx_ra_msg2_t **pp_msg2) { 123 | uint32_t size = msg.size(); 124 | 125 | sgx_ra_msg2_t *p_msg2 = NULL; 126 | p_msg2 = (sgx_ra_msg2_t*) malloc(size + sizeof(sgx_ra_msg2_t)); 127 | 128 | uint8_t pub_key_gx[32]; 129 | uint8_t pub_key_gy[32]; 130 | 131 | sgx_ec256_signature_t sign_gb_ga; 132 | sgx_spid_t spid; 133 | 134 | for (int i; i<32; i++) { 135 | pub_key_gx[i] = msg.public_key_gx(i); 136 | pub_key_gy[i] = msg.public_key_gy(i); 137 | } 138 | 139 | for (int i=0; i<16; i++) { 140 | spid.id[i] = msg.spid(i); 141 | } 142 | 143 | for (int i=0; i<8; i++) { 144 | sign_gb_ga.x[i] = msg.signature_x(i); 145 | sign_gb_ga.y[i] = msg.signature_y(i); 146 | } 147 | 148 | memcpy(&p_msg2->g_b.gx, &pub_key_gx, sizeof(pub_key_gx)); 149 | memcpy(&p_msg2->g_b.gy, &pub_key_gy, sizeof(pub_key_gy)); 150 | memcpy(&p_msg2->sign_gb_ga, &sign_gb_ga, sizeof(sign_gb_ga)); 151 | memcpy(&p_msg2->spid, &spid, sizeof(spid)); 152 | 153 | p_msg2->quote_type = (uint16_t)msg.quote_type(); 154 | p_msg2->kdf_id = msg.cmac_kdf_id(); 155 | 156 | uint8_t smac[16]; 157 | for (int i=0; i<16; i++) 158 | smac[i] = msg.smac(i); 159 | 160 | memcpy(&p_msg2->mac, &smac, sizeof(smac)); 161 | 162 | p_msg2->sig_rl_size = msg.size_sigrl(); 163 | uint8_t *sigrl = (uint8_t*) malloc(sizeof(uint8_t) * msg.size_sigrl()); 164 | 165 | for (int i=0; isig_rl, &sigrl, msg.size_sigrl()); 169 | 170 | *pp_msg2 = p_msg2; 171 | } 172 | 173 | 174 | string MessageHandler::handleMSG2(Messages::MessageMSG2 msg) { 175 | Log("Received MSG2"); 176 | 177 | uint32_t size = msg.size(); 178 | 179 | sgx_ra_msg2_t *p_msg2; 180 | this->assembleMSG2(msg, &p_msg2); 181 | 182 | sgx_ra_msg3_t *p_msg3 = NULL; 183 | uint32_t msg3_size; 184 | int ret = 0; 185 | 186 | do { 187 | ret = sgx_ra_proc_msg2(this->enclave->getContext(), 188 | this->enclave->getID(), 189 | sgx_ra_proc_msg2_trusted, 190 | sgx_ra_get_msg3_trusted, 191 | p_msg2, 192 | size, 193 | &p_msg3, 194 | &msg3_size); 195 | } while (SGX_ERROR_BUSY == ret && busy_retry_time--); 196 | 197 | SafeFree(p_msg2); 198 | 199 | if (SGX_SUCCESS != (sgx_status_t)ret) { 200 | Log("Error, call sgx_ra_proc_msg2 fail, error code: 0x%x", ret); 201 | } else { 202 | Log("Call sgx_ra_proc_msg2 success"); 203 | 204 | Messages::MessageMSG3 msg3; 205 | 206 | msg3.set_type(RA_MSG3); 207 | msg3.set_size(msg3_size); 208 | 209 | for (int i=0; imac[i]); 211 | 212 | for (int i=0; ig_a.gx[i]); 214 | msg3.add_gay_msg3(p_msg3->g_a.gy[i]); 215 | } 216 | 217 | for (int i=0; i<256; i++) { 218 | msg3.add_sec_property(p_msg3->ps_sec_prop.sgx_ps_sec_prop_desc[i]); 219 | } 220 | 221 | 222 | for (int i=0; i<1116; i++) { 223 | msg3.add_quote(p_msg3->quote[i]); 224 | } 225 | 226 | SafeFree(p_msg3); 227 | 228 | return nm->serialize(msg3); 229 | } 230 | 231 | SafeFree(p_msg3); 232 | 233 | return ""; 234 | } 235 | 236 | 237 | void MessageHandler::assembleAttestationMSG(Messages::AttestationMessage msg, ra_samp_response_header_t **pp_att_msg) { 238 | sample_ra_att_result_msg_t *p_att_result_msg = NULL; 239 | ra_samp_response_header_t* p_att_result_msg_full = NULL; 240 | 241 | int total_size = msg.size() + sizeof(ra_samp_response_header_t) + msg.result_size(); 242 | p_att_result_msg_full = (ra_samp_response_header_t*) malloc(total_size); 243 | 244 | memset(p_att_result_msg_full, 0, total_size); 245 | p_att_result_msg_full->type = RA_ATT_RESULT; 246 | p_att_result_msg_full->size = msg.size(); 247 | 248 | p_att_result_msg = (sample_ra_att_result_msg_t *) p_att_result_msg_full->body; 249 | 250 | p_att_result_msg->platform_info_blob.sample_epid_group_status = msg.epid_group_status(); 251 | p_att_result_msg->platform_info_blob.sample_tcb_evaluation_status = msg.tcb_evaluation_status(); 252 | p_att_result_msg->platform_info_blob.pse_evaluation_status = msg.pse_evaluation_status(); 253 | 254 | for (int i=0; iplatform_info_blob.latest_equivalent_tcb_psvn[i] = msg.latest_equivalent_tcb_psvn(i); 256 | 257 | for (int i=0; iplatform_info_blob.latest_pse_isvsvn[i] = msg.latest_pse_isvsvn(i); 259 | 260 | for (int i=0; iplatform_info_blob.latest_psda_svn[i] = msg.latest_psda_svn(i); 262 | 263 | for (int i=0; iplatform_info_blob.performance_rekey_gid[i] = msg.performance_rekey_gid(i); 265 | 266 | for (int i=0; iplatform_info_blob.signature.x[i] = msg.ec_sign256_x(i); 268 | p_att_result_msg->platform_info_blob.signature.y[i] = msg.ec_sign256_y(i); 269 | } 270 | 271 | for (int i=0; imac[i] = msg.mac_smk(i); 273 | 274 | 275 | p_att_result_msg->secret.payload_size = msg.result_size(); 276 | 277 | for (int i=0; i<12; i++) 278 | p_att_result_msg->secret.reserved[i] = msg.reserved(i); 279 | 280 | for (int i=0; isecret.payload_tag[i] = msg.payload_tag(i); 282 | 283 | for (int i=0; isecret.payload_tag[i] = msg.payload_tag(i); 285 | 286 | for (int i=0; isecret.payload[i] = (uint8_t)msg.payload(i); 288 | } 289 | 290 | *pp_att_msg = p_att_result_msg_full; 291 | } 292 | 293 | 294 | string MessageHandler::handleAttestationResult(Messages::AttestationMessage msg) { 295 | Log("Received Attestation result"); 296 | 297 | ra_samp_response_header_t *p_att_result_msg_full = NULL; 298 | this->assembleAttestationMSG(msg, &p_att_result_msg_full); 299 | sample_ra_att_result_msg_t *p_att_result_msg_body = (sample_ra_att_result_msg_t *) ((uint8_t*) p_att_result_msg_full + sizeof(ra_samp_response_header_t)); 300 | 301 | sgx_status_t status; 302 | sgx_status_t ret; 303 | 304 | ret = verify_att_result_mac(this->enclave->getID(), 305 | &status, 306 | this->enclave->getContext(), 307 | (uint8_t*)&p_att_result_msg_body->platform_info_blob, 308 | sizeof(ias_platform_info_blob_t), 309 | (uint8_t*)&p_att_result_msg_body->mac, 310 | sizeof(sgx_mac_t)); 311 | 312 | 313 | if ((SGX_SUCCESS != ret) || (SGX_SUCCESS != status)) { 314 | Log("Error: INTEGRITY FAILED - attestation result message MK based cmac failed", log::error); 315 | return ""; 316 | } 317 | 318 | if (0 != p_att_result_msg_full->status[0] || 0 != p_att_result_msg_full->status[1]) { 319 | Log("Error, attestation mac result message MK based cmac failed", log::error); 320 | } else { 321 | ret = verify_secret_data(this->enclave->getID(), 322 | &status, 323 | this->enclave->getContext(), 324 | p_att_result_msg_body->secret.payload, 325 | p_att_result_msg_body->secret.payload_size, 326 | p_att_result_msg_body->secret.payload_tag, 327 | MAX_VERIFICATION_RESULT, 328 | NULL); 329 | 330 | SafeFree(p_att_result_msg_full); 331 | 332 | if (SGX_SUCCESS != ret) { 333 | Log("Error, attestation result message secret using SK based AESGCM failed", log::error); 334 | print_error_message(ret); 335 | } else if (SGX_SUCCESS != status) { 336 | Log("Error, attestation result message secret using SK based AESGCM failed", log::error); 337 | print_error_message(status); 338 | } else { 339 | Log("Send attestation okay"); 340 | 341 | Messages::InitialMessage msg; 342 | msg.set_type(RA_APP_ATT_OK); 343 | msg.set_size(0); 344 | 345 | return nm->serialize(msg); 346 | } 347 | } 348 | 349 | SafeFree(p_att_result_msg_full); 350 | 351 | return ""; 352 | } 353 | 354 | 355 | string MessageHandler::handleMSG0(Messages::MessageMsg0 msg) { 356 | Log("MSG0 response received"); 357 | 358 | if (msg.status() == TYPE_OK) { 359 | sgx_status_t ret = this->initEnclave(); 360 | 361 | if (SGX_SUCCESS != ret || this->getEnclaveStatus()) { 362 | Log("Error, call enclave_init_ra fail", log::error); 363 | } else { 364 | Log("Call enclave_init_ra success"); 365 | Log("Sending msg1 to remote attestation service provider. Expecting msg2 back"); 366 | 367 | auto ret = this->generateMSG1(); 368 | 369 | return ret; 370 | } 371 | 372 | } else { 373 | Log("MSG0 response status was not OK", log::error); 374 | } 375 | 376 | return ""; 377 | } 378 | 379 | 380 | string MessageHandler::handleVerification() { 381 | Log("Verification request received"); 382 | return this->generateMSG0(); 383 | } 384 | 385 | 386 | string MessageHandler::createInitMsg(int type, string msg) { 387 | Messages::SecretMessage init_msg; 388 | init_msg.set_type(type); 389 | init_msg.set_size(msg.size()); 390 | 391 | return nm->serialize(init_msg); 392 | } 393 | 394 | 395 | vector MessageHandler::incomingHandler(string v, int type) { 396 | vector res; 397 | string s; 398 | bool ret; 399 | 400 | switch (type) { 401 | case RA_VERIFICATION: { //Verification request 402 | Messages::InitialMessage init_msg; 403 | ret = init_msg.ParseFromString(v); 404 | if (ret && init_msg.type() == RA_VERIFICATION) { 405 | s = this->handleVerification(); 406 | res.push_back(to_string(RA_MSG0)); 407 | } 408 | } 409 | break; 410 | case RA_MSG0: { //Reply to MSG0 411 | Messages::MessageMsg0 msg0; 412 | ret = msg0.ParseFromString(v); 413 | if (ret && (msg0.type() == RA_MSG0)) { 414 | s = this->handleMSG0(msg0); 415 | res.push_back(to_string(RA_MSG1)); 416 | } 417 | } 418 | break; 419 | case RA_MSG2: { //MSG2 420 | Messages::MessageMSG2 msg2; 421 | ret = msg2.ParseFromString(v); 422 | if (ret && (msg2.type() == RA_MSG2)) { 423 | s = this->handleMSG2(msg2); 424 | res.push_back(to_string(RA_MSG3)); 425 | } 426 | } 427 | break; 428 | case RA_ATT_RESULT: { //Reply to MSG3 429 | Messages::AttestationMessage att_msg; 430 | ret = att_msg.ParseFromString(v); 431 | if (ret && att_msg.type() == RA_ATT_RESULT) { 432 | s = this->handleAttestationResult(att_msg); 433 | res.push_back(to_string(RA_APP_ATT_OK)); 434 | } 435 | } 436 | break; 437 | default: 438 | Log("Unknown type: %d", type, log::error); 439 | break; 440 | } 441 | 442 | res.push_back(s); 443 | 444 | return res; 445 | } 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | -------------------------------------------------------------------------------- /ServiceProvider/service_provider/ServiceProvider.cpp: -------------------------------------------------------------------------------- 1 | #include "ServiceProvider.h" 2 | #include "sample_libcrypto.h" 3 | #include "../GeneralSettings.h" 4 | 5 | // This is the private EC key of SP, the corresponding public EC key is 6 | // hard coded in isv_enclave. It is based on NIST P-256 curve. 7 | static const sample_ec256_private_t g_sp_priv_key = { 8 | { 9 | 0x90, 0xe7, 0x6c, 0xbb, 0x2d, 0x52, 0xa1, 0xce, 10 | 0x3b, 0x66, 0xde, 0x11, 0x43, 0x9c, 0x87, 0xec, 11 | 0x1f, 0x86, 0x6a, 0x3b, 0x65, 0xb6, 0xae, 0xea, 12 | 0xad, 0x57, 0x34, 0x53, 0xd1, 0x03, 0x8c, 0x01 13 | } 14 | }; 15 | 16 | ServiceProvider::ServiceProvider(WebService *ws) : ws(ws) {} 17 | 18 | ServiceProvider::~ServiceProvider() {} 19 | 20 | 21 | int ServiceProvider::sp_ra_proc_msg0_req(const uint32_t id) { 22 | int ret = -1; 23 | 24 | if (!this->g_is_sp_registered || (this->extended_epid_group_id != id)) { 25 | Log("Received extended EPID group ID: %d", id); 26 | 27 | extended_epid_group_id = id; 28 | this->g_is_sp_registered = true; 29 | ret = SP_OK; 30 | } 31 | 32 | return ret; 33 | } 34 | 35 | 36 | int ServiceProvider::sp_ra_proc_msg1_req(Messages::MessageMSG1 msg1, Messages::MessageMSG2 *msg2) { 37 | ra_samp_response_header_t **pp_msg2; 38 | int ret = 0; 39 | ra_samp_response_header_t* p_msg2_full = NULL; 40 | sgx_ra_msg2_t *p_msg2 = NULL; 41 | sample_ecc_state_handle_t ecc_state = NULL; 42 | sample_status_t sample_ret = SAMPLE_SUCCESS; 43 | bool derive_ret = false; 44 | 45 | if (!g_is_sp_registered) { 46 | return SP_UNSUPPORTED_EXTENDED_EPID_GROUP; 47 | } 48 | 49 | do { 50 | //===================== RETRIEVE SIGRL FROM IAS ======================= 51 | uint8_t GID[4]; 52 | 53 | for (int i=0; i<4; i++) 54 | GID[i] = msg1.gid(i); 55 | 56 | reverse(begin(GID), end(GID)); 57 | 58 | string sigRl; 59 | bool error = false; 60 | error = this->ws->getSigRL(ByteArrayToString(GID, 4), &sigRl); 61 | 62 | if (error) 63 | return SP_RETRIEVE_SIGRL_ERROR; 64 | 65 | uint8_t *sig_rl; 66 | uint32_t sig_rl_size = StringToByteArray(sigRl, &sig_rl); 67 | //===================================================================== 68 | 69 | uint8_t gaXLittleEndian[32]; 70 | uint8_t gaYLittleEndian[32]; 71 | 72 | for (int i=0; i<32; i++) { 73 | gaXLittleEndian[i] = msg1.gax(i); 74 | gaYLittleEndian[i] = msg1.gay(i); 75 | } 76 | 77 | sample_ec256_public_t client_pub_key = {{0},{0}}; 78 | 79 | for (int x=0; xtype = RA_MSG2; 174 | p_msg2_full->size = msg2_size; 175 | 176 | p_msg2_full->status[0] = 0; 177 | p_msg2_full->status[1] = 0; 178 | p_msg2 = (sgx_ra_msg2_t *) p_msg2_full->body; 179 | 180 | 181 | uint8_t *spidBa; 182 | HexStringToByteArray(Settings::spid, &spidBa); 183 | 184 | for (int i=0; i<16; i++) 185 | p_msg2->spid.id[i] = spidBa[i]; 186 | 187 | 188 | // Assemble MSG2 189 | if(memcpy_s(&p_msg2->g_b, sizeof(p_msg2->g_b), &g_sp_db.g_b, sizeof(g_sp_db.g_b))) { 190 | Log("Error, memcpy failed", log::error); 191 | ret = SP_INTERNAL_ERROR; 192 | break; 193 | } 194 | 195 | p_msg2->quote_type = SAMPLE_QUOTE_LINKABLE_SIGNATURE; 196 | p_msg2->kdf_id = AES_CMAC_KDF_ID; 197 | 198 | // Create gb_ga 199 | sgx_ec256_public_t gb_ga[2]; 200 | if (memcpy_s(&gb_ga[0], sizeof(gb_ga[0]), &g_sp_db.g_b, sizeof(g_sp_db.g_b)) || 201 | memcpy_s(&gb_ga[1], sizeof(gb_ga[1]), &g_sp_db.g_a, sizeof(g_sp_db.g_a))) { 202 | Log("Error, memcpy failed", log::error); 203 | ret = SP_INTERNAL_ERROR; 204 | break; 205 | } 206 | 207 | // Sign gb_ga 208 | sample_ret = sample_ecdsa_sign((uint8_t *)&gb_ga, sizeof(gb_ga), 209 | (sample_ec256_private_t *)&g_sp_priv_key, 210 | (sample_ec256_signature_t *)&p_msg2->sign_gb_ga, 211 | ecc_state); 212 | 213 | if (SAMPLE_SUCCESS != sample_ret) { 214 | Log("Error, sign ga_gb fail", log::error); 215 | ret = SP_INTERNAL_ERROR; 216 | break; 217 | } 218 | 219 | 220 | // Generate the CMACsmk for gb||SPID||TYPE||KDF_ID||Sigsp(gb,ga) 221 | uint8_t mac[SAMPLE_EC_MAC_SIZE] = {0}; 222 | uint32_t cmac_size = offsetof(sgx_ra_msg2_t, mac); 223 | sample_ret = sample_rijndael128_cmac_msg(&g_sp_db.smk_key, (uint8_t *)&p_msg2->g_b, cmac_size, &mac); 224 | 225 | if (SAMPLE_SUCCESS != sample_ret) { 226 | Log("Error, cmac fail", log::error); 227 | ret = SP_INTERNAL_ERROR; 228 | break; 229 | } 230 | 231 | if (memcpy_s(&p_msg2->mac, sizeof(p_msg2->mac), mac, sizeof(mac))) { 232 | Log("Error, memcpy failed", log::error); 233 | ret = SP_INTERNAL_ERROR; 234 | break; 235 | } 236 | 237 | if (memcpy_s(&p_msg2->sig_rl[0], sig_rl_size, sig_rl, sig_rl_size)) { 238 | Log("Error, memcpy failed", log::error); 239 | ret = SP_INTERNAL_ERROR; 240 | break; 241 | } 242 | 243 | p_msg2->sig_rl_size = sig_rl_size; 244 | 245 | } while(0); 246 | 247 | 248 | if (ret) { 249 | *pp_msg2 = NULL; 250 | SafeFree(p_msg2_full); 251 | } else { 252 | 253 | //================= SET MSG2 Fields ================ 254 | msg2->set_size(p_msg2_full->size); 255 | 256 | for (auto x : p_msg2->g_b.gx) 257 | msg2->add_public_key_gx(x); 258 | 259 | for (auto x : p_msg2->g_b.gy) 260 | msg2->add_public_key_gy(x); 261 | 262 | for (auto x : p_msg2->spid.id) 263 | msg2->add_spid(x); 264 | 265 | msg2->set_quote_type(SAMPLE_QUOTE_LINKABLE_SIGNATURE); 266 | msg2->set_cmac_kdf_id(AES_CMAC_KDF_ID); 267 | 268 | for (auto x : p_msg2->sign_gb_ga.x) { 269 | msg2->add_signature_x(x); 270 | } 271 | 272 | for (auto x : p_msg2->sign_gb_ga.y) 273 | msg2->add_signature_y(x); 274 | 275 | for (auto x : p_msg2->mac) 276 | msg2->add_smac(x); 277 | 278 | msg2->set_size_sigrl(p_msg2->sig_rl_size); 279 | 280 | for (int i=0; isig_rl_size; i++) 281 | msg2->add_sigrl(p_msg2->sig_rl[i]); 282 | //===================================================== 283 | } 284 | 285 | if (ecc_state) { 286 | sample_ecc256_close_context(ecc_state); 287 | } 288 | 289 | return ret; 290 | } 291 | 292 | 293 | sgx_ra_msg3_t* ServiceProvider::assembleMSG3(Messages::MessageMSG3 msg) { 294 | sgx_ra_msg3_t *p_msg3 = (sgx_ra_msg3_t*) malloc(msg.size()); 295 | 296 | for (int i=0; imac[i] = msg.sgx_mac(i); 298 | 299 | for (int i=0; ig_a.gx[i] = msg.gax_msg3(i); 301 | p_msg3->g_a.gy[i] = msg.gay_msg3(i); 302 | } 303 | 304 | for (int i=0; i<256; i++) 305 | p_msg3->ps_sec_prop.sgx_ps_sec_prop_desc[i] = msg.sec_property(i); 306 | 307 | for (int i=0; i<1116; i++) 308 | p_msg3->quote[i] = msg.quote(i); 309 | 310 | return p_msg3; 311 | } 312 | 313 | 314 | 315 | // Process remote attestation message 3 316 | int ServiceProvider::sp_ra_proc_msg3_req(Messages::MessageMSG3 msg, Messages::AttestationMessage *att_msg) { 317 | int ret = 0; 318 | sample_status_t sample_ret = SAMPLE_SUCCESS; 319 | const uint8_t *p_msg3_cmaced = NULL; 320 | sgx_quote_t *p_quote = NULL; 321 | sample_sha_state_handle_t sha_handle = NULL; 322 | sample_report_data_t report_data = {0}; 323 | sample_ra_att_result_msg_t *p_att_result_msg = NULL; 324 | ra_samp_response_header_t* p_att_result_msg_full = NULL; 325 | uint32_t i; 326 | sgx_ra_msg3_t *p_msg3 = NULL; 327 | uint32_t att_result_msg_size; 328 | int len_hmac_nonce = 0; 329 | 330 | p_msg3 = assembleMSG3(msg); 331 | 332 | // Check to see if we have registered? 333 | if (!g_is_sp_registered) { 334 | Log("Unsupported extended EPID group", log::error); 335 | return -1; 336 | } 337 | 338 | do { 339 | // Compare g_a in message 3 with local g_a. 340 | if (memcmp(&g_sp_db.g_a, &p_msg3->g_a, sizeof(sgx_ec256_public_t))) { 341 | Log("Error, g_a is not same", log::error); 342 | ret = SP_PROTOCOL_ERROR; 343 | break; 344 | } 345 | 346 | //Make sure that msg3_size is bigger than sample_mac_t. 347 | uint32_t mac_size = msg.size() - sizeof(sample_mac_t); 348 | p_msg3_cmaced = reinterpret_cast(p_msg3); 349 | p_msg3_cmaced += sizeof(sample_mac_t); 350 | 351 | // Verify the message mac using SMK 352 | sample_cmac_128bit_tag_t mac = {0}; 353 | sample_ret = sample_rijndael128_cmac_msg(&g_sp_db.smk_key, p_msg3_cmaced, mac_size, &mac); 354 | 355 | if (SAMPLE_SUCCESS != sample_ret) { 356 | Log("Error, cmac fail", log::error); 357 | ret = SP_INTERNAL_ERROR; 358 | break; 359 | } 360 | 361 | if (memcmp(&p_msg3->mac, mac, sizeof(mac))) { 362 | Log("Error, verify cmac fail", log::error); 363 | ret = SP_INTEGRITY_FAILED; 364 | break; 365 | } 366 | 367 | if (memcpy_s(&g_sp_db.ps_sec_prop, sizeof(g_sp_db.ps_sec_prop), &p_msg3->ps_sec_prop, sizeof(p_msg3->ps_sec_prop))) { 368 | Log("Error, memcpy fail", log::error); 369 | ret = SP_INTERNAL_ERROR; 370 | break; 371 | } 372 | 373 | p_quote = (sgx_quote_t *) p_msg3->quote; 374 | 375 | 376 | // Verify the report_data in the Quote matches the expected value. 377 | // The first 32 bytes of report_data are SHA256 HASH of {ga|gb|vk}. 378 | // The second 32 bytes of report_data are set to zero. 379 | sample_ret = sample_sha256_init(&sha_handle); 380 | if (sample_ret != SAMPLE_SUCCESS) { 381 | Log("Error, init hash failed", log::error); 382 | ret = SP_INTERNAL_ERROR; 383 | break; 384 | } 385 | 386 | sample_ret = sample_sha256_update((uint8_t *)&(g_sp_db.g_a), sizeof(g_sp_db.g_a), sha_handle); 387 | if (sample_ret != SAMPLE_SUCCESS) { 388 | Log("Error, udpate hash failed", log::error); 389 | ret = SP_INTERNAL_ERROR; 390 | break; 391 | } 392 | 393 | sample_ret = sample_sha256_update((uint8_t *)&(g_sp_db.g_b), sizeof(g_sp_db.g_b), sha_handle); 394 | if (sample_ret != SAMPLE_SUCCESS) { 395 | Log("Error, udpate hash failed", log::error); 396 | ret = SP_INTERNAL_ERROR; 397 | break; 398 | } 399 | 400 | sample_ret = sample_sha256_update((uint8_t *)&(g_sp_db.vk_key), sizeof(g_sp_db.vk_key), sha_handle); 401 | if (sample_ret != SAMPLE_SUCCESS) { 402 | Log("Error, udpate hash failed", log::error); 403 | ret = SP_INTERNAL_ERROR; 404 | break; 405 | } 406 | 407 | sample_ret = sample_sha256_get_hash(sha_handle, (sample_sha256_hash_t *)&report_data); 408 | if (sample_ret != SAMPLE_SUCCESS) { 409 | Log("Error, Get hash failed", log::error); 410 | ret = SP_INTERNAL_ERROR; 411 | break; 412 | } 413 | 414 | if (memcmp((uint8_t *)&report_data, (uint8_t *)&(p_quote->report_body.report_data), sizeof(report_data))) { 415 | Log("Error, verify hash failed", log::error); 416 | ret = SP_INTEGRITY_FAILED; 417 | break; 418 | } 419 | 420 | // Verify quote with attestation server. 421 | ias_att_report_t attestation_report = {0}; 422 | ret = ias_verify_attestation_evidence(p_msg3->quote, p_msg3->ps_sec_prop.sgx_ps_sec_prop_desc, &attestation_report, ws); 423 | 424 | if (0 != ret) { 425 | ret = SP_IAS_FAILED; 426 | break; 427 | } 428 | 429 | Log("Atestation Report:"); 430 | Log("\tid: %s", attestation_report.id); 431 | Log("\tstatus: %d", attestation_report.status); 432 | Log("\trevocation_reason: %u", attestation_report.revocation_reason); 433 | Log("\tpse_status: %d", attestation_report.pse_status); 434 | 435 | Log("Enclave Report:"); 436 | Log("\tSignature Type: 0x%x", p_quote->sign_type); 437 | Log("\tSignature Basename: %s", ByteArrayToNoHexString(p_quote->basename.name, 32)); 438 | Log("\tattributes.flags: 0x%0lx", p_quote->report_body.attributes.flags); 439 | Log("\tattributes.xfrm: 0x%0lx", p_quote->report_body.attributes.xfrm); 440 | Log("\tmr_enclave: %s", ByteArrayToString(p_quote->report_body.mr_enclave.m, SGX_HASH_SIZE)); 441 | Log("\tmr_signer: %s", ByteArrayToString(p_quote->report_body.mr_signer.m, SGX_HASH_SIZE)); 442 | Log("\tisv_prod_id: 0x%0x", p_quote->report_body.isv_prod_id); 443 | Log("\tisv_svn: 0x%0x", p_quote->report_body.isv_svn); 444 | 445 | 446 | // Respond the client with the results of the attestation. 447 | att_result_msg_size = sizeof(sample_ra_att_result_msg_t); 448 | 449 | p_att_result_msg_full = (ra_samp_response_header_t*) malloc(att_result_msg_size + sizeof(ra_samp_response_header_t) + sizeof(validation_result)); 450 | if (!p_att_result_msg_full) { 451 | Log("Error, out of memory", log::error); 452 | ret = SP_INTERNAL_ERROR; 453 | break; 454 | } 455 | 456 | memset(p_att_result_msg_full, 0, att_result_msg_size + sizeof(ra_samp_response_header_t) + sizeof(validation_result)); 457 | p_att_result_msg_full->type = RA_ATT_RESULT; 458 | p_att_result_msg_full->size = att_result_msg_size; 459 | 460 | if (IAS_QUOTE_OK != attestation_report.status) { 461 | p_att_result_msg_full->status[0] = 0xFF; 462 | } 463 | 464 | if (IAS_PSE_OK != attestation_report.pse_status) { 465 | p_att_result_msg_full->status[1] = 0xFF; 466 | } 467 | 468 | p_att_result_msg = (sample_ra_att_result_msg_t *)p_att_result_msg_full->body; 469 | 470 | bool isv_policy_passed = true; 471 | 472 | p_att_result_msg->platform_info_blob = attestation_report.info_blob; 473 | 474 | // Generate mac based on the mk key. 475 | mac_size = sizeof(ias_platform_info_blob_t); 476 | sample_ret = sample_rijndael128_cmac_msg(&g_sp_db.mk_key, 477 | (const uint8_t*)&p_att_result_msg->platform_info_blob, 478 | mac_size, 479 | &p_att_result_msg->mac); 480 | 481 | if (SAMPLE_SUCCESS != sample_ret) { 482 | Log("Error, cmac fail", log::error); 483 | ret = SP_INTERNAL_ERROR; 484 | break; 485 | } 486 | 487 | // Generate shared secret and encrypt it with SK, if attestation passed. 488 | uint8_t aes_gcm_iv[SAMPLE_SP_IV_SIZE] = {0}; 489 | p_att_result_msg->secret.payload_size = MAX_VERIFICATION_RESULT; 490 | 491 | if ((IAS_QUOTE_OK == attestation_report.status) && 492 | (IAS_PSE_OK == attestation_report.pse_status) && 493 | (isv_policy_passed == true)) { 494 | memset(validation_result, '\0', MAX_VERIFICATION_RESULT); 495 | validation_result[0] = 0; 496 | validation_result[1] = 1; 497 | 498 | ret = sample_rijndael128GCM_encrypt(&g_sp_db.sk_key, 499 | &validation_result[0], 500 | p_att_result_msg->secret.payload_size, 501 | p_att_result_msg->secret.payload, 502 | &aes_gcm_iv[0], 503 | SAMPLE_SP_IV_SIZE, 504 | NULL, 505 | 0, 506 | &p_att_result_msg->secret.payload_tag); 507 | } 508 | 509 | } while(0); 510 | 511 | if (ret) { 512 | SafeFree(p_att_result_msg_full); 513 | return -1; 514 | } else { 515 | att_msg->set_size(att_result_msg_size); 516 | 517 | ias_platform_info_blob_t platform_info_blob = p_att_result_msg->platform_info_blob; 518 | att_msg->set_epid_group_status(platform_info_blob.sample_epid_group_status); 519 | att_msg->set_tcb_evaluation_status(platform_info_blob.sample_tcb_evaluation_status); 520 | att_msg->set_pse_evaluation_status(platform_info_blob.pse_evaluation_status); 521 | 522 | for (int i=0; iadd_latest_equivalent_tcb_psvn(platform_info_blob.latest_equivalent_tcb_psvn[i]); 524 | 525 | for (int i=0; iadd_latest_pse_isvsvn(platform_info_blob.latest_pse_isvsvn[i]); 527 | 528 | for (int i=0; iadd_latest_psda_svn(platform_info_blob.latest_psda_svn[i]); 530 | 531 | for (int i=0; iadd_performance_rekey_gid(platform_info_blob.performance_rekey_gid[i]); 533 | 534 | for (int i=0; iadd_ec_sign256_x(platform_info_blob.signature.x[i]); 536 | att_msg->add_ec_sign256_y(platform_info_blob.signature.y[i]); 537 | } 538 | 539 | for (int i=0; iadd_mac_smk(p_att_result_msg->mac[i]); 541 | 542 | att_msg->set_result_size(p_att_result_msg->secret.payload_size); 543 | 544 | for (int i=0; i<12; i++) 545 | att_msg->add_reserved(p_att_result_msg->secret.reserved[i]); 546 | 547 | for (int i=0; i<16; i++) 548 | att_msg->add_payload_tag(p_att_result_msg->secret.payload_tag[i]); 549 | 550 | for (int i=0; isecret.payload_size; i++) 551 | att_msg->add_payload(p_att_result_msg->secret.payload[i]); 552 | } 553 | 554 | return ret; 555 | } 556 | 557 | --------------------------------------------------------------------------------