diff --git a/QuoteGeneration/quote_wrapper/tdx_attest/tdx_attest.c b/QuoteGeneration/quote_wrapper/tdx_attest/tdx_attest.c index 23073091..6500cf2d 100644 --- a/QuoteGeneration/quote_wrapper/tdx_attest/tdx_attest.c +++ b/QuoteGeneration/quote_wrapper/tdx_attest/tdx_attest.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2022 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -227,7 +227,7 @@ void __attribute__((constructor)) init_mutex(void) { pthread_mutex_init(&mkdir_m void __attribute__((destructor)) destroy_mutex(void) { pthread_mutex_destroy(&mkdir_mutex); } static tdx_attest_error_t prepare_configfs(char **p_configfs_path) { - int ret = TDX_ATTEST_ERROR_NOT_SUPPORTED; + int ret = TDX_ATTEST_ERROR_QUOTE_FAILURE; char *configfs_path = NULL; do { // Retrive DCAP TDX quote configFS path from environment @@ -265,16 +265,20 @@ static tdx_attest_error_t prepare_configfs(char **p_configfs_path) { closedir(dir); break; } - if (errno != ENOENT) { + if (errno == ENOMEM) { pthread_mutex_unlock(&mkdir_mutex); - syslog(LOG_INFO, "libtdx_attest: default DCAP configFS not supported - fallback to vsock mode."); + ret = TDX_ATTEST_ERROR_OUT_OF_MEMORY; + break; + }else if (errno != ENOENT) { + pthread_mutex_unlock(&mkdir_mutex); + syslog(LOG_INFO, "libtdx_attest: default DCAP configFS not supported - fallback to TDcall mode."); break; } // Create default DCAP TDX quote configFS path only once if (!b_mkdir) { pthread_mutex_unlock(&mkdir_mutex); - syslog(LOG_INFO, "libtdx_attest: default DCAP configFS not supported - fallback to vsock mode."); + syslog(LOG_INFO, "libtdx_attest: default DCAP configFS not supported - fallback to TDcall mode."); break; } b_mkdir = 0; @@ -282,12 +286,12 @@ static tdx_attest_error_t prepare_configfs(char **p_configfs_path) { dir = opendir(QUOTE_CONFIGFS_PATH); if (dir == NULL) { pthread_mutex_unlock(&mkdir_mutex); - syslog(LOG_INFO, "libtdx_attest: configFS not supported - fallback to vsock mode."); - break; + syslog(LOG_INFO, "libtdx_attest: configFS not supported - fallback to TDcall mode."); + break; } closedir(dir); - if (mkdir(configfs_path, S_IRWXU | S_IRWXG)) { + if (mkdir(configfs_path, S_IRWXU | S_IRWXG)) { pthread_mutex_unlock(&mkdir_mutex); if (errno == EEXIST && (dir = opendir(configfs_path)) != NULL) { // Another process has just created configfs_path @@ -295,7 +299,7 @@ static tdx_attest_error_t prepare_configfs(char **p_configfs_path) { closedir(dir); break; } - syslog(LOG_INFO, "libtdx_attest: cannot create default configFS - fallback to vsock mode."); + syslog(LOG_INFO, "libtdx_attest: cannot create default configFS - fallback to TDcall mode."); break; } char provider_path[MAX_PATH]; @@ -304,14 +308,18 @@ static tdx_attest_error_t prepare_configfs(char **p_configfs_path) { // Linux kernel will create provider, generation, inblob, outblob in configfs_path // after configfs_path direcotry created. if (access(provider_path, F_OK) == 0) { - pthread_mutex_unlock(&mkdir_mutex); ret = TDX_ATTEST_SUCCESS; break; } usleep((useconds_t)retry); } + if (ret != TDX_ATTEST_SUCCESS) { + pthread_mutex_unlock(&mkdir_mutex); + syslog(LOG_INFO, "libtdx_attest: unavailable default configFS - fallback to TDcall mode."); + break; + } + pthread_mutex_unlock(&mkdir_mutex); - syslog(LOG_INFO, "libtdx_attest: unavailable default configFS - fallback to vsock mode."); break; } @@ -338,7 +346,7 @@ static tdx_attest_error_t prepare_configfs(char **p_configfs_path) { if (byte_size == -1 || byte_size == 0 || strncmp(provider, "tdx_guest", sizeof("tdx_guest") - 1)) { syslog(LOG_ERR, "libtdx_attest: configFS unsupported provider."); - return TDX_ATTEST_ERROR_NOT_SUPPORTED; + return TDX_ATTEST_ERROR_UNEXPECTED; } *p_configfs_path = configfs_path; return TDX_ATTEST_SUCCESS; @@ -390,432 +398,482 @@ static tdx_attest_error_t read_configfs_generation(char *generation_path, long* } #define RETRY_WAIT_TIME_USEC 10000000 - -tdx_attest_error_t tdx_att_get_quote( +static tdx_attest_error_t configfs_get_quote( const tdx_report_data_t *p_tdx_report_data, - const tdx_uuid_t *p_att_key_id_list, - uint32_t list_size, - tdx_uuid_t *p_att_key_id, uint8_t **pp_quote, - uint32_t *p_quote_size, - uint32_t flags) + uint32_t *p_quote_size) { - int s = -1; - int devfd = -1; + char *configfs_path = NULL; + tdx_attest_error_t ret = prepare_configfs(&configfs_path); + if (TDX_ATTEST_SUCCESS != ret) + return ret; - const uint8_t *p_quote = NULL; - uint32_t quote_size = 0; - tdx_attest_error_t ret = TDX_ATTEST_ERROR_UNEXPECTED; - uint8_t *p_blob_payload = NULL; + char inblob_path[MAX_PATH]; + snprintf(inblob_path, sizeof(inblob_path), "%s/inblob", configfs_path); - if ((!p_att_key_id_list && list_size) || - (p_att_key_id_list && !list_size)) { - return TDX_ATTEST_ERROR_INVALID_PARAMETER; - } - if (!pp_quote) { - return TDX_ATTEST_ERROR_INVALID_PARAMETER; + // Lock `inblob` to avoid other processes accessing it using libtdx_attest + // Will unlock it via close() + int fd_lock = open(inblob_path, O_WRONLY | O_CLOEXEC); + if (-1 == fd_lock) { + TDX_TRACE; + syslog(LOG_ERR, "libtdx_attest: failed to open configFS inblob."); + return TDX_ATTEST_ERROR_UNEXPECTED; } - if (flags) { - //TODO: I think we need to have a runtime version to make this flag usable. - return TDX_ATTEST_ERROR_INVALID_PARAMETER; + if (flock(fd_lock, LOCK_EX)) { + TDX_TRACE; + close(fd_lock); + syslog(LOG_ERR, "libtdx_attest: failed to lock configFS inblob."); + return TDX_ATTEST_ERROR_UNEXPECTED; } - // Currently only intel TDQE are supported - if (1 < list_size) { - return TDX_ATTEST_ERROR_INVALID_PARAMETER; - } - if (p_att_key_id_list && memcmp(p_att_key_id_list, &g_intel_tdqe_uuid, - sizeof(g_intel_tdqe_uuid))) { - return TDX_ATTEST_ERROR_UNSUPPORTED_ATT_KEY_ID; + /* Read and check generation value before writing inblob, after writing inblob and after + reading outblob to make sure that outblob matches inblob */ + char generation_path[MAX_PATH]; + snprintf(generation_path, sizeof(generation_path), "%s/generation", configfs_path); + long generation1; + ret = read_configfs_generation(generation_path, &generation1); + if (ret) { + close(fd_lock); + return ret; } - *pp_quote = NULL; + // Write TDX report data to inblob + int fd_inblob = open(inblob_path, O_WRONLY); + if (-1 == fd_inblob) { + TDX_TRACE; + close(fd_lock); + syslog(LOG_ERR, "libtdx_attest: failed to open configFS inblob."); + return TDX_ATTEST_ERROR_UNEXPECTED; + } - do { - char *configfs_path = NULL; - if (prepare_configfs(&configfs_path) != TDX_ATTEST_SUCCESS) + ssize_t byte_size = 0; + // Wait and retry when EBUSY; other TDX Quotes are being generating + for (int retry = 0; retry < 3; retry++) { + errno = 0; + byte_size = write(fd_inblob, p_tdx_report_data, sizeof(*p_tdx_report_data)); + if (errno != EBUSY) break; - - char inblob_path[MAX_PATH]; - snprintf(inblob_path, sizeof(inblob_path), "%s/inblob", configfs_path); - - // Lock `inblob` to avoid other processes accessing it using libtdx_attest - // Will unlock it via close() - int fd_lock = open(inblob_path, O_WRONLY | O_CLOEXEC); - if (-1 == fd_lock) { + usleep(RETRY_WAIT_TIME_USEC); + } + if (byte_size != sizeof(*p_tdx_report_data)) { + if (errno == EBUSY) { TDX_TRACE; - syslog(LOG_ERR, "libtdx_attest: failed to open configFS inblob."); - return TDX_ATTEST_ERROR_UNEXPECTED; - } - if (flock(fd_lock, LOCK_EX)) { + ret = TDX_ATTEST_ERROR_BUSY; + } else { TDX_TRACE; - close(fd_lock); - syslog(LOG_ERR, "libtdx_attest: failed to lock configFS inblob."); - return TDX_ATTEST_ERROR_UNEXPECTED; + ret = TDX_ATTEST_ERROR_UNEXPECTED; } + close(fd_lock); + close(fd_inblob); + syslog(LOG_ERR, "libtdx_attest: failed to write configFS inblob."); + return ret; + } + close(fd_inblob); - /* Read and check generation value before writing inblob, after writing inblob and after - reading outblob to make sure that outblob matches inblob */ - char generation_path[MAX_PATH]; - snprintf(generation_path, sizeof(generation_path), "%s/generation", configfs_path); - long generation1; - ret = read_configfs_generation(generation_path, &generation1); + long generation2; + do { + ret = read_configfs_generation(generation_path, &generation2); if (ret) { close(fd_lock); return ret; } + // In rare cases, generation is not updated + } while (generation2 == generation1 && !usleep(0)); + if (generation2 != generation1 + 1) { + // Another TDX quote generation has been triggered + close(fd_lock); + return TDX_ATTEST_ERROR_BUSY; + } - // Write TDX report data to inblob - int fd_inblob = open(inblob_path, O_WRONLY); - if (-1 == fd_inblob) { - TDX_TRACE; - close(fd_lock); - syslog(LOG_ERR, "libtdx_attest: failed to open configFS inblob."); - return TDX_ATTEST_ERROR_UNEXPECTED; - } - - ssize_t byte_size = 0; - // Wait and retry when EBUSY; other TDX Quotes are being generating - for (int retry = 0; retry < 3; retry++) { - errno = 0; - byte_size = write(fd_inblob, p_tdx_report_data, sizeof(*p_tdx_report_data)); - if (errno != EBUSY) - break; - usleep(RETRY_WAIT_TIME_USEC); - } - if (byte_size != sizeof(*p_tdx_report_data)) { - if (errno == EBUSY) { - TDX_TRACE; - ret = TDX_ATTEST_ERROR_BUSY; - } else { - TDX_TRACE; - ret = TDX_ATTEST_ERROR_UNEXPECTED; - } - close(fd_lock); - close(fd_inblob); - syslog(LOG_ERR, "libtdx_attest: failed to write configFS inblob."); - return ret; - } - close(fd_inblob); - - long generation2; - do { - ret = read_configfs_generation(generation_path, &generation2); - if (ret) { - close(fd_lock); - return ret; - } - // In rare cases, generation is not updated - } while (generation2 == generation1 && !usleep(0)); - if (generation2 != generation1 + 1) { - // Another TDX quote generation has been triggered - close(fd_lock); - return TDX_ATTEST_ERROR_BUSY; - } - - // Read TDX quote from outblob - char outblob_path[MAX_PATH]; - snprintf(outblob_path, sizeof(outblob_path), "%s/outblob", configfs_path); - int fd = open(outblob_path, O_RDONLY); - if (-1 == fd) { - TDX_TRACE; - syslog(LOG_ERR, "libtdx_attest: failed to open configFS outblob."); - close(fd_lock); - return TDX_ATTEST_ERROR_UNEXPECTED; - } + // Read TDX quote from outblob + char outblob_path[MAX_PATH]; + snprintf(outblob_path, sizeof(outblob_path), "%s/outblob", configfs_path); + int fd = open(outblob_path, O_RDONLY); + if (-1 == fd) { + TDX_TRACE; + syslog(LOG_ERR, "libtdx_attest: failed to open configFS outblob."); + close(fd_lock); + return TDX_ATTEST_ERROR_UNEXPECTED; + } - // Allocate memory for the entire file content - p_blob_payload = malloc(QUOTE_BUF_SIZE); - if (p_blob_payload == NULL) { - close(fd_lock); - close(fd); - return TDX_ATTEST_ERROR_OUT_OF_MEMORY; - } -#ifdef DEBUG - fprintf(stdout, "\nstart to read outblob\n"); -#endif - // Read the entire file in one shot - for (int retry = 0; retry < 3; retry++) { - errno = 0; - byte_size = read(fd, p_blob_payload, QUOTE_BUF_SIZE); - if (errno == EBUSY) { - usleep(RETRY_WAIT_TIME_USEC); - } else if (errno != EINTR && errno != ETIMEDOUT) - break; - } - if (byte_size == -1 || byte_size == 0) { - if (errno == EBUSY || errno == EINTR || errno == ETIMEDOUT) { - TDX_TRACE; - ret = TDX_ATTEST_ERROR_BUSY; - } else - ret = TDX_ATTEST_ERROR_QUOTE_FAILURE; - close(fd_lock); - close(fd); - free(p_blob_payload); - syslog(LOG_ERR, "libtdx_attest: failed to read outblob."); - return ret; - } + // Allocate memory for the entire file content + void* p_quote_buf = malloc(QUOTE_BUF_SIZE); + if (p_quote_buf == NULL) { + close(fd_lock); close(fd); - - quote_size = (uint32_t)byte_size; + return TDX_ATTEST_ERROR_OUT_OF_MEMORY; + } #ifdef DEBUG - fprintf(stdout, "\nquote size: %d\n", quote_size); + fprintf(stdout, "\nstart to read outblob\n"); #endif - if (quote_size <= QUOTE_MIN_SIZE || quote_size == QUOTE_BUF_SIZE) { - close(fd_lock); - free(p_blob_payload); - return TDX_ATTEST_ERROR_QUOTE_FAILURE; - } - - long generation3; - ret = read_configfs_generation(generation_path, &generation3); + // Read the entire file in one shot + for (int retry = 0; retry < 3; retry++) { + errno = 0; + byte_size = read(fd, p_quote_buf, QUOTE_BUF_SIZE); + if (errno == EBUSY) { + usleep(RETRY_WAIT_TIME_USEC); + } else if (errno != EINTR && errno != ETIMEDOUT) + break; + } + if (byte_size == -1 || byte_size == 0) { + if (errno == EBUSY || errno == EINTR || errno == ETIMEDOUT) { + TDX_TRACE; + ret = TDX_ATTEST_ERROR_BUSY; + } else + ret = TDX_ATTEST_ERROR_QUOTE_FAILURE; close(fd_lock); - if (ret) { - free(p_blob_payload); - return ret; - } - // Another TDX quote generation is triggered - if (generation3 != generation2) { - free(p_blob_payload); - return TDX_ATTEST_ERROR_BUSY; - } - - *pp_quote = realloc(p_blob_payload, quote_size); - if (!*pp_quote) { - free(p_blob_payload); - return TDX_ATTEST_ERROR_OUT_OF_MEMORY; - } - - if (p_quote_size) { - *p_quote_size = quote_size; - } - if (p_att_key_id) { - *p_att_key_id = g_intel_tdqe_uuid; - } - return TDX_ATTEST_SUCCESS; - } while (0); + close(fd); + free(p_quote_buf); + syslog(LOG_ERR, "libtdx_attest: failed to read configFS outblob."); + return ret; + } + close(fd); + uint32_t quote_size = (uint32_t)byte_size; #ifdef DEBUG - fprintf(stdout, "\ngoto legacy logic\n"); + fprintf(stdout, "\nquote size: %d\n", quote_size); #endif + if (quote_size <= QUOTE_MIN_SIZE || quote_size == QUOTE_BUF_SIZE) { + close(fd_lock); + free(p_quote_buf); + syslog(LOG_ERR, "libtdx_attest: failed to get quote in configFS mode."); + return TDX_ATTEST_ERROR_QUOTE_FAILURE; + } - uint32_t recieved_bytes = 0; - uint32_t in_msg_size = 0; - unsigned int vsock_port = 0; - uint32_t msg_size = 0; - qgs_msg_error_t qgs_msg_ret = QGS_MSG_SUCCESS; - qgs_msg_header_t *p_header = NULL; - uint8_t *p_req = NULL; - const uint8_t *p_selected_id = NULL; - uint32_t id_size = 0; - - tdx_report_t tdx_report; - memset(&tdx_report, 0, sizeof(tdx_report)); - - struct tdx_quote_hdr *p_get_quote_blob = malloc(REQ_BUF_SIZE); - if (!p_get_quote_blob) { - ret = TDX_ATTEST_ERROR_OUT_OF_MEMORY; - goto ret_point; + long generation3; + ret = read_configfs_generation(generation_path, &generation3); + close(fd_lock); + if (ret) { + free(p_quote_buf); + return ret; + } + // Another TDX quote generation is triggered + if (generation3 != generation2) { + free(p_quote_buf); + return TDX_ATTEST_ERROR_BUSY; } - devfd = open(TDX_ATTEST_DEV_PATH, O_RDWR | O_SYNC); - if (-1 == devfd) { - TDX_TRACE; - ret = TDX_ATTEST_ERROR_DEVICE_FAILURE; - goto ret_point; + *pp_quote = realloc(p_quote_buf, quote_size); + if (!*pp_quote) { + free(p_quote_buf); + return TDX_ATTEST_ERROR_OUT_OF_MEMORY; } - ret = get_tdx_report(devfd, p_tdx_report_data, &tdx_report); - if (TDX_ATTEST_SUCCESS != ret) { - goto ret_point; + if (p_quote_size) { + *p_quote_size = quote_size; } + return TDX_ATTEST_SUCCESS; +} + - qgs_msg_ret = qgs_msg_gen_get_quote_req(tdx_report.d, sizeof(tdx_report.d), +static tdx_attest_error_t generate_get_quote_blob( + const tdx_report_t *p_tdx_report, + struct tdx_quote_hdr *p_get_quote_blob) +{ + uint32_t msg_size = 0; + qgs_msg_error_t qgs_msg_ret = QGS_MSG_SUCCESS; + uint8_t *p_req = NULL; + qgs_msg_ret = qgs_msg_gen_get_quote_req((uint8_t*)p_tdx_report, sizeof(*p_tdx_report), NULL, 0, &p_req, &msg_size); if (QGS_MSG_SUCCESS != qgs_msg_ret) { #ifdef DEBUG fprintf(stdout, "\nqgs_msg_gen_get_quote_req return 0x%x\n", qgs_msg_ret); #endif - ret = TDX_ATTEST_ERROR_UNEXPECTED; - goto ret_point; + return TDX_ATTEST_ERROR_UNEXPECTED; } if (msg_size > REQ_BUF_SIZE - sizeof(struct tdx_quote_hdr) - HEADER_SIZE) { #ifdef DEBUG fprintf(stdout, "\nqmsg_size[%d] is too big\n", msg_size); - #endif - ret = TDX_ATTEST_ERROR_NOT_SUPPORTED; - goto ret_point; +#endif + qgs_msg_free(p_req); + return TDX_ATTEST_ERROR_NOT_SUPPORTED; } - p_blob_payload = (uint8_t *)&p_get_quote_blob->data; + uint8_t* p_blob_payload = (uint8_t *)&p_get_quote_blob->data; p_blob_payload[0] = (uint8_t)((msg_size >> 24) & 0xFF); p_blob_payload[1] = (uint8_t)((msg_size >> 16) & 0xFF); p_blob_payload[2] = (uint8_t)((msg_size >> 8) & 0xFF); p_blob_payload[3] = (uint8_t)(msg_size & 0xFF); memcpy(p_blob_payload + HEADER_SIZE, p_req, msg_size); + qgs_msg_free(p_req); - do { - vsock_port = get_vsock_port(); - if (!vsock_port) { - syslog(LOG_INFO, "libtdx_attest: cannot parse sock port - fallback to tdvmcall mode."); - break; - } - s = socket(AF_VSOCK, SOCK_STREAM, 0); - if (-1 == s) { - syslog(LOG_INFO, "libtdx_attest: cannot create socket - fallback to tdvmcall mode."); - break; - } - struct sockaddr_vm vm_addr; - memset(&vm_addr, 0, sizeof(vm_addr)); - vm_addr.svm_family = AF_VSOCK; - vm_addr.svm_reserved1 = 0; - vm_addr.svm_port = vsock_port; - vm_addr.svm_cid = VMADDR_CID_HOST; - if (connect(s, (struct sockaddr *)&vm_addr, sizeof(vm_addr))) { - syslog(LOG_INFO, "libtdx_attest: cannot connect - fallback to tdvmcall mode."); - break; - } + p_get_quote_blob->version = 1; + p_get_quote_blob->status = 0; + p_get_quote_blob->in_len = HEADER_SIZE + msg_size; + p_get_quote_blob->out_len = 0; + return TDX_ATTEST_SUCCESS; +} - // Write to socket - if (HEADER_SIZE + msg_size != send(s, p_blob_payload, - HEADER_SIZE + msg_size, 0)) { - TDX_TRACE; - ret = TDX_ATTEST_ERROR_VSOCK_FAILURE; - goto ret_point; - } - // Read the response size header - if (HEADER_SIZE != recv(s, p_blob_payload, - HEADER_SIZE, 0)) { - TDX_TRACE; - ret = TDX_ATTEST_ERROR_VSOCK_FAILURE; - goto ret_point; - } +static tdx_attest_error_t extract_quote_from_blob_payload( + uint8_t* p_blob_payload, + uint32_t payload_body_size, + uint8_t **pp_quote, + uint32_t *p_quote_size) +{ + const uint8_t *p_selected_id_ = NULL; + uint32_t id_size_ = 0; + const uint8_t *p_quote = NULL; + uint32_t quote_size = 0; + qgs_msg_error_t qgs_msg_ret = qgs_msg_inflate_get_quote_resp( + p_blob_payload + HEADER_SIZE, payload_body_size, + &p_selected_id_, &id_size_, + &p_quote, "e_size); + if (QGS_MSG_SUCCESS != qgs_msg_ret) { +#ifdef DEBUG + fprintf(stdout, "\nqgs_msg_inflate_get_quote_resp return 0x%x", qgs_msg_ret); +#endif + return TDX_ATTEST_ERROR_UNEXPECTED; + } - // decode the size - for (unsigned i = 0; i < HEADER_SIZE; ++i) { - in_msg_size = in_msg_size * 256 + ((p_blob_payload[i]) & 0xFF); - } + // We've called qgs_msg_inflate_get_quote_resp, the message type should be GET_QUOTE_RESP + qgs_msg_header_t *p_header = (qgs_msg_header_t *)(p_blob_payload + HEADER_SIZE); + if (p_header->error_code != 0) { +#ifdef DEBUG + fprintf(stdout, "\nerror code in resp msg is 0x%x", p_header->error_code); +#endif + return TDX_ATTEST_ERROR_UNEXPECTED; + } + *pp_quote = malloc(quote_size); + if (!*pp_quote) { + return TDX_ATTEST_ERROR_OUT_OF_MEMORY; + } + memcpy(*pp_quote, p_quote, quote_size); + if (p_quote_size) { + *p_quote_size = quote_size; + } + return TDX_ATTEST_SUCCESS; +} - // prepare the buffer and read the reply body - #ifdef DEBUG - fprintf(stdout, "\nReply message body is %u bytes", in_msg_size); - #endif - if (REQ_BUF_SIZE - sizeof(struct tdx_quote_hdr) - HEADER_SIZE < in_msg_size) { - #ifdef DEBUG - fprintf(stdout, "\nReply message body is too big"); - #endif - ret = TDX_ATTEST_ERROR_UNEXPECTED; +static tdx_attest_error_t vsock_get_quote_payload( + uint8_t* p_blob_payload, + uint32_t blob_payload_size, + uint32_t *p_payload_body_size) +{ + tdx_attest_error_t ret = TDX_ATTEST_ERROR_UNEXPECTED; + + uint32_t recieved_bytes = 0; + uint32_t body_size = 0; + + unsigned int vsock_port = get_vsock_port(); + if (!vsock_port) { + syslog(LOG_INFO, "libtdx_attest: cannot parse sock port - use configfs mode."); + return TDX_ATTEST_ERROR_NOT_SUPPORTED; + } + int s = socket(AF_VSOCK, SOCK_STREAM, 0); + if (-1 == s) { + syslog(LOG_ERR, "libtdx_attest: cannot create socket."); + return TDX_ATTEST_ERROR_VSOCK_FAILURE; + } + + struct sockaddr_vm vm_addr; + memset(&vm_addr, 0, sizeof(vm_addr)); + vm_addr.svm_family = AF_VSOCK; + vm_addr.svm_reserved1 = 0; + vm_addr.svm_port = vsock_port; + vm_addr.svm_cid = VMADDR_CID_HOST; + if (connect(s, (struct sockaddr *)&vm_addr, sizeof(vm_addr))) { + syslog(LOG_ERR, "libtdx_attest: cannot connect socket."); + ret = TDX_ATTEST_ERROR_VSOCK_FAILURE; + goto ret_point; + } + + // Write to socket + if (blob_payload_size != send(s, p_blob_payload, + blob_payload_size, 0)) { + TDX_TRACE; + ret = TDX_ATTEST_ERROR_VSOCK_FAILURE; + goto ret_point; + } + + // Read the response size header + if (HEADER_SIZE != recv(s, p_blob_payload, + HEADER_SIZE, 0)) { + TDX_TRACE; + ret = TDX_ATTEST_ERROR_VSOCK_FAILURE; + goto ret_point; + } + + // decode the size + for (unsigned i = 0; i < HEADER_SIZE; ++i) { + body_size = body_size * 256 + ((p_blob_payload[i]) & 0xFF); + } + + // prepare the buffer and read the reply body +#ifdef DEBUG + fprintf(stdout, "\nReply message body is %u bytes", body_size); +#endif + + if (REQ_BUF_SIZE - sizeof(struct tdx_quote_hdr) - HEADER_SIZE < body_size) { +#ifdef DEBUG + fprintf(stdout, "\nReply message body is too big"); +#endif + ret = TDX_ATTEST_ERROR_UNEXPECTED; + goto ret_point; + } + while( recieved_bytes < body_size) { + int recv_ret = (int)recv(s, p_blob_payload + HEADER_SIZE + recieved_bytes, + body_size - recieved_bytes, 0); + if (recv_ret < 0) { + ret = TDX_ATTEST_ERROR_VSOCK_FAILURE; goto ret_point; } - while( recieved_bytes < in_msg_size) { - int recv_ret = (int)recv(s, p_blob_payload + HEADER_SIZE + recieved_bytes, - in_msg_size - recieved_bytes, 0); - if (recv_ret < 0) { - ret = TDX_ATTEST_ERROR_VSOCK_FAILURE; - goto ret_point; - } - recieved_bytes += (uint32_t)recv_ret; - } - #ifdef DEBUG - fprintf(stdout, "\nGet %u bytes response from vsock", recieved_bytes); - #endif + recieved_bytes += (uint32_t)recv_ret; + } - goto done; - } while (0); + *p_payload_body_size = body_size; +#ifdef DEBUG + fprintf(stdout, "\nGet %u bytes response from vsock", recieved_bytes); +#endif + ret = TDX_ATTEST_SUCCESS; + +ret_point: + close(s); + return ret; +} +tdx_attest_error_t tdcall_get_quote_payload( + int devfd, + struct tdx_quote_hdr *p_get_quote_blob, + uint32_t *p_payload_body_size) +{ int ioctl_ret; struct tdx_quote_req arg; - p_get_quote_blob->version = 1; - p_get_quote_blob->status = 0; - p_get_quote_blob->in_len = HEADER_SIZE + msg_size; - p_get_quote_blob->out_len = 0; arg.buf = (__u64)p_get_quote_blob; arg.len = REQ_BUF_SIZE; ioctl_ret = ioctl(devfd, TDX_CMD_GET_QUOTE, &arg); if (EBUSY == ioctl_ret) { TDX_TRACE; - ret = TDX_ATTEST_ERROR_BUSY; - goto ret_point; + return TDX_ATTEST_ERROR_BUSY; } else if (ioctl_ret) { TDX_TRACE; - ret = TDX_ATTEST_ERROR_QUOTE_FAILURE; - goto ret_point; + syslog(LOG_ERR, "libtdx_attest: cannot get quote by TD call."); + return TDX_ATTEST_ERROR_QUOTE_FAILURE; } if (p_get_quote_blob->status || p_get_quote_blob->out_len <= HEADER_SIZE) { TDX_TRACE; if (GET_QUOTE_IN_FLIGHT == p_get_quote_blob->status) { - ret = TDX_ATTEST_ERROR_BUSY; + return TDX_ATTEST_ERROR_BUSY; } else if (GET_QUOTE_SERVICE_UNAVAILABLE == p_get_quote_blob->status) { - ret = TDX_ATTEST_ERROR_NOT_SUPPORTED; + return TDX_ATTEST_ERROR_NOT_SUPPORTED; } else { - ret = TDX_ATTEST_ERROR_UNEXPECTED; + return TDX_ATTEST_ERROR_UNEXPECTED; } - goto ret_point; } - //in_msg_size is the size of serialized response + uint32_t body_size = 0; for (unsigned i = 0; i < HEADER_SIZE; ++i) { - in_msg_size = in_msg_size * 256 + ((p_blob_payload[i]) & 0xFF); + body_size = body_size * 256 + ((((uint8_t*)p_get_quote_blob->data)[i]) & 0xFF); } - if (in_msg_size != p_get_quote_blob->out_len - HEADER_SIZE) { + if (body_size != p_get_quote_blob->out_len - HEADER_SIZE) { TDX_TRACE; - ret = TDX_ATTEST_ERROR_UNEXPECTED; - goto ret_point; + return TDX_ATTEST_ERROR_UNEXPECTED; } - #ifdef DEBUG - fprintf(stdout, "\nGet %u bytes response from tdvmcall", in_msg_size); - #endif + + *p_payload_body_size = body_size; +#ifdef DEBUG + fprintf(stdout, "\nGet %u bytes response from tdvmcall", body_size); +#endif + return TDX_ATTEST_SUCCESS; +} -done: - qgs_msg_ret = qgs_msg_inflate_get_quote_resp( - p_blob_payload + HEADER_SIZE, in_msg_size, - &p_selected_id, &id_size, - &p_quote, "e_size); - if (QGS_MSG_SUCCESS != qgs_msg_ret) { - #ifdef DEBUG - fprintf(stdout, "\nqgs_msg_inflate_get_quote_resp return 0x%x", qgs_msg_ret); - #endif - ret = TDX_ATTEST_ERROR_UNEXPECTED; +tdx_attest_error_t tdx_att_get_quote( + const tdx_report_data_t *p_tdx_report_data, + const tdx_uuid_t *p_att_key_id_list, + uint32_t list_size, + tdx_uuid_t *p_att_key_id, + uint8_t **pp_quote, + uint32_t *p_quote_size, + uint32_t flags) +{ + tdx_attest_error_t ret = TDX_ATTEST_ERROR_UNEXPECTED; + + if ((!p_att_key_id_list && list_size) || + (p_att_key_id_list && !list_size)) { + return TDX_ATTEST_ERROR_INVALID_PARAMETER; + } + if (!pp_quote) { + return TDX_ATTEST_ERROR_INVALID_PARAMETER; + } + if (flags) { + //TODO: I think we need to have a runtime version to make this flag usable. + return TDX_ATTEST_ERROR_INVALID_PARAMETER; + } + + // Currently only intel TDQE are supported + if (1 < list_size) { + return TDX_ATTEST_ERROR_INVALID_PARAMETER; + } + if (p_att_key_id_list && memcmp(p_att_key_id_list, &g_intel_tdqe_uuid, + sizeof(g_intel_tdqe_uuid))) { + return TDX_ATTEST_ERROR_UNSUPPORTED_ATT_KEY_ID; + } + + *pp_quote = NULL; + + struct tdx_quote_hdr *p_get_quote_blob = malloc(REQ_BUF_SIZE); + if (!p_get_quote_blob) { + return TDX_ATTEST_ERROR_OUT_OF_MEMORY; + } + + uint32_t payload_body_size = 0; + + tdx_report_t tdx_report; + memset(&tdx_report, 0, sizeof(tdx_report)); + + int devfd = open(TDX_ATTEST_DEV_PATH, O_RDWR | O_SYNC); + if (-1 == devfd) { + TDX_TRACE; + free(p_get_quote_blob); + return TDX_ATTEST_ERROR_DEVICE_FAILURE; + } + + ret = get_tdx_report(devfd, p_tdx_report_data, &tdx_report); + if (TDX_ATTEST_SUCCESS != ret) { goto ret_point; } - // We've called qgs_msg_inflate_get_quote_resp, the message type should be GET_QUOTE_RESP - p_header = (qgs_msg_header_t *)(p_blob_payload + HEADER_SIZE); - if (p_header->error_code != 0) { - #ifdef DEBUG - fprintf(stdout, "\nerror code in resp msg is 0x%x", p_header->error_code); - #endif - ret = TDX_ATTEST_ERROR_UNEXPECTED; + ret = generate_get_quote_blob(&tdx_report, p_get_quote_blob); + if (TDX_ATTEST_SUCCESS != ret) { goto ret_point; } - *pp_quote = malloc(quote_size); - if (!*pp_quote) { - ret = TDX_ATTEST_ERROR_OUT_OF_MEMORY; + + ret = vsock_get_quote_payload((uint8_t*)p_get_quote_blob->data, p_get_quote_blob->in_len, &payload_body_size); + if (TDX_ATTEST_SUCCESS == ret) { + ret = extract_quote_from_blob_payload((uint8_t*)p_get_quote_blob->data, payload_body_size, pp_quote, p_quote_size); + } + if (TDX_ATTEST_SUCCESS == ret || TDX_ATTEST_ERROR_NOT_SUPPORTED != ret) { goto ret_point; } - memcpy(*pp_quote, p_quote, quote_size); - if (p_quote_size) { - *p_quote_size = quote_size; + +#ifdef DEBUG + fprintf(stdout, "\ngoto configfs logic\n"); +#endif + + ret = configfs_get_quote(p_tdx_report_data, pp_quote, p_quote_size); + if (TDX_ATTEST_SUCCESS == ret || TDX_ATTEST_ERROR_NOT_SUPPORTED != ret) { + goto ret_point; } - if (p_att_key_id) { - *p_att_key_id = g_intel_tdqe_uuid; + +#ifdef DEBUG + fprintf(stdout, "\ngoto legacy logic\n"); +#endif + + ret = tdcall_get_quote_payload(devfd, p_get_quote_blob, &payload_body_size); + if (TDX_ATTEST_SUCCESS == ret) { + ret = extract_quote_from_blob_payload((uint8_t*)p_get_quote_blob->data, payload_body_size, pp_quote, p_quote_size); } - ret = TDX_ATTEST_SUCCESS; ret_point: - if (s >= 0) { - close(s); - } - if (-1 != devfd) { - close(devfd); + if (TDX_ATTEST_SUCCESS == ret && p_att_key_id) { + *p_att_key_id = g_intel_tdqe_uuid; } - qgs_msg_free(p_req); + close(devfd); free(p_get_quote_blob); return ret;