#include "WebService.h" #include "../GeneralSettings.h" WebService* WebService::instance = NULL; WebService::WebService() {} WebService::~WebService() { if (curl) curl_easy_cleanup(curl); } WebService* WebService::getInstance() { if (instance == NULL) { instance = new WebService(); } return instance; } void WebService::init() { curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { Log("Curl initialized successfully"); // curl_easy_setopt( curl, CURLOPT_VERBOSE, 1L ); curl_easy_setopt( curl, CURLOPT_SSLCERTTYPE, "PEM"); curl_easy_setopt( curl, CURLOPT_SSLCERT, Settings::ias_crt); curl_easy_setopt( curl, CURLOPT_SSLKEY, Settings::ias_key); curl_easy_setopt( curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); curl_easy_setopt( curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); curl_easy_setopt( curl, CURLOPT_NOPROGRESS, 1L); } else Log("Curl init error", log::error); } vector> WebService::parseJSONfromIAS(string json) { Json::Value root; Json::Reader reader; bool parsingSuccessful = reader.parse(json.c_str(), root); if (!parsingSuccessful) { Log("Failed to parse JSON string from IAS", log::error); return vector>(); } vector> values; string id = root.get("id", "UTF-8" ).asString(); string timestamp = root.get("timestamp", "UTF-8" ).asString(); string epidPseudonym = root.get("epidPseudonym", "UTF-8" ).asString(); string isvEnclaveQuoteStatus = root.get("isvEnclaveQuoteStatus", "UTF-8" ).asString(); values.push_back({"id", id}); values.push_back({"timestamp", timestamp}); values.push_back({"epidPseudonym", epidPseudonym}); values.push_back({"isvEnclaveQuoteStatus", isvEnclaveQuoteStatus}); return values; } string WebService::createJSONforIAS(uint8_t *quote, uint8_t *pseManifest, uint8_t *nonce) { Json::Value request; request["isvEnclaveQuote"] = Base64encodeUint8(quote, 1116); // request["pseManifest"] = Base64encodeUint8(quote, 256); //only needed when enclave has been signed Json::FastWriter fastWriter; string output = fastWriter.write(request); return output; } size_t ias_response_header_parser(void *ptr, size_t size, size_t nmemb, void *userdata) { int parsed_fields = 0, response_status, content_length, ret = size * nmemb; char *x = (char*) calloc(size+1, nmemb); assert(x); memcpy(x, ptr, size * nmemb); parsed_fields = sscanf( x, "HTTP/1.1 %d", &response_status ); if (parsed_fields == 1) { ((ias_response_header_t *) userdata)->response_status = response_status; return ret; } parsed_fields = sscanf( x, "content-length: %d", &content_length ); if (parsed_fields == 1) { ((ias_response_header_t *) userdata)->content_length = content_length; return ret; } char *p_request_id = (char*) calloc(1, REQUEST_ID_MAX_LEN); parsed_fields = sscanf(x, "request-id: %s", p_request_id ); if (parsed_fields == 1) { std::string request_id_str( p_request_id ); ( ( ias_response_header_t * ) userdata )->request_id = request_id_str; return ret; } return ret; } size_t ias_reponse_body_handler( void *ptr, size_t size, size_t nmemb, void *userdata ) { size_t realsize = size * nmemb; ias_response_container_t *ias_response_container = ( ias_response_container_t * ) userdata; ias_response_container->p_response = (char *) realloc(ias_response_container->p_response, ias_response_container->size + realsize + 1); if (ias_response_container->p_response == NULL ) { Log("Unable to allocate extra memory", log::error); return 0; } memcpy( &( ias_response_container->p_response[ias_response_container->size]), ptr, realsize ); ias_response_container->size += realsize; ias_response_container->p_response[ias_response_container->size] = 0; return realsize; } bool WebService::sendToIAS(string url, IAS type, string payload, struct curl_slist *headers, ias_response_container_t *ias_response_container, ias_response_header_t *response_header) { CURLcode res = CURLE_OK; curl_easy_setopt( curl, CURLOPT_URL, url.c_str()); if (headers) { curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.c_str()); } ias_response_container->p_response = (char*) malloc(1); ias_response_container->size = 0; curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, ias_response_header_parser); curl_easy_setopt(curl, CURLOPT_HEADERDATA, response_header); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ias_reponse_body_handler); curl_easy_setopt(curl, CURLOPT_WRITEDATA, ias_response_container); res = curl_easy_perform(curl); if (res != CURLE_OK) { Log("curl_easy_perform() failed: %s", curl_easy_strerror(res)); return false; } return true; } bool WebService::getSigRL(string gid, string *sigrl) { Log("Retrieving SigRL from IAS"); //check if the sigrl for the gid has already been retrieved once -> to save time for (auto x : retrieved_sigrl) { if (x.first == gid) { *sigrl = x.second; return false; } } Log("Gid is %s", gid); ias_response_container_t ias_response_container; ias_response_header_t response_header; string url = Settings::ias_url + "sigrl/" + gid; this->sendToIAS(url, IAS::sigrl, "", NULL, &ias_response_container, &response_header); Log("\tResponse status is: %d" , response_header.response_status); Log("\tContent-Length: %d", response_header.content_length); if (response_header.response_status == 200) { if (response_header.content_length > 0) { string response(ias_response_container.p_response); *sigrl = Base64decode(response); } retrieved_sigrl.push_back({gid, *sigrl}); } else return true; return false; } bool WebService::verifyQuote(uint8_t *quote, uint8_t *pseManifest, uint8_t *nonce, vector> *result) { string encoded_quote = this->createJSONforIAS(quote, pseManifest, nonce); ias_response_container_t ias_response_container; ias_response_header_t response_header; struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Content-Type: application/json"); string payload = encoded_quote; string url = Settings::ias_url + "report"; this->sendToIAS(url, IAS::report, payload, headers, &ias_response_container, &response_header); if (response_header.response_status == 200) { Log("Quote attestation successful, new report has been created"); string response(ias_response_container.p_response); auto res = parseJSONfromIAS(response); *result = res; } else { Log("Quote attestation returned status: %d", response_header.response_status); return true; } return false; }