enclave_platform.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. /* Copyright (C) 2019, Texas A&M University.
  2. This file is part of Graphene Library OS.
  3. Graphene Library OS is free software: you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public License
  5. as published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. Graphene Library OS is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  13. #include <pal_linux.h>
  14. #include <pal_linux_error.h>
  15. #include <pal_internal.h>
  16. #include <pal_debug.h>
  17. #include <pal_security.h>
  18. #include <pal_crypto.h>
  19. #include <api.h>
  20. #include "quote/generated-cacert.h"
  21. /*
  22. * Graphene's simple remote attestation feature:
  23. *
  24. * This feature is for verifying the SGX hardware platforms for executing applications
  25. * in Graphene, to a remote trusted entity. The whole remote attestation process requires
  26. * interaction with the Intel Attestation Service (IAS) and Intel PSW enclave for
  27. * generating the remote and local quotes. Once the platform is fully verified, Graphene
  28. * will continue to initialize the library OS and the application; otherwise the execution
  29. * should terminate.
  30. *
  31. * Graphene's remote attestation process is meant to be transparent to the application;
  32. * that is, no change is required to the source code or binary of the application. The
  33. * remote attestation feature is enabled if "sgx.ra_client_spid" and "sgx.ra_client_key"
  34. * are specified in the manifest. To obtain the SPID and the subscription key, register in
  35. * the Intel API Portal: https://api.portal.trustedservices.intel.com/EPID-attestation.
  36. *
  37. * The remote attestation process contains four steps:
  38. *
  39. * (1) Initialization:
  40. *
  41. * +-------------------+ +-----------+ +---------+
  42. * | Intel PSW Enclave | target info (PSW) | Untrusted | target info (PSW) | Enclave |
  43. * | (AESMD) |------------------->| PAL |-------------------->| PAL |
  44. * +-------------------+ +-----------+ +---------+
  45. *
  46. * Before the enclave is created, Graphene contacts the AESMD to retrieve the target info
  47. * of the Intel PSW enclave. The target info is used for generating local report later.
  48. *
  49. * (2) OCALL + Local attestation:
  50. *
  51. * +---------+ +-----------+ +-------------------+
  52. * | Enclave | OCALL(GET_ATTESTATION) | Untrusted | Report (PAL->PSW) | Intel PSW Enclave |
  53. * | PAL |----------------------->| PAL |------------------>| (AESMD) |
  54. * +---------+ +-----------+ +-------------------+
  55. *
  56. * The enclave PAL uses ENCLU[EREPORT] to generate a local report for the PSW enclave to
  57. * verify that the two enclaves are on the same platform. The enclave PAL then issues an
  58. * OCALL(GET_ATTESTATION), along with the report, the SPID, and the subscription key.
  59. * The report is given to the PSW enclave to generate a local quote. The PSW enclave will
  60. * verify the report, decide whether to trust the Graphene enclave, and then sign the
  61. * local quote with a PSW-only attestation key.
  62. *
  63. * (3) Contact the IAS for platform report:
  64. *
  65. * The local quote from the PSW enclave needs to be verified by the IAS. Different from the
  66. * Intel SDK model, Graphene does not rely on a third party to contact the IAS.
  67. * Graphene contacts the IAS as part of its remote attestation process.
  68. *
  69. * +-----------+ +--------------+ +---------------+
  70. * | Untrusted | fork + execve | HTTPS client | HTTPS (quote, SPID, key) | Intel Attest. |
  71. * | PAL |-------------->| (CURL) |--------------------------->| Service |
  72. * +-----------+ +--------------+ +---------------+
  73. *
  74. * Graphene now uses a commodity HTTPS client (CURL) to contact the IAS. This is not fully
  75. * compliant to the TOS of the IAS, because the SPID and the key is not protected from
  76. * the untrusted host. The verification of the SGX platform does not require secrecy of the
  77. * SPID/key, because the SPID/key is only used by the IAS to identify the clients. Even if
  78. * an attacker has obtained the SPID/key, the attacker cannot tamper the quote and the IAS
  79. * attestation report.
  80. *
  81. * (4) Checking the IAS report:
  82. *
  83. * +---------------+ +-----------+ HTTPS resp, Certs, +---------+
  84. * | Intel Attest. | HTTPS resp, Certs | Untrusted | Report (PSW->PAL) | Enclave |
  85. * | Service |------------------>| PAL |-------------------->| PAL |
  86. * +---------------+ +-----------+ +---------+
  87. *
  88. * Finally, Graphene returns the HTTPS response and a certificate chain from the IAS
  89. * back to the enclave PAL, along with the local report from the PSW enclave. Graphene
  90. * then verifies the attestation result based on the following criteria:
  91. *
  92. * - The HTTPS response needs to be signed by the certificate chain, including the first
  93. * certificate to generate the signature, and all the following certificates to sign
  94. * the previous certificates.
  95. * - The last certificate in the chain will be signed by a known IAS root CA, hard-coded
  96. * in the enclave PAL.
  97. * - The report from the PSW enclave needs to be verified. This will establish the mutual
  98. * trust between the enclave PAL and the PSW enclave.
  99. * - The HTTPS response from the IAS needs to contain the same quote generated from the
  100. * PSW enclave, the same mr_enclave, attributes, and 64-byte report data.
  101. * - The HTTPS response needs to have an acceptable status, which is "OK" by default, or
  102. * "GROUP_OUT_OF_DATE" if "sgx.ra_accept_group_out_of_date = 1" is in the manifest, or
  103. * "CONFIGURATION_NEEDED" if "sgx.ra_accept_configuration_needed = 1" is in the manifest.
  104. * If you obtain a status besides OK, please see the SECURITY ADVISORIES in README.md.
  105. */
  106. /*
  107. * Perform the initial attestation procedure if "sgx.ra_client.spid" is specified in the manifest
  108. * file.
  109. */
  110. int init_trusted_platform(void) {
  111. char spid_hex[sizeof(sgx_spid_t) * 2 + 1];
  112. ssize_t len =
  113. get_config(pal_state.root_config, "sgx.ra_client_spid", spid_hex, sizeof(spid_hex));
  114. if (len <= 0) {
  115. SGX_DBG(DBG_E,
  116. "*** No client info specified in the manifest. "
  117. "Graphene will not perform remote attestation ***\n");
  118. return 0;
  119. }
  120. if (len != sizeof(sgx_spid_t) * 2) {
  121. SGX_DBG(DBG_E, "Malformed sgx.ra_client_spid value in the manifest: %s\n", spid_hex);
  122. return -PAL_ERROR_INVAL;
  123. }
  124. sgx_spid_t spid;
  125. for (ssize_t i = 0; i < len; i++) {
  126. int8_t val = hex2dec(spid_hex[i]);
  127. if (val < 0) {
  128. SGX_DBG(DBG_E, "Malformed sgx.ra_client_spid value in the manifest: %s\n", spid_hex);
  129. return -PAL_ERROR_INVAL;
  130. }
  131. spid[i / 2] = spid[i / 2] * 16 + (uint8_t)val;
  132. }
  133. char subkey[CONFIG_MAX];
  134. len = get_config(pal_state.root_config, "sgx.ra_client_key", subkey, sizeof(subkey));
  135. if (len <= 0) {
  136. SGX_DBG(DBG_E, "No sgx.ra_client_key in the manifest\n");
  137. return -PAL_ERROR_INVAL;
  138. }
  139. char buf[2];
  140. len = get_config(pal_state.root_config, "sgx.ra_client_linkable", buf, sizeof(buf));
  141. bool linkable = (len == 1 && buf[0] == '1');
  142. len = get_config(pal_state.root_config, "sgx.ra_accept_group_out_of_date", buf, sizeof(buf));
  143. bool accept_group_out_of_date = (len == 1 && buf[0] == '1');
  144. len = get_config(pal_state.root_config, "sgx.ra_accept_configuration_needed", buf, sizeof(buf));
  145. bool accept_configuration_needed = (len == 1 && buf[0] == '1');
  146. sgx_quote_nonce_t nonce;
  147. int ret = _DkRandomBitsRead(&nonce, sizeof(nonce));
  148. if (ret < 0)
  149. return ret;
  150. char* status;
  151. char* timestamp;
  152. ret = sgx_verify_platform(&spid, subkey, &nonce, (sgx_report_data_t*)&pal_enclave_state,
  153. linkable, accept_group_out_of_date, accept_configuration_needed,
  154. /*ret_attestation=*/NULL, &status, &timestamp);
  155. if (ret < 0)
  156. return ret;
  157. // If the attestation is successful, update the control block
  158. __pal_control.attestation_status = status;
  159. __pal_control.attestation_timestamp = timestamp;
  160. return ret;
  161. }
  162. /*
  163. * A simple function to parse a X509 certificate for only the certificate body, the signature,
  164. * and the public key.
  165. *
  166. * TODO: Currently no verification of the X509 certificate.
  167. *
  168. * @cert: The certificate to parse (DER format).
  169. * @cert_len: The length of cert.
  170. * @body: The certificate body (the signed part).
  171. * @body_len: The length of body.
  172. * @sig: The certificate signature.
  173. * @sig_len: The length of sig.
  174. * @pubkey: The RSA public key from the certificate.
  175. */
  176. static int parse_x509(uint8_t* cert, size_t cert_len, uint8_t** body, size_t* body_len,
  177. uint8_t** sig, size_t* sig_len, LIB_RSA_KEY* pubkey) {
  178. uint8_t* ptr = cert;
  179. uint8_t* end = cert + cert_len;
  180. enum asn1_tag tag;
  181. bool is_cons;
  182. uint8_t* buf;
  183. size_t buf_len;
  184. int ret;
  185. // X509Certificate := SEQUENCE {
  186. // Body CertificateBody,
  187. // SignatureAlgorithm AlgorithmDescriptor,
  188. // Signature BIT STRING }
  189. ret = lib_ASN1GetSerial(&ptr, end, &tag, &is_cons, &buf, &buf_len);
  190. if (ret < 0)
  191. return ret;
  192. if (tag != ASN1_SEQUENCE || !is_cons)
  193. return -PAL_ERROR_INVAL;
  194. uint8_t* cert_signed = ptr = buf;
  195. uint8_t* cert_body;
  196. uint8_t* cert_sig;
  197. size_t cert_body_len, cert_sig_len;
  198. end = buf + buf_len;
  199. ret = lib_ASN1GetSerial(&ptr, end, &tag, &is_cons, &cert_body, &cert_body_len);
  200. if (ret < 0)
  201. return ret;
  202. if (tag != ASN1_SEQUENCE || !is_cons)
  203. return -PAL_ERROR_INVAL;
  204. size_t cert_signed_len = ptr - cert_signed;
  205. // Skip SignatureAlgorithm
  206. ret = lib_ASN1GetSerial(&ptr, end, &tag, &is_cons, &buf, &buf_len);
  207. if (ret < 0)
  208. return ret;
  209. ret = lib_ASN1GetBitstring(&ptr, end, &cert_sig, &cert_sig_len);
  210. if (ret < 0)
  211. return ret;
  212. // CertficateBody := SEQUENCE {
  213. // Version CONSTANT,
  214. // SerialNumber INTEGER,
  215. // Signature AlgorithmDiscriptor,
  216. // Issuer Name,
  217. // Validity ValidityTime,
  218. // Subject Name,
  219. // SubjectPublicKeyInfo PublicKeyInfo,
  220. // (optional fields) }
  221. ptr = cert_body;
  222. end = cert_body + cert_body_len;
  223. // Skip Version, SerialNumber, Signature, Issuer, Validity, and Subject
  224. for (int i = 0; i < 6; i++) {
  225. ret = lib_ASN1GetSerial(&ptr, end, &tag, &is_cons, &buf, &buf_len);
  226. if (ret < 0)
  227. return ret;
  228. }
  229. // Get SubjectPublicKeyInfo
  230. ret = lib_ASN1GetSerial(&ptr, end, &tag, &is_cons, &buf, &buf_len);
  231. if (ret < 0)
  232. return ret;
  233. if (tag != ASN1_SEQUENCE || !is_cons)
  234. return -PAL_ERROR_INVAL;
  235. // PublickKeyInfo := SEQUENCE {
  236. // PublicKeyAlgorithm AlgorithmDescriptor,
  237. // PublicKey BIT STRING }
  238. ptr = buf;
  239. end = buf + buf_len;
  240. // Skip PublicKeyAlgorithm
  241. ret = lib_ASN1GetSerial(&ptr, end, &tag, &is_cons, &buf, &buf_len);
  242. if (ret < 0)
  243. return ret;
  244. // Get PublicKey
  245. uint8_t* pkey_bits;
  246. size_t pkey_bits_len;
  247. ret = lib_ASN1GetBitstring(&ptr, end, &pkey_bits, &pkey_bits_len);
  248. if (ret < 0)
  249. return ret;
  250. // RSAPublicKey := SEQUENCE {
  251. // Modulus Integer,
  252. // PublicExponent Integer }
  253. ptr = pkey_bits;
  254. end = pkey_bits + pkey_bits_len;
  255. ret = lib_ASN1GetSerial(&ptr, end, &tag, &is_cons, &buf, &buf_len);
  256. if (ret < 0)
  257. return ret;
  258. uint8_t* mod;
  259. uint8_t* exp;
  260. size_t mod_len, exp_len;
  261. ptr = buf;
  262. end = buf + buf_len;
  263. ret = lib_ASN1GetLargeNumberLength(&ptr, end, &mod_len);
  264. if (ret < 0)
  265. return ret;
  266. mod = ptr;
  267. ptr += mod_len;
  268. ret = lib_ASN1GetLargeNumberLength(&ptr, end, &exp_len);
  269. if (ret < 0)
  270. return ret;
  271. exp = ptr;
  272. ptr += exp_len;
  273. *body = malloc(cert_signed_len);
  274. *body_len = cert_signed_len;
  275. memcpy(*body, cert_signed, cert_signed_len);
  276. *sig = malloc(cert_sig_len);
  277. *sig_len = cert_sig_len;
  278. memcpy(*sig, cert_sig, cert_sig_len);
  279. ret = lib_RSAInitKey(pubkey);
  280. if (ret < 0)
  281. return ret;
  282. ret = lib_RSAImportPublicKey(pubkey, exp, exp_len, mod, mod_len);
  283. if (ret < 0)
  284. return ret;
  285. return 0;
  286. }
  287. /*
  288. * Same as parse_x509(), but parse the certificate in PEM format.
  289. *
  290. * @cert: The starting address for parsing the certificate.
  291. * @cert_end: Returns the end of certificate after parsing.
  292. * @body: The certificate body (the signed part).
  293. * @body_len: The length of body.
  294. * @sig: The certificate signature.
  295. * @sig_len: The length of sig.
  296. * @pubkey: The RSA public key from the certificate.
  297. */
  298. static int parse_x509_pem(char* cert, char** cert_end, uint8_t** body, size_t* body_len,
  299. uint8_t** sig, size_t* sig_len, LIB_RSA_KEY* pubkey) {
  300. int ret;
  301. char* start = strchr(cert, '-');
  302. if (!start) {
  303. // No more certificate
  304. *cert_end = NULL;
  305. return 0;
  306. }
  307. if (!strstartswith_static(start, "-----BEGIN CERTIFICATE-----"))
  308. return -PAL_ERROR_INVAL;
  309. start += static_strlen("-----BEGIN CERTIFICATE-----");
  310. char* end = strchr(start, '-');
  311. if (!strstartswith_static(end, "-----END CERTIFICATE-----"))
  312. return -PAL_ERROR_INVAL;
  313. size_t cert_der_len;
  314. ret = lib_Base64Decode(start, end - start, NULL, &cert_der_len);
  315. if (ret < 0)
  316. return ret;
  317. uint8_t* cert_der = __alloca(cert_der_len);
  318. ret = lib_Base64Decode(start, end - start, cert_der, &cert_der_len);
  319. if (ret < 0)
  320. return ret;
  321. ret = parse_x509(cert_der, cert_der_len, body, body_len, sig, sig_len, pubkey);
  322. if (ret < 0)
  323. return ret;
  324. *cert_end = end + static_strlen("-----END CERTIFICATE-----");
  325. return 0;
  326. }
  327. /*
  328. * Perform the remote attestation to verify the current SGX platform.
  329. *
  330. * The remote attestation procedure verifies two primary properties: (1) The current execution runs
  331. * in an SGX enclave; and (2) The enclave is created on a genuine, up-to-date Intel CPU. This
  332. * procedure requires interaction with the Intel PSW quoting enclave (AESMD) and the Intel
  333. * Attestation Service (IAS). The quoting enclave verifies a local attestation report from the
  334. * target enclave, and then generates a quoting enclave (QE) report and a platform quote signed by
  335. * the platform's attestation key. The IAS then verifies the platform quote and issues a remote
  336. * attestation report, signed by a certificate chain attached to the report.
  337. *
  338. * TODO: currently no verification of the correctness of the IAS certificate
  339. *
  340. * @spid: The SPID registered for the Intel Attestation Service (IAS).
  341. * @subkey: SPID subscription key.
  342. * @nonce: A 16-byte nonce to be included in the quote.
  343. * @report_data: A 64-byte bytestring to be included in the local report and the quote.
  344. * @linkable: Specify whether the SPID is linkable.
  345. * @accept_group_out_of_date: Specify whether to accept GROUP_OUT_OF_DATE from IAS
  346. * @accept_configuration_needed: Specify whether to accept CONFIGURATION_NEEDED from IAS
  347. * @ret_attestation: Returns the retrieved attestation data.
  348. * @ret_ias_status: Returns a pointer to the attestation status (as a string) from the IAS.
  349. * @ret_ias_timestamp: Returns a pointer to the timestamp (as a string) from the IAS.
  350. * Timestamp format: %Y-%m-%dT%H:%M:%S.%f (Ex: 2019-08-01T12:30:00.123456)
  351. */
  352. int sgx_verify_platform(sgx_spid_t* spid, const char* subkey, sgx_quote_nonce_t* nonce,
  353. sgx_report_data_t* report_data, bool linkable,
  354. bool accept_group_out_of_date, bool accept_configuration_needed,
  355. sgx_attestation_t* ret_attestation, char** ret_ias_status,
  356. char** ret_ias_timestamp) {
  357. SGX_DBG(DBG_S, "Request quote:\n");
  358. SGX_DBG(DBG_S, " spid: %s\n", ALLOCA_BYTES2HEXSTR(*spid));
  359. SGX_DBG(DBG_S, " type: %s\n", linkable ? "linkable" : "unlinkable");
  360. SGX_DBG(DBG_S, " nonce: %s\n", ALLOCA_BYTES2HEXSTR(*nonce));
  361. __sgx_mem_aligned sgx_report_t report;
  362. __sgx_mem_aligned sgx_target_info_t targetinfo = pal_sec.aesm_targetinfo;
  363. int ret = sgx_report(&targetinfo, report_data, &report);
  364. if (ret) {
  365. SGX_DBG(DBG_E, "Failed to get report for attestation\n");
  366. return -PAL_ERROR_DENIED;
  367. }
  368. sgx_attestation_t attestation;
  369. ret = ocall_get_attestation(spid, subkey, linkable, &report, nonce, &attestation);
  370. if (ret < 0) {
  371. SGX_DBG(DBG_E, "Failed to get attestation\n");
  372. return ret;
  373. }
  374. // First, verify the report from the quoting enclave
  375. ret = sgx_verify_report(&attestation.qe_report);
  376. if (ret < 0) {
  377. SGX_DBG(DBG_E, "Failed to verify QE report, ret = %d\n", ret);
  378. goto failed;
  379. }
  380. // Verify the IAS response against the certificate chain
  381. uint8_t* data_to_verify = (uint8_t*)attestation.ias_report;
  382. uint8_t* data_sig = attestation.ias_sig;
  383. size_t data_len = attestation.ias_report_len;
  384. size_t data_sig_len = attestation.ias_sig_len;
  385. // Attach the IAS signing chain with the hard-coded CA certificate
  386. const char* ca_cert = IAS_CA_CERT;
  387. size_t len1 = strlen(attestation.ias_certs);
  388. size_t len2 = static_strlen(IAS_CA_CERT);
  389. char* certs = malloc(len1 + len2 + 1);
  390. memcpy(certs, attestation.ias_certs, len1);
  391. memcpy(certs + len1, ca_cert, len2);
  392. certs[len1 + len2] = 0;
  393. free(attestation.ias_certs);
  394. attestation.ias_certs = certs;
  395. attestation.ias_certs_len = len1 + len2 + 1;
  396. // There can be multiple certificates in the chain. We need to use the public key from the
  397. // *first* certificate to verify the IAS response. For each certificate except the last one, we
  398. // need to use the public key from the *next* certificate to verify the certificate body. The
  399. // last certificate will be verified by the CA certificate (hard-coded in the binary)
  400. for (char* cert_start = attestation.ias_certs;
  401. cert_start < attestation.ias_certs + attestation.ias_certs_len && *cert_start;) {
  402. // Generate the message digest first (without RSA)
  403. LIB_SHA256_CONTEXT ctx;
  404. uint8_t hash[32];
  405. if ((ret = lib_SHA256Init(&ctx)) < 0)
  406. goto failed;
  407. if ((ret = lib_SHA256Update(&ctx, data_to_verify, data_len)) < 0)
  408. goto failed;
  409. if ((ret = lib_SHA256Final(&ctx, hash)) < 0)
  410. goto failed;
  411. // Use the public key to verify the last signature
  412. uint8_t* cert_body;
  413. uint8_t* cert_sig;
  414. size_t cert_body_len;
  415. size_t cert_sig_len;
  416. LIB_RSA_KEY cert_key;
  417. ret = parse_x509_pem(cert_start, &cert_start, &cert_body, &cert_body_len, &cert_sig,
  418. &cert_sig_len, &cert_key);
  419. if (ret < 0) {
  420. SGX_DBG(DBG_E, "Failed to parse IAS certificate, rv = %d\n", ret);
  421. goto failed;
  422. }
  423. ret = lib_RSAVerifySHA256(&cert_key, hash, sizeof(hash), data_sig, data_sig_len);
  424. if (ret < 0) {
  425. SGX_DBG(DBG_E,
  426. "Failed to verify the report against the IAS certificates, rv = %d\n",
  427. ret);
  428. lib_RSAFreeKey(&cert_key);
  429. goto failed;
  430. }
  431. lib_RSAFreeKey(&cert_key);
  432. data_to_verify = cert_body;
  433. data_sig = cert_sig;
  434. data_len = cert_body_len;
  435. data_sig_len = cert_sig_len;
  436. }
  437. // Parse the IAS report in JSON format
  438. char* ias_status = NULL;
  439. char* ias_timestamp = NULL;
  440. sgx_quote_nonce_t* ias_nonce = NULL;
  441. sgx_quote_t* ias_quote = NULL;
  442. char* start = attestation.ias_report;
  443. if (start[0] == '{')
  444. start++;
  445. char* end = strchr(start, ',');
  446. while (end) {
  447. char* next_start = end + 1;
  448. // Retrieve the key and value separated by the colon (:)
  449. char* delim = strchr(start, ':');
  450. if (!delim)
  451. break;
  452. char* key = start;
  453. char* val = delim + 1;
  454. size_t klen = delim - start;
  455. size_t vlen = end - val;
  456. // Remove quotation marks (") around the key and value if there are any
  457. if (key[0] == '"') {
  458. key++;
  459. klen--;
  460. }
  461. if (key[klen - 1] == '"')
  462. klen--;
  463. if (val[0] == '"') {
  464. val++;
  465. vlen--;
  466. }
  467. if (val[vlen - 1] == '"')
  468. vlen--;
  469. // Scan the fields in the IAS report.
  470. if (!memcmp(key, "isvEnclaveQuoteStatus", klen)) {
  471. // Parse "isvEnclaveQuoteStatus":"OK"|"GROUP_OUT_OF_DATE"|...
  472. ias_status = __alloca(vlen + 1);
  473. memcpy(ias_status, val, vlen);
  474. ias_status[vlen] = 0;
  475. } else if (!memcmp(key, "nonce", klen)) {
  476. // Parse "nonce":"{Hex representation of the initial nonce}"
  477. if (vlen != sizeof(sgx_quote_nonce_t) * 2) {
  478. SGX_DBG(DBG_E, "Malformed nonce in the IAS report\n");
  479. goto failed;
  480. }
  481. ias_nonce = __alloca(sizeof(sgx_quote_nonce_t));
  482. for (size_t i = 0; i < sizeof(sgx_quote_nonce_t); i++) {
  483. int8_t hi = hex2dec(val[i * 2]);
  484. int8_t lo = hex2dec(val[i * 2 + 1]);
  485. if (hi < 0 || lo < 0) {
  486. SGX_DBG(DBG_E, "Malformed nonce in the IAS report\n");
  487. goto failed;
  488. }
  489. ((uint8_t*)ias_nonce)[i] = (uint8_t)hi * 16 + (uint8_t)lo;
  490. }
  491. } else if (!memcmp(key, "timestamp", klen)) {
  492. // Parse "timestamp":"{IAS timestamp (format: %Y-%m-%dT%H:%M:%S.%f)}"
  493. ias_timestamp = __alloca(vlen + 1);
  494. memcpy(ias_timestamp, val, vlen);
  495. ias_timestamp[vlen] = 0;
  496. } else if (!memcmp(key, "isvEnclaveQuoteBody", klen)) {
  497. // Parse "isvEnclaveQuoteBody":"{Quote body (in Base64 format)}"
  498. size_t ias_quote_len;
  499. ret = lib_Base64Decode(val, vlen, NULL, &ias_quote_len);
  500. if (ret < 0) {
  501. SGX_DBG(DBG_E, "Malformed quote in the IAS report\n");
  502. goto failed;
  503. }
  504. ias_quote = __alloca(ias_quote_len);
  505. ret = lib_Base64Decode(val, vlen, (uint8_t*)ias_quote, &ias_quote_len);
  506. if (ret < 0) {
  507. SGX_DBG(DBG_E, "Malformed quote in the IAS report\n");
  508. goto failed;
  509. }
  510. }
  511. start = next_start;
  512. end = strchr(start, ',') ?: strchr(start, '}');
  513. }
  514. if (!ias_status || !ias_nonce || !ias_timestamp || !ias_quote) {
  515. SGX_DBG(DBG_E, "Missing important field(s) in the IAS report\n");
  516. goto failed;
  517. }
  518. SGX_DBG(DBG_S, "Quote:\n");
  519. SGX_DBG(DBG_S, " version: %04x\n", ias_quote->body.version);
  520. SGX_DBG(DBG_S, " sigtype: %04x\n", ias_quote->body.sigtype);
  521. SGX_DBG(DBG_S, " gid: %08x\n", ias_quote->body.gid);
  522. SGX_DBG(DBG_S, " isvsvn qe: %08x\n", ias_quote->body.isvsvn_qe);
  523. SGX_DBG(DBG_S, " isvsvn pce: %08x\n", ias_quote->body.isvsvn_pce);
  524. SGX_DBG(DBG_S, "IAS report: %s\n", attestation.ias_report);
  525. SGX_DBG(DBG_S, " status: %s\n", ias_status);
  526. SGX_DBG(DBG_S, " timestamp: %s\n", ias_timestamp);
  527. // Only accept status to be "OK" or "GROUP_OUT_OF_DATE" / "CONFIGURATION_NEEDED" (if
  528. // accept_out_of_date / accept_configuration_needed is true)
  529. if (strcmp_static(ias_status, "OK") &&
  530. (!accept_group_out_of_date || strcmp_static(ias_status, "GROUP_OUT_OF_DATE")) &&
  531. (!accept_configuration_needed || strcmp_static(ias_status, "CONFIGURATION_NEEDED"))) {
  532. SGX_DBG(DBG_E, "IAS returned invalid status: %s\n", ias_status);
  533. goto failed;
  534. }
  535. // Check if the nonce matches the IAS report
  536. if (memcmp(ias_nonce, nonce, sizeof(sgx_quote_nonce_t))) {
  537. SGX_DBG(DBG_E, "IAS returned the wrong nonce\n");
  538. goto failed;
  539. }
  540. // Check if the quote matches the IAS report
  541. if (memcmp(&ias_quote->body, &attestation.quote->body, sizeof(sgx_quote_body_t)) ||
  542. memcmp(&ias_quote->report_body, &report.body, sizeof(sgx_report_body_t))) {
  543. SGX_DBG(DBG_E, "IAS returned the wrong quote\n");
  544. goto failed;
  545. }
  546. // Check if the quote has the right enclave report
  547. if (memcmp(&attestation.quote->report_body, &report.body, sizeof(sgx_report_body_t))) {
  548. SGX_DBG(DBG_E, "The returned quote contains the wrong enclave report\n");
  549. goto failed;
  550. }
  551. // Succeeded!!!
  552. if (ret_ias_status) {
  553. size_t len = strlen(ias_status) + 1;
  554. *ret_ias_status = malloc(len);
  555. memcpy(*ret_ias_status, ias_status, len);
  556. }
  557. if (ret_ias_timestamp) {
  558. size_t len = strlen(ias_timestamp) + 1;
  559. *ret_ias_timestamp = malloc(len);
  560. memcpy(*ret_ias_timestamp, ias_timestamp, len);
  561. }
  562. if (ret_attestation) {
  563. memcpy(ret_attestation, &attestation, sizeof(sgx_attestation_t));
  564. return 0;
  565. }
  566. ret = 0;
  567. free_attestation:
  568. if (attestation.quote)
  569. free(attestation.quote);
  570. if (attestation.ias_report)
  571. free(attestation.ias_report);
  572. if (attestation.ias_sig)
  573. free(attestation.ias_sig);
  574. if (attestation.ias_certs)
  575. free(attestation.ias_certs);
  576. return ret;
  577. failed:
  578. ret = -PAL_ERROR_DENIED;
  579. goto free_attestation;
  580. }