enclave_platform.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  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 mrenclave, 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.
  103. * If you obtain a status besides OK, please see the SECURITY ADVISORIES in README.md.
  104. */
  105. /*
  106. * Perform the initial attestation procedure if "sgx.ra_client.spid" is specified in
  107. * the manifest file.
  108. */
  109. int init_trusted_platform(void) {
  110. char spid_hex[sizeof(sgx_spid_t) * 2 + 1];
  111. ssize_t len = get_config(pal_state.root_config, "sgx.ra_client_spid", spid_hex,
  112. sizeof(spid_hex));
  113. if (len <= 0) {
  114. SGX_DBG(DBG_E, "*** No client info specified in the manifest. "
  115. "Graphene will not perform remote attestation ***\n");
  116. return 0;
  117. }
  118. if (len != sizeof(sgx_spid_t) * 2) {
  119. SGX_DBG(DBG_E, "Malformed sgx.ra_client_spid value in the manifest: %s\n", spid_hex);
  120. return -PAL_ERROR_INVAL;
  121. }
  122. sgx_spid_t spid;
  123. for (ssize_t i = 0; i < len; i++) {
  124. int8_t val = hex2dec(spid_hex[i]);
  125. if (val < 0) {
  126. SGX_DBG(DBG_E, "Malformed sgx.ra_client_spid value in the manifest: %s\n", spid_hex);
  127. return -PAL_ERROR_INVAL;
  128. }
  129. spid[i/2] = spid[i/2] * 16 + (uint8_t)val;
  130. }
  131. char subkey[CONFIG_MAX];
  132. len = get_config(pal_state.root_config, "sgx.ra_client_key", subkey, CONFIG_MAX);
  133. if (len <= 0) {
  134. SGX_DBG(DBG_E, "No sgx.ra_client_key in the manifest\n");
  135. return -PAL_ERROR_INVAL;
  136. }
  137. char buf[2];
  138. len = get_config(pal_state.root_config, "sgx.ra_client_linkable", buf, sizeof(buf));
  139. bool linkable = (len == 1 && buf[0] == '1');
  140. len = get_config(pal_state.root_config, "sgx.ra_accept_group_out_of_date", buf, sizeof(buf));
  141. bool accept_group_out_of_date = (len == 1 && buf[0] == '1');
  142. sgx_quote_nonce_t nonce;
  143. int ret = _DkRandomBitsRead(&nonce, sizeof(nonce));
  144. if (ret < 0)
  145. return ret;
  146. char* status;
  147. char* timestamp;
  148. ret = sgx_verify_platform(&spid, subkey, &nonce, (sgx_arch_report_data_t*)&pal_enclave_state,
  149. linkable, accept_group_out_of_date, NULL, &status, &timestamp);
  150. if (ret < 0)
  151. return ret;
  152. // If the attestation is successful, update the control block
  153. __pal_control.attestation_status = status;
  154. __pal_control.attestation_timestamp = timestamp;
  155. return ret;
  156. }
  157. /*
  158. * A simple function to parse a X509 certificate for only the certificate body, the signature,
  159. * and the public key.
  160. *
  161. * TODO: Currently no verification of the X509 certificate.
  162. *
  163. * @cert: The certificate to parse (DER format).
  164. * @cert_len: The length of cert.
  165. * @body: The certificate body (the signed part).
  166. * @body_len: The length of body.
  167. * @sig: The certificate signature.
  168. * @sig_len: The length of sig.
  169. * @pubkey: The RSA public key from the certificate.
  170. */
  171. static int parse_x509(uint8_t* cert, size_t cert_len, uint8_t** body, size_t* body_len,
  172. uint8_t** sig, size_t* sig_len, LIB_RSA_KEY* pubkey) {
  173. uint8_t* ptr = cert;
  174. uint8_t* end = cert + cert_len;
  175. enum asn1_tag tag;
  176. bool is_cons;
  177. uint8_t* buf;
  178. size_t buf_len;
  179. int ret;
  180. // X509Certificate := SEQUENCE {
  181. // Body CertificateBody,
  182. // SignatureAlgorithm AlgorithmDescriptor,
  183. // Signature BIT STRING }
  184. ret = lib_ASN1GetSerial(&ptr, end, &tag, &is_cons, &buf, &buf_len);
  185. if (ret < 0)
  186. return ret;
  187. if (tag != ASN1_SEQUENCE || !is_cons)
  188. return -PAL_ERROR_INVAL;
  189. uint8_t* cert_signed = ptr = buf;
  190. uint8_t* cert_body;
  191. uint8_t* cert_sig;
  192. size_t cert_body_len, cert_sig_len;
  193. end = buf + buf_len;
  194. ret = lib_ASN1GetSerial(&ptr, end, &tag, &is_cons, &cert_body, &cert_body_len);
  195. if (ret < 0)
  196. return ret;
  197. if (tag != ASN1_SEQUENCE || !is_cons)
  198. return -PAL_ERROR_INVAL;
  199. size_t cert_signed_len = ptr - cert_signed;
  200. // Skip SignatureAlgorithm
  201. ret = lib_ASN1GetSerial(&ptr, end, &tag, &is_cons, &buf, &buf_len);
  202. if (ret < 0)
  203. return ret;
  204. ret = lib_ASN1GetBitstring(&ptr, end, &cert_sig, &cert_sig_len);
  205. if (ret < 0)
  206. return ret;
  207. // CertficateBody := SEQUENCE {
  208. // Version CONSTANT,
  209. // SerialNumber INTEGER,
  210. // Signature AlgorithmDiscriptor,
  211. // Issuer Name,
  212. // Validity ValidityTime,
  213. // Subject Name,
  214. // SubjectPublicKeyInfo PublicKeyInfo,
  215. // (optional fields) }
  216. ptr = cert_body;
  217. end = cert_body + cert_body_len;
  218. // Skip Version, SerialNumber, Signature, Issuer, Validity, and Subject
  219. for (int i = 0; i < 6; i++) {
  220. ret = lib_ASN1GetSerial(&ptr, end, &tag, &is_cons, &buf, &buf_len);
  221. if (ret < 0)
  222. return ret;
  223. }
  224. // Get SubjectPublicKeyInfo
  225. ret = lib_ASN1GetSerial(&ptr, end, &tag, &is_cons, &buf, &buf_len);
  226. if (ret < 0)
  227. return ret;
  228. if (tag != ASN1_SEQUENCE || !is_cons)
  229. return -PAL_ERROR_INVAL;
  230. // PublickKeyInfo := SEQUENCE {
  231. // PublicKeyAlgorithm AlgorithmDescriptor,
  232. // PublicKey BIT STRING }
  233. ptr = buf;
  234. end = buf + buf_len;
  235. // Skip PublicKeyAlgorithm
  236. ret = lib_ASN1GetSerial(&ptr, end, &tag, &is_cons, &buf, &buf_len);
  237. if (ret < 0)
  238. return ret;
  239. // Get PublicKey
  240. uint8_t* pkey_bits;
  241. size_t pkey_bits_len;
  242. ret = lib_ASN1GetBitstring(&ptr, end, &pkey_bits, &pkey_bits_len);
  243. if (ret < 0)
  244. return ret;
  245. // RSAPublicKey := SEQUENCE {
  246. // Modulus Integer,
  247. // PublicExponent Integer }
  248. ptr = pkey_bits;
  249. end = pkey_bits + pkey_bits_len;
  250. ret = lib_ASN1GetSerial(&ptr, end, &tag, &is_cons, &buf, &buf_len);
  251. if (ret < 0)
  252. return ret;
  253. uint8_t* mod;
  254. uint8_t* exp;
  255. size_t mod_len, exp_len;
  256. ptr = buf;
  257. end = buf + buf_len;
  258. ret = lib_ASN1GetLargeNumberLength(&ptr, end, &mod_len);
  259. if (ret < 0)
  260. return ret;
  261. mod = ptr;
  262. ptr += mod_len;
  263. ret = lib_ASN1GetLargeNumberLength(&ptr, end, &exp_len);
  264. if (ret < 0)
  265. return ret;
  266. exp = ptr;
  267. ptr += exp_len;
  268. *body = malloc(cert_signed_len);
  269. *body_len = cert_signed_len;
  270. memcpy(*body, cert_signed, cert_signed_len);
  271. *sig = malloc(cert_sig_len);
  272. *sig_len = cert_sig_len;
  273. memcpy(*sig, cert_sig, cert_sig_len);
  274. ret = lib_RSAInitKey(pubkey);
  275. if (ret < 0)
  276. return ret;
  277. ret = lib_RSAImportPublicKey(pubkey, exp, exp_len, mod, mod_len);
  278. if (ret < 0)
  279. return ret;
  280. return 0;
  281. }
  282. /*
  283. * Same as parse_x509(), but parse the certificate in PEM format.
  284. *
  285. * @cert: The starting address for parsing the certificate.
  286. * @cert_end: Returns the end of certificate after parsing.
  287. * @body: The certificate body (the signed part).
  288. * @body_len: The length of body.
  289. * @sig: The certificate signature.
  290. * @sig_len: The length of sig.
  291. * @pubkey: The RSA public key from the certificate.
  292. */
  293. static int parse_x509_pem(char* cert, char** cert_end, uint8_t** body, size_t* body_len,
  294. uint8_t** sig, size_t* sig_len, LIB_RSA_KEY* pubkey) {
  295. int ret;
  296. char* start = strchr(cert, '-');
  297. if (!start) {
  298. // No more certificate
  299. *cert_end = NULL;
  300. return 0;
  301. }
  302. if (!strpartcmp_static(start, "-----BEGIN CERTIFICATE-----"))
  303. return -PAL_ERROR_INVAL;
  304. start += static_strlen("-----BEGIN CERTIFICATE-----");
  305. char* end = strchr(start, '-');
  306. if (!strpartcmp_static(end, "-----END CERTIFICATE-----"))
  307. return -PAL_ERROR_INVAL;
  308. size_t cert_der_len;
  309. ret = lib_Base64Decode(start, end - start, NULL, &cert_der_len);
  310. if (ret < 0)
  311. return ret;
  312. uint8_t* cert_der = __alloca(cert_der_len);
  313. ret = lib_Base64Decode(start, end - start, cert_der, &cert_der_len);
  314. if (ret < 0)
  315. return ret;
  316. ret = parse_x509(cert_der, cert_der_len, body, body_len, sig, sig_len, pubkey);
  317. if (ret < 0)
  318. return ret;
  319. *cert_end = end + static_strlen("-----END CERTIFICATE-----");
  320. return 0;
  321. }
  322. /*
  323. * Perform the remote attestation to verify the current SGX platform.
  324. *
  325. * The remote attestation procedure verifies two primary properties: (1) The current execution
  326. * runs in an SGX enclave; and (2) The enclave is created on a genuine, up-to-date Intel CPU.
  327. * This procedure requires interaction with the Intel PSW quoting enclave (AESMD) and the
  328. * Intel Attestation Service (IAS). The quoting enclave verifies a local attestation report
  329. * from the target enclave, and then generates a quoting enclave (QE) report and a platform
  330. * quote signed by the platform's attestation key. The IAS then verifies the platform quote and
  331. * issues a remote attestation report, signed by a certificate chain attached to the report.
  332. *
  333. * TODO: currently no verification of the correctness of the IAS certificate
  334. *
  335. * @spid: The SPID registered for the Intel Attestation Service (IAS).
  336. * @subkey: SPID subscription key.
  337. * @nonce: A 16-byte nonce to be included in the quote.
  338. * @report_data: A 64-byte bytestring to be included in the local report and the quote.
  339. * @linkable: Specify whether the SPID is linkable.
  340. * @accept_group_out_of_date: Specify whether to accept GROUP_OUT_OF_DATE from IAS
  341. * @ret_attestation: Returns the retrieved attestation data.
  342. * @ret_ias_status: Returns a pointer to the attestation status (as a string) from the IAS.
  343. * @ret_ias_timestamp: Returns a pointer to the timestamp (as a string) from the IAS.
  344. * Timestamp format: %Y-%m-%dT%H:%M:%S.%f (Ex: 2019-08-01T12:30:00.123456)
  345. */
  346. int sgx_verify_platform(sgx_spid_t* spid, const char* subkey, sgx_quote_nonce_t* nonce,
  347. sgx_arch_report_data_t* report_data, bool linkable,
  348. bool accept_group_out_of_date, sgx_attestation_t* ret_attestation,
  349. char** ret_ias_status, char** ret_ias_timestamp) {
  350. SGX_DBG(DBG_S, "Request quote:\n");
  351. SGX_DBG(DBG_S, " spid: %s\n", ALLOCA_BYTES2HEXSTR(*spid));
  352. SGX_DBG(DBG_S, " type: %s\n", linkable ? "linkable" : "unlinkable");
  353. SGX_DBG(DBG_S, " nonce: %s\n", ALLOCA_BYTES2HEXSTR(*nonce));
  354. sgx_arch_report_t report __sgx_mem_aligned;
  355. sgx_arch_targetinfo_t targetinfo __sgx_mem_aligned = pal_sec.aesm_targetinfo;
  356. int ret = sgx_report(&targetinfo, report_data, &report);
  357. if (ret) {
  358. SGX_DBG(DBG_E, "Failed to get report for attestation\n");
  359. return -PAL_ERROR_DENIED;
  360. }
  361. sgx_attestation_t attestation;
  362. ret = ocall_get_attestation(spid, subkey, linkable, &report, nonce, &attestation);
  363. if (ret < 0) {
  364. SGX_DBG(DBG_E, "Failed to get attestation\n");
  365. return ret;
  366. }
  367. // First, verify the report from the quoting enclave
  368. ret = sgx_verify_report(&attestation.qe_report);
  369. if (ret < 0) {
  370. SGX_DBG(DBG_E, "Failed to verify QE report, ret = %d\n", ret);
  371. goto failed;
  372. }
  373. // Verify the IAS response against the certificate chain
  374. uint8_t* data_to_verify = (uint8_t*)attestation.ias_report;
  375. uint8_t* data_sig = attestation.ias_sig;
  376. size_t data_len = attestation.ias_report_len;
  377. size_t data_sig_len = attestation.ias_sig_len;
  378. // Attach the IAS signing chain with the hard-coded CA certificate
  379. const char* ca_cert = IAS_CA_CERT;
  380. size_t len1 = strlen(attestation.ias_certs);
  381. size_t len2 = static_strlen(IAS_CA_CERT);
  382. char* certs = malloc(len1 + len2 + 1);
  383. memcpy(certs, attestation.ias_certs, len1);
  384. memcpy(certs + len1, ca_cert, len2);
  385. certs[len1 + len2] = 0;
  386. free(attestation.ias_certs);
  387. attestation.ias_certs = certs;
  388. attestation.ias_certs_len = len1 + len2 + 1;
  389. // There can be multiple certificates in the chain. We need to use the public key from
  390. // the *first* certificate to verify the IAS response. For each certificate except
  391. // the last one, we need to use the public key from the *next* certificate to verify
  392. // the certificate body. The last certificate will be verified by the CA certificate
  393. // (hard-coded in the binary)
  394. for (char* cert_start = attestation.ias_certs;
  395. cert_start < attestation.ias_certs + attestation.ias_certs_len && *cert_start; ) {
  396. // Generate the message digest first (without RSA)
  397. LIB_SHA256_CONTEXT ctx;
  398. uint8_t hash[32];
  399. if ((ret = lib_SHA256Init(&ctx)) < 0)
  400. goto failed;
  401. if ((ret = lib_SHA256Update(&ctx, data_to_verify, data_len)) < 0)
  402. goto failed;
  403. if ((ret = lib_SHA256Final(&ctx, hash)) < 0)
  404. goto failed;
  405. // Use the public key to verify the last signature
  406. uint8_t* cert_body;
  407. uint8_t* cert_sig;
  408. size_t cert_body_len;
  409. size_t cert_sig_len;
  410. LIB_RSA_KEY cert_key;
  411. ret = parse_x509_pem(cert_start, &cert_start, &cert_body, &cert_body_len, &cert_sig,
  412. &cert_sig_len, &cert_key);
  413. if (ret < 0) {
  414. SGX_DBG(DBG_E, "Failed to parse IAS certificate, rv = %d\n", ret);
  415. goto failed;
  416. }
  417. ret = lib_RSAVerifySHA256(&cert_key, hash, sizeof(hash), data_sig, data_sig_len);
  418. if (ret < 0) {
  419. SGX_DBG(DBG_E, "Failed to verify the report against the IAS certificates,"
  420. " rv = %d\n", ret);
  421. lib_RSAFreeKey(&cert_key);
  422. goto failed;
  423. }
  424. lib_RSAFreeKey(&cert_key);
  425. data_to_verify = cert_body;
  426. data_sig = cert_sig;
  427. data_len = cert_body_len;
  428. data_sig_len = cert_sig_len;
  429. }
  430. // Parse the IAS report in JSON format
  431. char* ias_status = NULL;
  432. char* ias_timestamp = NULL;
  433. sgx_quote_nonce_t* ias_nonce = NULL;
  434. sgx_quote_t* ias_quote = NULL;
  435. char* start = attestation.ias_report;
  436. if (start[0] == '{') start++;
  437. char* end = strchr(start, ',');
  438. while (end) {
  439. char* next_start = end + 1;
  440. // Retrieve the key and value separated by the colon (:)
  441. char* delim = strchr(start, ':');
  442. if (!delim)
  443. break;
  444. char* key = start;
  445. char* val = delim + 1;
  446. size_t klen = delim - start;
  447. size_t vlen = end - val;
  448. // Remove quotation marks (") around the key and value if there are any
  449. if (key[0] == '"') { key++; klen--; }
  450. if (key[klen - 1] == '"') klen--;
  451. if (val[0] == '"') { val++; vlen--; }
  452. if (val[vlen - 1] == '"') vlen--;
  453. // Scan the fields in the IAS report.
  454. if (!memcmp(key, "isvEnclaveQuoteStatus", klen)) {
  455. // Parse "isvEnclaveQuoteStatus":"OK"|"GROUP_OUT_OF_DATE"|...
  456. ias_status = __alloca(vlen + 1);
  457. memcpy(ias_status, val, vlen);
  458. ias_status[vlen] = 0;
  459. } else if (!memcmp(key, "nonce", klen)) {
  460. // Parse "nonce":"{Hex representation of the initial nonce}"
  461. if (vlen != sizeof(sgx_quote_nonce_t) * 2) {
  462. SGX_DBG(DBG_E, "Malformed nonce in the IAS report\n");
  463. goto failed;
  464. }
  465. ias_nonce = __alloca(sizeof(sgx_quote_nonce_t));
  466. for (size_t i = 0; i < sizeof(sgx_quote_nonce_t); i++) {
  467. int8_t hi = hex2dec(val[i * 2]);
  468. int8_t lo = hex2dec(val[i * 2 + 1]);
  469. if (hi < 0 || lo < 0) {
  470. SGX_DBG(DBG_E, "Malformed nonce in the IAS report\n");
  471. goto failed;
  472. }
  473. ((uint8_t*)ias_nonce)[i] = (uint8_t)hi * 16 + (uint8_t)lo;
  474. }
  475. } else if (!memcmp(key, "timestamp", klen)) {
  476. // Parse "timestamp":"{IAS timestamp (format: %Y-%m-%dT%H:%M:%S.%f)}"
  477. ias_timestamp = __alloca(vlen + 1);
  478. memcpy(ias_timestamp, val, vlen);
  479. ias_timestamp[vlen] = 0;
  480. } else if (!memcmp(key, "isvEnclaveQuoteBody", klen)) {
  481. // Parse "isvEnclaveQuoteBody":"{Quote body (in Base64 format)}"
  482. size_t ias_quote_len;
  483. ret = lib_Base64Decode(val, vlen, NULL, &ias_quote_len);
  484. if (ret < 0) {
  485. SGX_DBG(DBG_E, "Malformed quote in the IAS report\n");
  486. goto failed;
  487. }
  488. ias_quote = __alloca(ias_quote_len);
  489. ret = lib_Base64Decode(val, vlen, (uint8_t*)ias_quote, &ias_quote_len);
  490. if (ret < 0) {
  491. SGX_DBG(DBG_E, "Malformed quote in the IAS report\n");
  492. goto failed;
  493. }
  494. }
  495. start = next_start;
  496. end = strchr(start, ',') ? : strchr(start, '}');
  497. }
  498. if (!ias_status || !ias_nonce || !ias_timestamp || !ias_quote) {
  499. SGX_DBG(DBG_E, "Missing important field(s) in the IAS report\n");
  500. goto failed;
  501. }
  502. SGX_DBG(DBG_S, "Quote:\n");
  503. SGX_DBG(DBG_S, " version: %04x\n", ias_quote->body.version);
  504. SGX_DBG(DBG_S, " sigtype: %04x\n", ias_quote->body.sigtype);
  505. SGX_DBG(DBG_S, " gid: %08x\n", ias_quote->body.gid);
  506. SGX_DBG(DBG_S, " isvsvn qe: %08x\n", ias_quote->body.isvsvn_qe);
  507. SGX_DBG(DBG_S, " isvsvn pce: %08x\n", ias_quote->body.isvsvn_pce);
  508. SGX_DBG(DBG_S, "IAS report: %s\n", attestation.ias_report);
  509. SGX_DBG(DBG_S, " status: %s\n", ias_status);
  510. SGX_DBG(DBG_S, " timestamp: %s\n", ias_timestamp);
  511. // Only accept status to be "OK" or "GROUP_OUT_OF_DATE" (if accept_out_of_date is true)
  512. if (!strcmp_static(ias_status, "OK") &&
  513. (!accept_group_out_of_date || !strcmp_static(ias_status, "GROUP_OUT_OF_DATE"))) {
  514. SGX_DBG(DBG_E, "IAS returned invalid status: %s\n", ias_status);
  515. goto failed;
  516. }
  517. // Check if the nonce matches the IAS report
  518. if (memcmp(ias_nonce, nonce, sizeof(sgx_quote_nonce_t))) {
  519. SGX_DBG(DBG_E, "IAS returned the wrong nonce\n");
  520. goto failed;
  521. }
  522. // Check if the quote matches the IAS report
  523. if (memcmp(&ias_quote->body, &attestation.quote->body, sizeof(sgx_quote_body_t)) ||
  524. memcmp(&ias_quote->report_body, &report.body, sizeof(sgx_arch_report_body_t))) {
  525. SGX_DBG(DBG_E, "IAS returned the wrong quote\n");
  526. goto failed;
  527. }
  528. // Check if the quote has the right enclave report
  529. if (memcmp(&attestation.quote->report_body, &report.body, sizeof(sgx_arch_report_body_t))) {
  530. SGX_DBG(DBG_E, "The returned quote contains the wrong enclave report\n");
  531. goto failed;
  532. }
  533. // Succeeded!!!
  534. if (ret_ias_status) {
  535. size_t len = strlen(ias_status) + 1;
  536. *ret_ias_status = malloc(len);
  537. memcpy(*ret_ias_status, ias_status, len);
  538. }
  539. if (ret_ias_timestamp) {
  540. size_t len = strlen(ias_timestamp) + 1;
  541. *ret_ias_timestamp = malloc(len);
  542. memcpy(*ret_ias_timestamp, ias_timestamp, len);
  543. }
  544. if (ret_attestation) {
  545. memcpy(ret_attestation, &attestation, sizeof(sgx_attestation_t));
  546. return 0;
  547. }
  548. ret = 0;
  549. free_attestation:
  550. if (attestation.quote) free(attestation.quote);
  551. if (attestation.ias_report) free(attestation.ias_report);
  552. if (attestation.ias_sig) free(attestation.ias_sig);
  553. if (attestation.ias_certs) free(attestation.ias_certs);
  554. return ret;
  555. failed:
  556. ret = -PAL_ERROR_DENIED;
  557. goto free_attestation;
  558. }