//Function to verify that ECDSA signature of XEGB is correct sgx_status_t verify_xegb(const extended_epid_group_blob_t& xegb, uint8_t *result){ if (lv_htons(xegb.data_length) != EXTENDED_EPID_GROUP_BLOB_DATA_LEN || xegb.format_id != XEGB_FORMAT_ID){ return SGX_ERROR_INVALID_PARAMETER; } sgx_status_t status = SGX_SUCCESS; sgx_ecc_state_handle_t handle= 0; sgx_ec256_signature_t ec_signature; status = sgx_ecc256_open_context(&handle); if(SGX_SUCCESS!=status){ return status; } se_static_assert(sizeof(ec_signature)==sizeof(xegb.signature)); memcpy(&ec_signature, xegb.signature, sizeof(xegb.signature)); SWAP_ENDIAN_32B(ec_signature.x); SWAP_ENDIAN_32B(ec_signature.y); status = sgx_ecdsa_verify(reinterpret_cast<const uint8_t *>(&xegb), static_cast<uint32_t>(sizeof(xegb)-sizeof(xegb.signature)), const_cast<sgx_ec256_public_t *>(&g_sdsk_pub_key_little_endian), &ec_signature, result, handle); (void)sgx_ecc256_close_context(handle); if(SGX_SUCCESS!=status){ return status; } return SGX_SUCCESS; }
//Function to verify the ECDSA signature of a PEK //SHA1 value for integrity checking is not verified since the ECDSA verification could make sure the integrity at the same time. sgx_status_t check_pek_signature(const signed_pek_t& signed_pek, const sgx_ec256_public_t* pek_sk, uint8_t *result) { sgx_status_t status = SGX_SUCCESS; sgx_ecc_state_handle_t handle= 0; sgx_ec256_signature_t ec_signature; status = sgx_ecc256_open_context(&handle); if(SGX_SUCCESS!=status){ return status; } se_static_assert(sizeof(ec_signature)==sizeof(signed_pek.pek_signature)); memcpy(&ec_signature, signed_pek.pek_signature, sizeof(signed_pek.pek_signature)); SWAP_ENDIAN_32B(ec_signature.x); SWAP_ENDIAN_32B(ec_signature.y); status = sgx_ecdsa_verify(reinterpret_cast<const uint8_t *>(&signed_pek), static_cast<uint32_t>(sizeof(signed_pek.n)+sizeof(signed_pek.e)), pek_sk, &ec_signature, result, handle); (void)sgx_ecc256_close_context(handle); return status; }
int ias_verify_attestation_evidence( sample_quote_t *p_isv_quote, uint8_t* pse_manifest, ias_att_report_t* p_attestation_verification_report) { int ret = 0; sample_ecc_state_handle_t ecc_state = NULL; //unused parameters UNUSED(pse_manifest); if((NULL == p_isv_quote) || (NULL == p_attestation_verification_report)) { return -1; } //Decrypt the Quote signature and verify. p_attestation_verification_report->id = 0x12345678; p_attestation_verification_report->status = IAS_QUOTE_OK; p_attestation_verification_report->revocation_reason = IAS_REVOC_REASON_NONE; p_attestation_verification_report->info_blob.sample_epid_group_status = 0 << IAS_EPID_GROUP_STATUS_REVOKED_BIT_POS | 0 << IAS_EPID_GROUP_STATUS_REKEY_AVAILABLE_BIT_POS; p_attestation_verification_report->info_blob.sample_tcb_evaluation_status = 0 << IAS_TCB_EVAL_STATUS_CPUSVN_OUT_OF_DATE_BIT_POS | 0 << IAS_TCB_EVAL_STATUS_ISVSVN_OUT_OF_DATE_BIT_POS; p_attestation_verification_report->info_blob.pse_evaluation_status = 0 << IAS_PSE_EVAL_STATUS_ISVSVN_OUT_OF_DATE_BIT_POS | 0 << IAS_PSE_EVAL_STATUS_EPID_GROUP_REVOKED_BIT_POS | 0 << IAS_PSE_EVAL_STATUS_PSDASVN_OUT_OF_DATE_BIT_POS | 0 << IAS_PSE_EVAL_STATUS_SIGRL_OUT_OF_DATE_BIT_POS | 0 << IAS_PSE_EVAL_STATUS_PRIVRL_OUT_OF_DATE_BIT_POS; memset(p_attestation_verification_report-> info_blob.latest_equivalent_tcb_psvn, 0, PSVN_SIZE); memset(p_attestation_verification_report->info_blob.latest_pse_isvsvn, 0, ISVSVN_SIZE); memset(p_attestation_verification_report->info_blob.latest_psda_svn, 0, PSDA_SVN_SIZE); memset(p_attestation_verification_report->info_blob.performance_rekey_gid, 0, GID_SIZE); // @TODO: Product signing algorithm still TBD. May be RSA2048 signing. // Generate the Service providers ECCDH key pair. do { ret = sample_ecc256_open_context(&ecc_state); if (SAMPLE_SUCCESS != ret) { fprintf(stderr, "\nError, cannot get ECC cotext in [%s].", __FUNCTION__); ret = -1; break; } // Sign ret = sample_ecdsa_sign( (uint8_t *)&p_attestation_verification_report-> info_blob.sample_epid_group_status, sizeof(ias_platform_info_blob_t) - sizeof(sample_ec_sign256_t), (sample_ec256_private_t *)&g_rk_priv_key, (sample_ec256_signature_t *)&p_attestation_verification_report-> info_blob.signature, ecc_state); if (SAMPLE_SUCCESS != ret) { fprintf(stderr, "\nError, sign ga_gb fail in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } SWAP_ENDIAN_32B(p_attestation_verification_report-> info_blob.signature.x); SWAP_ENDIAN_32B(p_attestation_verification_report-> info_blob.signature.y); }while (0); if (ecc_state) { sample_ecc256_close_context(ecc_state); } p_attestation_verification_report->pse_status = IAS_PSE_OK; // For now, don't simulate the policy reports. p_attestation_verification_report->policy_report_size = 0; return(ret); }
/* * External function used to get quote. Prefix "emp_" means it is a pointer * points memory outside enclave. * * @param p_blob[in, out] Pointer to the EPID Blob. * @param blob_size[in] The size of EPID Blob, in bytes. * @param p_enclave_report[in] The application enclave's report. * @param quote_type[in] The type of quote, random based or name based. * @param p_spid[in] Pointer to SPID. * @param p_nonce[in] Pointer to nonce. * @param emp_sig_rl[in] Pointer to SIG-RL. * @param sig_rl_size[in] The size of SIG-RL, in bytes. * @param p_qe_report[out] Pointer to QE report, which reportdata is * sha256(nonce || quote) * @param emp_quote[out] Pointer to the output buffer for quote. * @param quote_size[in] The size of emp_quote, in bytes. * @param pce_isvsvn[in] The ISVSVN of PCE. * @return ae_error_t AE_SUCCESS for success, otherwise for errors. */ uint32_t get_quote( uint8_t *p_blob, uint32_t blob_size, const sgx_report_t *p_enclave_report, sgx_quote_sign_type_t quote_type, const sgx_spid_t *p_spid, const sgx_quote_nonce_t *p_nonce, const uint8_t *emp_sig_rl, uint32_t sig_rl_size, sgx_report_t *p_qe_report, uint8_t *emp_quote, uint32_t quote_size, sgx_isv_svn_t pce_isvsvn) { ae_error_t ret = AE_SUCCESS; EpidStatus epid_ret = kEpidNoErr; MemberCtx *p_epid_context = NULL; sgx_quote_t quote_body; uint8_t is_resealed = 0; sgx_basename_t basename = {{0}}; uint64_t sign_size = 0; sgx_status_t se_ret = SGX_SUCCESS; sgx_report_t qe_report; uint64_t required_buffer_size = 0; se_sig_rl_t sig_rl_header; se_plaintext_epid_data_sdk_t plaintext; sgx_ec256_signature_t ec_signature; sgx_cpu_svn_t cpusvn; memset("e_body, 0, sizeof(quote_body)); memset(&sig_rl_header, 0, sizeof(sig_rl_header)); memset(&plaintext, 0, sizeof(plaintext)); memset(&ec_signature, 0, sizeof(ec_signature)); memset(&cpusvn, 0, sizeof(cpusvn)); /* Actually, some cases here will be checked with code generated by edger8r. Here we just want to defend in depth. */ if((NULL == p_blob) || (NULL == p_enclave_report) || (NULL == p_spid) || (NULL == emp_quote) || (!quote_size) || ((NULL != emp_sig_rl) && (sig_rl_size < sizeof(se_sig_rl_t) + 2 * SE_ECDSA_SIGN_SIZE)) // // this size check could mispredict and cause us to // overflow, but we have an lfence below // that's safe to use for this case // || ((NULL == emp_sig_rl) && (sig_rl_size != 0))) return QE_PARAMETER_ERROR; if(SGX_TRUSTED_EPID_BLOB_SIZE_SDK != blob_size) return QE_PARAMETER_ERROR; // // this could mispredict and cause us to // overflow, but we have an lfence below // that's safe to use for this case // if(SGX_LINKABLE_SIGNATURE != quote_type && SGX_UNLINKABLE_SIGNATURE != quote_type) return QE_PARAMETER_ERROR; if(!p_nonce && p_qe_report) return QE_PARAMETER_ERROR; if(p_nonce && !p_qe_report) return QE_PARAMETER_ERROR; /* To reduce the memory footprint of QE, we should leave sig_rl and quote buffer outside enclave. */ if(!sgx_is_outside_enclave(emp_sig_rl, sig_rl_size)) return QE_PARAMETER_ERROR; // // for user_check SigRL input // based on quote_size input parameter // sgx_lfence(); if(!sgx_is_outside_enclave(emp_quote, quote_size)) return QE_PARAMETER_ERROR; /* Check whether p_blob is copied into EPC. If we want to reduce the memory usage, maybe we can leave the p_blob outside EPC. */ if(!sgx_is_within_enclave(p_blob, blob_size)) return QE_PARAMETER_ERROR; if(!sgx_is_within_enclave(p_enclave_report, sizeof(*p_enclave_report))) return QE_PARAMETER_ERROR; if(!sgx_is_within_enclave(p_spid, sizeof(*p_spid))) return QE_PARAMETER_ERROR; /* If the code reach here, if p_nonce is NULL, then p_qe_report will be NULL also. So we only check p_nonce here.*/ if(p_nonce) { /* Actually Edger8r will alloc the buffer within EPC, this is just kind of defense in depth. */ if(!sgx_is_within_enclave(p_nonce, sizeof(*p_nonce))) return QE_PARAMETER_ERROR; if(!sgx_is_within_enclave(p_qe_report, sizeof(*p_qe_report))) return QE_PARAMETER_ERROR; } /* Verify the input report. */ if(SGX_SUCCESS != sgx_verify_report(p_enclave_report)) return QE_PARAMETER_ERROR; /* Verify EPID p_blob and create the context */ ret = random_stack_advance(verify_blob_internal, p_blob, blob_size, &is_resealed, TRUE, plaintext, &p_epid_context, &cpusvn); if(AE_SUCCESS != ret) goto CLEANUP; /* If SIG-RL is provided, we should check its size. */ if(emp_sig_rl) { uint64_t temp_size = 0; uint64_t n2 = 0; memcpy(&sig_rl_header, emp_sig_rl, sizeof(sig_rl_header)); if(sig_rl_header.protocol_version != SE_EPID_SIG_RL_VERSION) { ret = QE_PARAMETER_ERROR; goto CLEANUP; } if(sig_rl_header.epid_identifier != SE_EPID_SIG_RL_ID) { ret = QE_PARAMETER_ERROR; goto CLEANUP; } if(memcmp(&sig_rl_header.sig_rl.gid, &plaintext.epid_group_cert.gid, sizeof(sig_rl_header.sig_rl.gid))) { ret = QE_PARAMETER_ERROR; goto CLEANUP; } temp_size = se_get_sig_rl_size(&sig_rl_header); if(temp_size != sig_rl_size) { ret = QE_PARAMETER_ERROR; goto CLEANUP; } se_static_assert(sizeof(ec_signature.x) == SE_ECDSA_SIGN_SIZE); se_static_assert(sizeof(ec_signature.y) == SE_ECDSA_SIGN_SIZE); memcpy(ec_signature.x, emp_sig_rl + sig_rl_size - (SE_ECDSA_SIGN_SIZE * 2), sizeof(ec_signature.x)); SWAP_ENDIAN_32B(ec_signature.x); memcpy(ec_signature.y, emp_sig_rl + sig_rl_size - (SE_ECDSA_SIGN_SIZE * 1), sizeof(ec_signature.y)); SWAP_ENDIAN_32B(ec_signature.y); n2 = SWAP_4BYTES(sig_rl_header.sig_rl.n2); temp_size = sizeof(EpidSignature) - sizeof(NrProof) + n2 * sizeof(NrProof); if(temp_size > UINT32_MAX) { ret = QE_PARAMETER_ERROR; goto CLEANUP; } sign_size = temp_size; } else { sign_size = sizeof(BasicSignature) + sizeof(uint32_t) // rl_ver + sizeof(uint32_t); // rl_num } /* Verify sizeof basename is large enough and it should always be true*/ se_static_assert(sizeof(basename) > sizeof(*p_spid)); /* Because basename has already been zeroed, so we don't need to concatenating with 0s.*/ memcpy(&basename, p_spid, sizeof(*p_spid)); if(SGX_UNLINKABLE_SIGNATURE == quote_type) { uint8_t *p = (uint8_t *)&basename + sizeof(*p_spid); se_ret = sgx_read_rand(p, sizeof(basename) - sizeof(*p_spid)); if(SGX_SUCCESS != se_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } } epid_ret = EpidRegisterBasename(p_epid_context, (uint8_t *)&basename, sizeof(basename)); if(kEpidNoErr != epid_ret) { ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } required_buffer_size = SE_QUOTE_LENGTH_WITHOUT_SIG + sign_size; /* We should make sure the buffer size is big enough. */ if(quote_size < required_buffer_size) { ret = QE_PARAMETER_ERROR; goto CLEANUP; } // // for user_check SigRL input // based on n2 field in SigRL // sgx_lfence(); /* Copy the data in the report into quote body. */ memset(emp_quote, 0, quote_size); quote_body.version = QE_QUOTE_VERSION; quote_body.sign_type = (uint16_t)quote_type; quote_body.pce_svn = pce_isvsvn; // Both are little endian quote_body.xeid = plaintext.xeid; // Both are little endian se_static_assert(sizeof(plaintext.epid_group_cert.gid) == sizeof(OctStr32)); se_static_assert(sizeof(quote_body.epid_group_id) == sizeof(uint32_t)); ((uint8_t *)("e_body.epid_group_id))[0] = plaintext.epid_group_cert.gid.data[3]; ((uint8_t *)("e_body.epid_group_id))[1] = plaintext.epid_group_cert.gid.data[2]; ((uint8_t *)("e_body.epid_group_id))[2] = plaintext.epid_group_cert.gid.data[1]; ((uint8_t *)("e_body.epid_group_id))[3] = plaintext.epid_group_cert.gid.data[0]; memcpy("e_body.basename, &basename, sizeof(quote_body.basename)); // Get the QE's report. se_ret = sgx_create_report(NULL, NULL, &qe_report); if(SGX_SUCCESS != se_ret) { ret = QE_PARAMETER_ERROR; goto CLEANUP; } // Copy QE's security version in to Quote body. quote_body.qe_svn = qe_report.body.isv_svn; // Copy the incoming report into Quote body. memcpy("e_body.report_body, &(p_enclave_report->body), sizeof(quote_body.report_body)); /* Because required_buffer_size is larger than signature_len, so if we get here, then no integer overflow will ocur. */ quote_body.signature_len = (uint32_t)(sizeof(se_wrap_key_t) + QUOTE_IV_SIZE + sizeof(uint32_t) + sign_size + sizeof(sgx_mac_t)); /* Make the signature. */ ret = qe_epid_sign(p_epid_context, plaintext, &basename, emp_sig_rl ? ((const se_sig_rl_t *)emp_sig_rl)->sig_rl.bk : NULL, &sig_rl_header, &ec_signature, p_enclave_report, p_nonce, p_qe_report, emp_quote, "e_body, (uint32_t)sign_size); if(AE_SUCCESS != ret) { // Only need to clean the buffer after the fixed length part. memset_s(emp_quote + sizeof(sgx_quote_t), quote_size - sizeof(sgx_quote_t), 0, quote_size - sizeof(sgx_quote_t)); goto CLEANUP; } memcpy(emp_quote, "e_body, sizeof(sgx_quote_t)); CLEANUP: if(p_epid_context) epid_member_delete(&p_epid_context); return ret; }