ae_error_t CertificateProvisioningProtocol::aesCMAC(const upse::Buffer& key, const upse::Buffer& message, upse::Buffer& cmac) { ae_error_t status = AE_FAILURE; do { if (key.getSize() != sizeof(sgx_aes_gcm_128bit_key_t)) break; status = cmac.Alloc(sizeof(sgx_cmac_128bit_tag_t)); if (AE_FAILED(status)) break; uint8_t* pCMAC; status = upse::BufferWriter(cmac).reserve(cmac.getSize(), &pCMAC); if (AE_FAILED(status)) break; sgx_status_t sgx_status; sgx_status = sgx_rijndael128_cmac_msg(reinterpret_cast<const sgx_aes_gcm_128bit_key_t *>(key.getData()), message.getData(), message.getSize(), reinterpret_cast<sgx_cmac_128bit_tag_t *>(pCMAC)); if (SGX_SUCCESS != sgx_status) { status = AE_FAILURE; break; } status = AE_SUCCESS; } while (0); return status; }
ae_error_t CertificateProvisioningProtocol::aesGCMDecrypt(const upse::Buffer& iv, const upse::Buffer& key, const upse::Buffer& cipherText, const upse::Buffer& aad, const upse::Buffer& mac, upse::Buffer& plainText) { ae_error_t status = AE_FAILURE; do { if (key.getSize() != sizeof(sgx_aes_gcm_128bit_key_t)) break; status = plainText.Alloc(cipherText.getSize()); if (AE_FAILED(status)) break; uint8_t* pPlainText = NULL; status = upse::BufferWriter(plainText).reserve(plainText.getSize(), &pPlainText); if (AE_FAILED(status)) break; sgx_status_t sgx_status; sgx_status = sgx_rijndael128GCM_decrypt(reinterpret_cast<const sgx_aes_gcm_128bit_key_t *>(key.getData()), cipherText.getData(), cipherText.getSize(), pPlainText, iv.getData(), IV_SIZE, aad.getData(), aad.getSize(), reinterpret_cast<const sgx_aes_gcm_128bit_tag_t *>(mac.getData())); if (SGX_SUCCESS != sgx_status) { AESM_LOG_ERROR("%s", g_event_string_table[SGX_EVENT_PSE_CERT_PROV_INTEGRITY_ERROR]); status = AE_FAILURE; break; } status = AE_SUCCESS; } while (0); return status; }
ae_error_t CertificateProvisioningProtocol::sendReceive(const upse::Buffer& sendSerialized, upse::Buffer& recvSerialized) { ae_error_t status = AE_FAILURE; uint8_t* recv = NULL; uint32_t recv_size = 0; do { AESM_DBG_INFO("start send msg"); status = AESMNetworkEncoding::aesm_send_recv_msg_encoding(m_url.c_str(), const_cast<uint8_t *>(sendSerialized.getData()), sendSerialized.getSize(), recv, recv_size); if (AE_FAILED(status)) break; AESM_DBG_INFO("msg received with size %u", recv_size); status = recvSerialized.Alloc(recv_size); if (AE_FAILED(status)) break; AESM_DBG_INFO("buffer alloced"); status = upse::BufferWriter(recvSerialized).writeRaw(recv, recv_size); if (AE_FAILED(status)) break; AESM_DBG_INFO("buffer written"); status = AE_SUCCESS; } while (0); if (NULL != recv) AESMNetworkEncoding::aesm_free_response_msg(recv); return status; }
ae_error_t CertificateProvisioningProtocol::SendM1_ReceiveM2 ( /*in */ const uint32_t gid, /*out*/ upse::Buffer& nonce, /*out*/ upse::Buffer& sigRLBuffer ) { ae_error_t status = AE_FAILURE; upse::Buffer serializedMsg1; upse::Buffer serializedMsg2; do { BREAK_IF_FALSE((m_is_initialized), status, AESM_PSE_PR_BACKEND_NOT_INITIALIZED); BREAK_IF_FALSE( (msg_next_state_M1 == m_nextState), status, AESM_PSE_PR_CALL_ORDER_ERROR); status = msg1_generate(*(const GroupId*)&gid, serializedMsg1); BREAK_IF_FAILED_ERR(status, AESM_PSE_PR_BACKEND_MSG1_GENERATE); // BREAK_IF_FAILED(status); status = sendReceive(serializedMsg1, serializedMsg2); if (AE_FAILED(status)) break; status = msg2_process(serializedMsg2, nonce, sigRLBuffer); if (AE_FAILED(status)) break; m_nextState = msg_next_state_M3; } while (0); return status; }
ae_error_t CertificateProvisioningProtocol::msg3_seq3_2_create_quote_signature_tlv(const upse::Buffer& quote, TLVsMsg& seq3_2_tlv_quote_signature) { ae_error_t status = AESM_PSE_PR_INTERNAL_ERROR; tlv_status_t tlv_status; do { if (sizeof(sgx_quote_t) > quote.getSize()) break; const sgx_quote_t* pQuote = (const sgx_quote_t*)quote.getData(); /* the QUOTE SIGNATURE TLV doesn't include Quote.signature_len */ uint32_t SigLen = pQuote->signature_len; if (sizeof(sgx_quote_t) + SigLen > quote.getSize()) break; const uint8_t *pSig = pQuote->signature; tlv_status = seq3_2_tlv_quote_signature.add_quote_signature(pSig, SigLen); status = tlv_error_2_pve_error(tlv_status); if (AE_FAILED(status)) break; status = AE_SUCCESS; } while (0); return status; }
aesm_error_t AESMLogic::get_launch_token( const uint8_t * mrenclave, uint32_t mrenclave_size, const uint8_t *public_key, uint32_t public_key_size, const uint8_t *se_attributes, uint32_t se_attributes_size, uint8_t * lictoken, uint32_t lictoken_size) { AESM_DBG_INFO("enter function"); CHECK_SERVICE_STATUS; AESMLogicLock lock(_le_mutex); CHECK_SERVICE_STATUS; ae_error_t ret_le = AE_SUCCESS; if (NULL == mrenclave || NULL == public_key || NULL == se_attributes || NULL == lictoken) { //sizes are checked in CLEClass::get_launch_token() AESM_DBG_TRACE("Invalid parameter"); return AESM_PARAMETER_ERROR; } ae_error_t ae_ret = CLEClass::instance().load_enclave(); if(ae_ret == AE_SERVER_NOT_AVAILABLE) { AESM_LOG_ERROR("%s", g_event_string_table[SGX_EVENT_SERVICE_UNAVAILABLE]); AESM_DBG_FATAL("LE not loaded due to AE_SERVER_NOT_AVAILABLE, possible SGX Env Not Ready"); return AESM_NO_DEVICE_ERROR; } else if(AE_FAILED(ae_ret)) { AESM_DBG_ERROR("LE not loaded:%d", ae_ret); return AESM_UNEXPECTED_ERROR; } ret_le = static_cast<ae_error_t>(CLEClass::instance().get_launch_token( const_cast<uint8_t *>(mrenclave), mrenclave_size, const_cast<uint8_t *>(public_key), public_key_size, const_cast<uint8_t *>(se_attributes), se_attributes_size, lictoken, lictoken_size)); switch (ret_le) { case AE_SUCCESS: return AESM_SUCCESS; case LE_INVALID_PARAMETER: AESM_DBG_TRACE("Invalid parameter"); return AESM_PARAMETER_ERROR; case LE_INVALID_ATTRIBUTE: case LE_INVALID_PRIVILEGE_ERROR: AESM_DBG_TRACE("Launch token error"); return AESM_GET_LICENSETOKEN_ERROR; case LE_WHITELIST_UNINITIALIZED_ERROR: AESM_DBG_TRACE("LE whitelist uninitialized error"); return AESM_UNEXPECTED_ERROR; default: AESM_DBG_WARN("unexpeted error %d", ret_le); return AESM_UNEXPECTED_ERROR; } }
ae_error_t CertificateProvisioningProtocol::encryptRSA_OAEP_SHA256(const public_key_t& publicKey, upse::BufferReader& plainTextReader, upse::Buffer& cipherText) { ae_error_t status = AE_FAILURE; void* rsa_pub_key = NULL; size_t dst_len = 0; do { if(SGX_SUCCESS != get_intel_rsa_pub_key(publicKey, &rsa_pub_key)) break; int plainTextSize = plainTextReader.getRemainingSize(); const uint8_t* pPlainText = NULL; if (AE_FAILED(plainTextReader.readRaw(&pPlainText))) break; int cipherTextSize = get_intel_pek_cipher_text_size(); if (AE_FAILED(cipherText.Alloc(cipherTextSize))) break; upse::BufferWriter cipherTextWriter(cipherText); uint8_t* pCipherText; if (AE_FAILED(cipherTextWriter.reserve(cipherText.getSize(), &pCipherText))) break; // Check the encrypt output length sgx_status_t res = sgx_rsa_pub_encrypt_sha256(rsa_pub_key, NULL, &dst_len, pPlainText, plainTextSize); if(res != SGX_SUCCESS || dst_len != cipherText.getSize()) break; res = sgx_rsa_pub_encrypt_sha256(rsa_pub_key, pCipherText, &dst_len, pPlainText, plainTextSize); if(res != SGX_SUCCESS) break; status = AE_SUCCESS; } while (0); free_intel_rsa_pub_key(rsa_pub_key); return status; }
ae_error_t CertificateProvisioningProtocol::aesGCMEncrypt(const upse::Buffer& iv, const upse::Buffer& key, const upse::Buffer& plainText, const upse::Buffer& aad, upse::Buffer& encryptedText, upse::Buffer& mac) { ae_error_t status = AE_FAILURE; do { if (key.getSize() != sizeof(sgx_aes_gcm_128bit_key_t)) break; status = encryptedText.Alloc(plainText.getSize()); if (AE_FAILED(status)) break; uint8_t* pEncryptedText; status = upse::BufferWriter(encryptedText).reserve(encryptedText.getSize(), &pEncryptedText); if (AE_FAILED(status)) break; status = mac.Alloc(sizeof(sgx_aes_gcm_128bit_tag_t)); if (AE_FAILED(status)) break; uint8_t* pMAC; status = upse::BufferWriter(mac).reserve(mac.getSize(), &pMAC); if (AE_FAILED(status)) break; sgx_status_t sgx_status; sgx_status = sgx_rijndael128GCM_encrypt(reinterpret_cast<const sgx_aes_gcm_128bit_key_t *>(key.getData()), plainText.getData(), plainText.getSize(), pEncryptedText, iv.getData(), IV_SIZE, aad.getData(), aad.getSize(), reinterpret_cast<sgx_aes_gcm_128bit_tag_t *>(pMAC)); if (SGX_SUCCESS != sgx_status) { status = AE_FAILURE; break; } status = AE_SUCCESS; } while (0); return status; }
ae_error_t CertificateProvisioningProtocol::msg1_create_seq2_1(TLVsMsg& seq2_1_tlv_block_cipher_info) { //* 2.1 Block Cipher Info TLV (TLV Type, Type, Version, Size, [SK]) ae_error_t status = AE_FAILURE; tlv_status_t tlv_status; do { status = get_random_value(SK_SIZE, M1SK); if (AE_FAILED(status)) break; tlv_status = seq2_1_tlv_block_cipher_info.add_block_cipher_info(M1SK.getData()); status = tlv_error_2_pve_error(tlv_status); if (AE_FAILED(status)) break; status = AE_SUCCESS; } while (0); return status; }
ae_error_t CertificateProvisioningProtocol::get_random_value(uint32_t size, upse::Buffer& randomValue) { ae_error_t status = AE_FAILURE; do { status = randomValue.Alloc(size); if (AE_FAILED(status)) break; uint8_t* p; upse::BufferWriter bw(randomValue); status = bw.reserve(size, &p); if (AE_FAILED(status)) break; status = aesm_read_rand(p, size); } while (0); return status; }
ae_error_t upsePersistentStorage::Write(aesm_data_id_t data_id, upse::Buffer& data) { ae_error_t status = AESM_PSE_PR_PERSISTENT_STORAGE_WRITE_ERROR; do { if (AE_FAILED(aesm_write_data(FT_PERSISTENT_STORAGE, data_id, data.getData(), data.getSize()))) break; status = AE_SUCCESS; } while (0); return status; }
ae_error_t CertificateProvisioningProtocol::msg1_create_seq2_0(const TLVsMsg& seq2_1_tlv_block_cipher_info, TLVsMsg& seq2_0_tlv_cipher_text) { //* 2.0 Cipher Text TLV (TLV Type, Type, Version, Size, [KeyID, EncryptedPayload is 2.1]) ae_error_t status = AE_FAILURE; tlv_status_t tlv_status; do { upse::Buffer seq2_1_encrypted_tlv; upse::Buffer encryptedBlockCipherInfo; const public_key_t& public_key = get_intel_pek(); // Encrypt TLV 2.1 upse::Buffer blockCipherInfo; status = blockCipherInfo.Alloc(seq2_1_tlv_block_cipher_info.get_tlv_msg(), seq2_1_tlv_block_cipher_info.get_tlv_msg_size()); if (AE_FAILED(status)) break; upse::BufferReader blockCipherInfoReader(blockCipherInfo); status = encryptRSA_OAEP_SHA256(public_key, blockCipherInfoReader, encryptedBlockCipherInfo); if (AE_FAILED(status)) break; tlv_status = seq2_0_tlv_cipher_text.add_cipher_text(encryptedBlockCipherInfo.getData(), encryptedBlockCipherInfo.getSize(), PEK_3072_PUB); status = tlv_error_2_pve_error(tlv_status); if (AE_FAILED(status)) break; status = AE_SUCCESS; } while (0); return status; }
aesm_error_t AESMLogic::white_list_register( const uint8_t *white_list_cert, uint32_t white_list_cert_size) { AESM_DBG_INFO("enter function"); CHECK_SERVICE_STATUS; AESMLogicLock lock(_le_mutex); CHECK_SERVICE_STATUS; ae_error_t ret_le = AE_SUCCESS; if (NULL == white_list_cert||0==white_list_cert_size){ AESM_DBG_TRACE("Invalid parameter"); return AESM_PARAMETER_ERROR; } ae_error_t ae_ret = CLEClass::instance().load_enclave(); if(ae_ret == AE_SERVER_NOT_AVAILABLE) { AESM_DBG_WARN("LE not loaded due to AE_SERVER_NOT_AVAILABLE, possible SGX Env Not Ready"); ret_le = save_unverified_white_list(white_list_cert, white_list_cert_size); } else if(AE_FAILED(ae_ret)) { AESM_DBG_ERROR("LE not loaded:%d", ae_ret); return AESM_UNEXPECTED_ERROR; }else{ ret_le = static_cast<ae_error_t>(CLEClass::instance().white_list_register( white_list_cert, white_list_cert_size)); } switch (ret_le) { case AE_SUCCESS: return AESM_SUCCESS; case LE_INVALID_PARAMETER: AESM_DBG_TRACE("Invalid parameter"); return AESM_PARAMETER_ERROR; case LE_INVALID_ATTRIBUTE: AESM_DBG_TRACE("Launch token error"); return AESM_GET_LICENSETOKEN_ERROR; default: AESM_DBG_WARN("unexpeted error %d", ret_le); return AESM_UNEXPECTED_ERROR; } }
ae_error_t ecall_tGenM7 ( /*in */ const SIGMA_S1_MESSAGE* pS1, /*in */ const EPID_SIG_RL* pSigRL, /*in */ uint32_t nTotalLen_SigRL, /*in */ const uint8_t* pOcspResp, /*in */ uint32_t nLen_OcspResp, /*in */ const uint8_t* pVerifierCert, /*in */ uint32_t nLen_VerifierCert, /*in */ const pairing_blob_t* pPairingBlob, /*in */ uint32_t nMax_S2, /*out*/ SIGMA_S2_MESSAGE* pS2, /*out*/ uint32_t* pnLen_S2 ) { ae_error_t status = AE_FAILURE; PSE_PR_SAFE_DELETE(s_pVerifier); do { s_pVerifier = new (std::nothrow) TEpidSigmaVerifier; BREAK_IF_TRUE((NULL == s_pVerifier), status, PSE_PR_INSUFFICIENT_MEMORY_ERROR); status = s_pVerifier->GenM7( pS1, pSigRL, nTotalLen_SigRL, pOcspResp, nLen_OcspResp, pVerifierCert, nLen_VerifierCert, pPairingBlob, nMax_S2, pS2, pnLen_S2); BREAK_IF_FAILED(status); } while (0); if (AE_FAILED(status)) PSE_PR_SAFE_DELETE(s_pVerifier); return status; }
ae_error_t CertificateProvisioningProtocol::msg3_seq3_1_create_quote_tlv(const upse::Buffer& quoteBuffer, TLVsMsg& quoteTLV) { ae_error_t status = AESM_PSE_PR_INTERNAL_ERROR; tlv_status_t tlv_status; do { if (sizeof(sgx_quote_t) > quoteBuffer.getSize()) break; const sgx_quote_t* pQuote = (const sgx_quote_t*)quoteBuffer.getData(); tlv_status = quoteTLV.add_quote((uint8_t*)pQuote, static_cast<uint32_t>(sizeof(sgx_quote_t)-sizeof(pQuote->signature_len))); status = tlv_error_2_pve_error(tlv_status); if (AE_FAILED(status)) break; } while (0); return status; }
ae_error_t CertificateProvisioningProtocol::msg1_create_seq3_0(const TLVsMsg& seq3_1_tlv_epid_gid, const provision_request_header_t& serializedHeader, const upse::Buffer& ek1, TLVsMsg& seq3_0_tlv_block_cipher_text, upse::Buffer& mac) { //* 3.0 Block Cipher Text TLV (TLV Type, Type, Version, Size, [IV, EncryptedPayload is 3.1]) ae_error_t status = AE_FAILURE; tlv_status_t tlv_status; do { status = get_random_value(IV_SIZE, M1IV); if (AE_FAILED(status)) break; upse::Buffer aad; status = aad.Alloc(sizeof(serializedHeader)); if (AE_FAILED(status)) break; upse::BufferWriter aadWriter(aad); status = aadWriter.writeRaw((const uint8_t*)&serializedHeader, sizeof(serializedHeader)); if (AE_FAILED(status)) break; upse::Buffer epidGid; status = epidGid.Alloc(seq3_1_tlv_epid_gid.get_tlv_msg(), seq3_1_tlv_epid_gid.get_tlv_msg_size()); if (AE_FAILED(status)) break; upse::Buffer encryptedPayload; status = aesGCMEncrypt(M1IV, ek1, epidGid, aad, encryptedPayload, mac); if (AE_FAILED(status)) break; tlv_status = seq3_0_tlv_block_cipher_text.add_block_cipher_text(M1IV.getData(), encryptedPayload.getData(), encryptedPayload.getSize()); status = tlv_error_2_pve_error(tlv_status); if (AE_FAILED(status)) break; status = AE_SUCCESS; } while (0); return status; }
ae_error_t SigmaHelper::GetOcspResponseFromServer ( /*in */ const std::list<upse::Buffer>& certChain, /*in */ const OCSP_REQ& ocspReq, /*out*/ upse::Buffer& ocspResp ) { ae_error_t status = AE_FAILURE; int nPaddedBytes = 0; int nTotalOcspBytes = 0; do { if (ocspReq.ReqType == NO_OCSP) { status = AE_SUCCESS; break; } const char *url = EndpointSelectionInfo::instance().get_server_url( PSE_OCSP); if (url == NULL){ return OAL_CONFIG_FILE_ERROR; } // Load the root certificate into a local buffer upse::Buffer rootCert; SigmaHelper::GetRootCA(rootCert); std::list<upse::Buffer> ocspResponseList; // loop through chain and get an OCSP Response for each certificate/issuer pair bool fDone = false; // // certs were added leaf to root direction (assuming server functions according to spec) // std::list<upse::Buffer>::const_iterator itCertificate = certChain.begin(); do { if (itCertificate == certChain.end()) { status = AE_FAILURE; break; } upse::Buffer ocspResponse; const upse::Buffer& verifierCertificate = *itCertificate; ++itCertificate; int busy_loop = 0; do { if (itCertificate != certChain.end()) { const upse::Buffer& issuerCertificate = *itCertificate; status = Get_OCSPResponse(url, &ocspReq.OcspNonce, verifierCertificate, issuerCertificate, ocspResponse); } else { fDone = true; const upse::Buffer& issuerCertificate = rootCert; status = Get_OCSPResponse(url, &ocspReq.OcspNonce, verifierCertificate, issuerCertificate, ocspResponse); } if (AESM_PSE_PR_OCSP_RESPONSE_STATUS_TRYLATER != status) break; se_sleep(OCSP_BUSY_RETRY_SLEEP_MILLISECONDS); } while (busy_loop++ < MAX_OCSP_BUSY_RETRIES); if (AE_FAILED(status)) break; nPaddedBytes += REQUIRED_PADDING_DWORD_ALIGNMENT(ocspResponse.getSize()); nTotalOcspBytes += ocspResponse.getSize(); ocspResponseList.push_back(ocspResponse); } while (!fDone); if (AE_FAILED(status)) break; if (0 == ocspResponseList.size()) { status = AE_FAILURE; break; } nPaddedBytes = REQUIRED_PADDING_DWORD_ALIGNMENT(nTotalOcspBytes); if(UINT16_MAX-((int)sizeof(SIGMA_VLR_HEADER) + nPaddedBytes) < nTotalOcspBytes){ status = AE_FAILURE; break; } int nLength = static_cast<int>(sizeof(SIGMA_VLR_HEADER)) + nPaddedBytes + nTotalOcspBytes; ocspResp.Alloc(nLength); upse::BufferWriter bw(ocspResp); uint8_t* p; status = bw.reserve(nLength, &p); if (AE_FAILED(status)) break; OCSP_RESPONSE_VLR* pVLR = (OCSP_RESPONSE_VLR*)p; pVLR->VlrHeader.ID = OCSP_RESPONSE_VLR_ID; pVLR->VlrHeader.PaddedBytes = (UINT8)nPaddedBytes; pVLR->VlrHeader.Length = (UINT16)nLength; memset(pVLR->OcspResponse, 0, nPaddedBytes + nTotalOcspBytes); int nNext = 0; // // order above doesn't really matter since it's between verifier/host and ocsp responder // and each request/response is independent // spec basically says what's correct here // but we'll leave condition to show how to traverse in either order // #if !defined(LEAFTOROOT) #error LEAFTOROOT not defined #endif #if !LEAFTOROOT // // this clause adds responses from root to leaf // SGX_DBGPRINT_PRINT_STRING_LTP("root ocsp to leaf ocsp direction"); std::list<upse::Buffer>::reverse_iterator itRespList = ocspResponseList.rbegin(); for ( ; itRespList != ocspResponseList.rend(); ++itRespList) { const upse::Buffer& item = *itRespList; memcpy_s(pVLR->OcspResponse + nNext, item.getSize(), item.getData(), item.getSize()); nNext += item.getSize(); } #else SGX_DBGPRINT_PRINT_STRING_LTP("leaf ocsp to root ocsp direction"); // // this clause adds responses from leaf to root // std::list<upse::Buffer>::iterator itRespList = ocspResponseList.begin(); for ( ; itRespList != ocspResponseList.end(); ++itRespList) { const upse::Buffer& item = *itRespList; memcpy_s(pVLR->OcspResponse + nNext, item.getSize(), item.getData(), item.getSize()); nNext += item.getSize(); } #endif Helper::write_ocsp_response_vlr(ocspResp); status = AE_SUCCESS; } while (0); if (status == OAL_NETWORK_UNAVAILABLE_ERROR) { if (ocspReq.ReqType == CACHED && AE_SUCCEEDED(Helper::read_ocsp_response_vlr(ocspResp))) { status = AE_SUCCESS; } } SGX_DBGPRINT_PRINT_FUNCTION_AND_RETURNVAL(__FUNCTION__, status); return status; }
// // return values // SUCCESS: // NO_LONGTERM_PAIRING_BLOB: // DONT_NEED_UPDATE_PAIR_LTP: psda svn now up to date // MAY_NEED_UPDATE_LTP: psda updated, but may not be up to date // OLD_EPID11_RLS: // ae_error_t PlatformInfoLogic::need_long_term_pairing(const platform_info_blob_wrapper_t* platformInfoBlobWrapper) { AESM_DBG_TRACE("enter fun"); ae_error_t status = AE_SUCCESS; pairing_blob_t pairing_blob; if (AE_FAILED(Helper::read_ltp_blob(pairing_blob))) { status = AESM_NLTP_NO_LTP_BLOB; } else if (Helper::noPseCert()) { status = AESM_NPC_NO_PSE_CERT; } else { uint32_t current_psda_svn = PSDAService::instance().psda_svn; pse_pr_interface_psda* pPSDA = NULL; pPSDA = new(std::nothrow) pse_pr_interface_psda(); if (pPSDA == NULL) { return AE_OUT_OF_MEMORY_ERROR; } EPID_GID meGid; if (NULL != platformInfoBlobWrapper) { // // psda svn was bad, cse gid was good and now psda svn is good // fact that we may not be able to get current PSDA SVN doesn't matter // here as long as expression involving it evaluates to false // uint32_t pib_psda_svn; pib_psda_svn = latest_psda_svn(platformInfoBlobWrapper); //pairing_blob_t pairing_blob; //Helper::read_ltp_blob(pairing_blob); // // psda svn was bad, cse gid was good and now psda svn is good // fact that we may not be able to get current PSDA SVN doesn't matter // here as long as expression involving it evaluates to false // if (((psda_svn_out_of_date(platformInfoBlobWrapper)) && (current_psda_svn == pib_psda_svn)) || 0) //(!psda_svn_out_of_date(platformInfoBlobWrapper) && cse_gid_out_of_date(platformInfoBlobWrapper))) { status = AESM_NLTP_DONT_NEED_UPDATE_PAIR_LTP; // don't need update, but need pairing } else if (cse_gid_out_of_date(platformInfoBlobWrapper)) { if (AE_SUCCESS == pPSDA->get_csme_gid(&meGid)) { if (Helper::ltpBlobCseGid(pairing_blob) != meGid) { status = AESM_NLTP_DONT_NEED_UPDATE_PAIR_LTP; } } else { status = AESM_NLTP_DONT_NEED_UPDATE_PAIR_LTP; } } // // we need to handle cases where current psda svn or psda svn in ltp // blob is unavailable // no ltp blob is handled above // not being able to get current psda svn is handled elsewhere // we just need to make sure we don't return something misleading // else if (newer_psda_svn(current_psda_svn, Helper::ltpBlobPsdaSvn(pairing_blob))) //(currentCse_gid() != ltpBlobCse_gid())) // assume no rollback { status = AESM_NLTP_MAY_NEED_UPDATE_LTP; // may need update and need pairing } else if (old_epid11_rls(platformInfoBlobWrapper)) { status = AESM_NLTP_OLD_EPID11_RLS; } } else { if ((AE_SUCCESS == pPSDA->get_csme_gid(&meGid)) && (Helper::ltpBlobCseGid(pairing_blob) != meGid)) { status = AESM_NLTP_DONT_NEED_UPDATE_PAIR_LTP; } // // see comment above about what happens when no ltp blob // or we can't get current psda svn // else if (newer_psda_svn(current_psda_svn, Helper::ltpBlobPsdaSvn(pairing_blob))) //(currentCse_gid() != ltpBlobCse_gid())) { status = AESM_NLTP_MAY_NEED_UPDATE_LTP; } } delete pPSDA; pPSDA = NULL; } SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION(__FUNCTION__" returning ", status, status); return status; }
//********************************************************************* // Call quoting enclave to convert report to name-based quote //********************************************************************* static ae_error_t do_get_quote ( /*in */ upse::Buffer& reportBuffer, /*in */ upse::Buffer& sigRLBuffer, /*out*/ upse::Buffer& quoteBuffer ) { // Call QE to convert REPORT to a name-based QUOTE ae_error_t status = AE_FAILURE; ae_error_t tmp_status = AE_SUCCESS; do { #ifndef FAKE_QUOTE uint32_t nQuote; // in - Quote buffer size sgx_report_t enclaveReport; // in sgx_quote_sign_type_t quote_type; // in sgx_spid_t spid = {{0}}; // in uint8_t* pSigRL = NULL; // in uint32_t nSigRL = 0; // in - Sig RL buffer size memset(&enclaveReport, 0, sizeof(enclaveReport)); nSigRL = sigRLBuffer.getSize(); if (0 != nSigRL) pSigRL = const_cast<uint8_t*>(sigRLBuffer.getData()); if (SGX_SUCCESS != sgx_calc_quote_size(pSigRL, nSigRL, &nQuote)) break; tmp_status = quoteBuffer.Alloc(nQuote); if (AE_FAILED(tmp_status)) break; upse::BufferWriter bwQuote(quoteBuffer); uint8_t* pQuote; tmp_status = bwQuote.reserve(nQuote, &pQuote); // out if (AE_FAILED(tmp_status)) break; quote_type = SGX_UNLINKABLE_SIGNATURE; // or SGX_LINKABLE_SIGNATURE // LSB16(SHA256("SGX PSE PROVISIONING SERVER")) // const char* SPID_VALUE = "SGX PSE PROVISIONING SERVER"; // sgx_sha256_hash_t spid_hash; // sgx_sha256_msg((const uint8_t*)SPID_VALUE, strlen(SPID_VALUE), &spid_hash); // memcpy_s(spid.id, sizeof(spid.id), &spid_hash[0], 16); static uint8_t spid_hash[] = { 0x32, 0x81, 0xE5, 0x9E, 0xB1, 0x23, 0xFA, 0xCD, 0x56, 0xDB, 0x62, 0x1E, 0x3B, 0x37, 0xFB, 0xE2 }; memcpy_s(spid.id, sizeof(spid.id), spid_hash, sizeof(spid_hash)); if (reportBuffer.getSize() != sizeof(enclaveReport)) break; memcpy_s(&enclaveReport, reportBuffer.getSize(), reportBuffer.getData(), reportBuffer.getSize()); aesm_error_t result; result = AESMLogic::get_quote( (uint8_t*)&enclaveReport, sizeof(enclaveReport), quote_type, (uint8_t*)&spid, sizeof(spid), NULL, 0, pSigRL, nSigRL, NULL, 0, (uint8_t*)pQuote, nQuote); if (result == AESM_BUSY) { //EPID_PROVISION triggered, make sure previous EPID provision has finished ae_error_t temp_ret = wait_pve_thread(); BREAK_IF_TRUE(AE_SUCCESS != temp_ret , status, PSE_PR_PCH_EPID_UNKNOWN_ERROR); //redo get_quote result = AESMLogic::get_quote( (uint8_t*)&enclaveReport, sizeof(enclaveReport), quote_type, (uint8_t*)&spid, sizeof(spid), NULL, 0, pSigRL, nSigRL, NULL, 0, (uint8_t*)pQuote, nQuote); } BREAK_IF_TRUE(AESM_OUT_OF_EPC == result, status, AESM_AE_OUT_OF_EPC); BREAK_IF_TRUE(AESM_SUCCESS != result, status, AESM_PSE_PR_GET_QUOTE_ERROR); #else const uint16_t SIGNATURE_LENGTH = 32; tmp_status = quoteBuffer.Alloc(sizeof(sgx_quote_t) + SIGNATURE_LENGTH); if (AE_FAILED(tmp_status)) break; sgx_quote_t* pQuote; tmp_status = upse::BufferWriter(quoteBuffer).reserve(quoteBuffer.getSize(), (uint8_t**)&pQuote); if (AE_FAILED(tmp_status)) break; uint16_t CPUSVN = 1; pQuote->version = 1; memcpy_s(pQuote->epid_group_id, sizeof(pQuote->epid_group_id), &GID_TO_USE, sizeof(GID_TO_USE)); pQuote->report_body.isv_prod_id = 0x0002; //0x8086; pQuote->report_body.isv_svn = 1; memcpy_s(pQuote->report_body.cpu_svn, sizeof(pQuote->report_body.cpu_svn), &CPUSVN, sizeof(CPUSVN)); const sgx_report_t* pReport = (sgx_report_t*)reportBuffer.getData(); memcpy_s(pQuote->report_body.report_data, sizeof(pQuote->report_body.report_data), pReport->body.report_data, sizeof(pQuote->report_body.report_data)); pQuote->signature_len = SIGNATURE_LENGTH; //NOTE: The signature is not valid when doing a FAKE_QUOTE #endif status = AE_SUCCESS; } while (0); if ((AE_FAILURE == status) && AE_FAILED(tmp_status)) status = tmp_status; SGX_DBGPRINT_PRINT_FUNCTION_AND_RETURNVAL(__FUNCTION__, status); return status; }
//********************************************************************* // Call quoting enclave to get target info //********************************************************************* static ae_error_t do_quote_initialization ( /*out */ upse::Buffer& targetInfo, /*out */ GroupId* pGID ) { ae_error_t status = AE_FAILURE; do { BREAK_IF_TRUE( (NULL == pGID), status, PSE_PR_BAD_POINTER_ERROR); #ifndef FAKE_QUOTE if (AE_FAILED(targetInfo.Alloc(sizeof(sgx_target_info_t)))) break; upse::BufferWriter bwTargetInfo(targetInfo); uint8_t* p; status = bwTargetInfo.reserve(sizeof(sgx_target_info_t), &p); if (AE_FAILED(status)) break; sgx_target_info_t* pTargetInfo = (sgx_target_info_t*)p; aesm_error_t result; SGX_DBGPRINT_PRINT_ANSI_STRING("aesmLogic.init_quote?"); result = AESMLogic::init_quote( (uint8_t*)pTargetInfo, sizeof(sgx_target_info_t), (uint8_t*)pGID, sizeof(*pGID)); if (result == AESM_BUSY) { //EPID_PROVISION triggered, make sure previous EPID provision has finished ae_error_t temp_ret = wait_pve_thread(); BREAK_IF_TRUE(AE_SUCCESS != temp_ret , status, PSE_PR_PCH_EPID_UNKNOWN_ERROR); //redo init_quote result = AESMLogic::init_quote( (uint8_t*)pTargetInfo, sizeof(sgx_target_info_t), (uint8_t*)pGID, sizeof(*pGID)); } BREAK_IF_TRUE(AESM_UPDATE_AVAILABLE == result, status, PSW_UPDATE_REQUIRED); BREAK_IF_TRUE(AESM_OUT_OF_EPC == result, status, AESM_AE_OUT_OF_EPC); BREAK_IF_TRUE(AESM_SUCCESS != result, status, AESM_PSE_PR_INIT_QUOTE_ERROR); #else //NRG: m_tmpGID = 0; upse::Buffer m_tmpGID; if (AE_FAILED(m_tmpGID.Alloc(GID_TO_USE, sizeof(GID_TO_USE)))) break; // m_tmpGID = 1244; // upse::BufferWriter(m_tmpGID).writeRaw(GID_TO_USE, sizeof(GID_TO_USE)); SigmaData::SetGID(m_tmpGID); memcpy_s(pGID, sizeof(GroupId), m_tmpGID.getData(), sizeof(GroupId)); if (AE_FAILED(targetInfo.Alloc(sizeof(sgx_target_info_t)))) break; #endif SGX_DBGPRINT_PRINT_ANSI_STRING("aesmLogic.init_quote success"); status = AE_SUCCESS; } while (0); SGX_DBGPRINT_PRINT_FUNCTION_AND_RETURNVAL(__FUNCTION__, status); return status; }
ae_error_t ConvertBackendStatus(CertificateProvisioningProtocol& cpp, ae_error_t status) { if (AE_FAILED(status)) { if (PSE_PRS_OK != cpp.GetProtocolResponseStatus()) { SGX_DBGPRINT_ONE_STRING_ONE_INT("Backend ProtocolResponseStatus", cpp.GetProtocolResponseStatus()); switch (cpp.GetProtocolResponseStatus()) { case PSE_PRS_INVALID_GID: status = AESM_PSE_PR_BACKEND_INVALID_GID; break; case PSE_PRS_GID_REVOKED: status = AESM_PSE_PR_BACKEND_GID_REVOKED; break; case PSE_PRS_INVALID_QUOTE: status = AESM_PSE_PR_BACKEND_INVALID_QUOTE; break; case PSE_PRS_INVALID_REQUEST: status = AESM_PSE_PR_BACKEND_INVALID_REQUEST; break; default: status = AESM_PSE_PR_BACKEND_UNKNOWN_PROTOCOL_RESPONSE; break; } AESM_DBG_ERROR(g_event_string_table[SGX_EVENT_PSE_CERT_PROV_PROTOCOL_RESPONSE_FAILURE], status); AESM_LOG_ERROR(g_event_string_table[SGX_EVENT_PSE_CERT_PROV_PROTOCOL_RESPONSE_FAILURE], status); } else if (GRS_OK != cpp.GetGeneralResponseStatus()) { SGX_DBGPRINT_ONE_STRING_ONE_INT("Backend GeneralResponseStatus", cpp.GetGeneralResponseStatus()); switch (cpp.GetGeneralResponseStatus()) { case GRS_SERVER_BUSY: status = AESM_PSE_PR_BACKEND_SERVER_BUSY; break; case GRS_INTEGRITY_CHECK_FAIL: status = AESM_PSE_PR_BACKEND_INTEGRITY_CHECK_FAIL; break; case GRS_INCORRECT_SYNTAX: status = AESM_PSE_PR_BACKEND_INCORRECT_SYNTAX; break; case GRS_INCOMPATIBLE_VERSION: status = PSW_UPDATE_REQUIRED; break; case GRS_TRANSACTION_STATE_LOST: status = AESM_PSE_PR_BACKEND_TRANSACTION_STATE_LOST; break; case GRS_PROTOCOL_ERROR: status = AESM_PSE_PR_BACKEND_PROTOCOL_ERROR; break; case GRS_INTERNAL_ERROR: status = AESM_PSE_PR_BACKEND_INTERNAL_ERROR; break; default: status = AESM_PSE_PR_BACKEND_UNKNOWN_PROTOCOL_RESPONSE; break; } AESM_DBG_ERROR(g_event_string_table[SGX_EVENT_PSE_CERT_PROV_GENERAL_RESPONSE_FAILURE], status); AESM_LOG_ERROR(g_event_string_table[SGX_EVENT_PSE_CERT_PROV_GENERAL_RESPONSE_FAILURE], status); } else { switch (status) { case OAL_NETWORK_UNAVAILABLE_ERROR: { AESM_LOG_ERROR(g_event_string_table[SGX_EVENT_PSE_CERT_PROV_FAILURE]); break; } case PSE_PAIRING_BLOB_UNSEALING_ERROR: { AESM_LOG_ERROR(g_event_string_table[SGX_EVENT_LTP_BLOB_INTEGRITY_ERROR]); break; } case PSE_PAIRING_BLOB_INVALID_ERROR: { AESM_LOG_ERROR(g_event_string_table[SGX_EVENT_LTP_BLOB_INVALID_ERROR]); break; } case AESM_PSE_PR_BACKEND_MSG4_PLATFORM_INFO_BLOB_SIZE: { // // happens if pib returned is not the right size // AESM_LOG_ERROR(g_event_string_table[SGX_EVENT_PSE_CERT_PROV_PROTOCOL_RESPONSE_FAILURE]); break; } case AE_FAILURE: { // // happens if problem with proxy setting // AESM_LOG_ERROR(g_event_string_table[SGX_EVENT_PSE_CERT_PROV_FAILURE]); break; } case AESM_CP_ATTESTATION_FAILURE: { AESM_LOG_ERROR(g_event_string_table[SGX_EVENT_PSE_ATTESTATION_ERROR]); break; } default: { AESM_DBG_ERROR("Error in ConvertBackendStatus(status) : status = %d (%xh)", status, status); break; } } } } return status; }
bool Helper::noLtpBlob() { upse::Buffer pairing_blob; return AE_FAILED(read_ltp_blob(pairing_blob)); }
bool Helper::noPseCert() { std::list<upse::Buffer> certChain; return AE_FAILED(Helper::LoadCertificateChain(certChain)); }
ae_error_t Helper::SaveCertificateChain( /*in */ std::list<upse::Buffer>& certChain) { ae_error_t status = AESM_PSE_PR_CERT_SAVE_ERROR; char* szParseString = NULL; int nLen, pos=0; do { RemoveCertificateChain(); // Allocate enough space for the list of names and separator character if(((size_t)(INT32_MAX-1))/sizeof(CERT_FILENAME_POSTFIX_FORMAT) < certChain.size() ) break; int nBytes = static_cast<int>(certChain.size() * sizeof(CERT_FILENAME_POSTFIX_FORMAT)) + 1; szParseString = (char*)calloc(1, nBytes); if (NULL == szParseString) { break; } char* szNextCertNamePostfix = szParseString; int fileNo = 0; char szFilenamePostfix[80]; std::list<upse::Buffer>::iterator it = certChain.begin(); aesm_data_id_t fileid = PSE_PR_CERTIFICATE_FID; while (it != certChain.end()) { nLen = sprintf_s(szFilenamePostfix, sizeof(szFilenamePostfix), CERT_FILENAME_POSTFIX_FORMAT, ++fileNo); if (AE_SUCCESS != upsePersistentStorage::Write(fileid++, *it)) { break; } if (PSE_PR_CERTIFICATE_FID_MAX == fileid) { break; } strcpy_s(szNextCertNamePostfix, nBytes-pos, szFilenamePostfix); pos += nLen; szNextCertNamePostfix += nLen; ++it; if (it != certChain.end()) { if (pos >= nBytes) { break; } *szNextCertNamePostfix = ';'; pos++; ++szNextCertNamePostfix; } } if ((szNextCertNamePostfix - szParseString) > nBytes) { break; } nBytes = static_cast<int>(szNextCertNamePostfix - szParseString); upse::Buffer nameListBuffer; if (AE_FAILED(nameListBuffer.Alloc(nBytes))) break; upse::BufferWriter bw(nameListBuffer); bw.writeRaw((uint8_t*)szParseString, nBytes); if (AE_SUCCESS != upsePersistentStorage::Write(PSE_PR_CERTIFICATE_CHAIN_FID, nameListBuffer)) { break; } status = AE_SUCCESS; } while (0); if (NULL != szParseString) { free(szParseString); } SGX_DBGPRINT_PRINT_FUNCTION_AND_RETURNVAL(__FUNCTION__, status); return status; }
ae_error_t Helper::PrepareCertificateChainVLR( /*in*/ std::list<upse::Buffer>& certChain, /*out*/ upse::Buffer& certChainVLR) { ae_error_t status = AESM_PSE_PR_LOAD_VERIFIER_CERT_ERROR; try { do { int nPaddedBytes = 0; int nCertChain = 0; #if !defined(LEAFTOROOT) #error LEAFTOROOT not #defined #endif // // spec'd behavior is to receive certs in leaft to root order // then, it only makes sense to store them leaf to root // but sigma wants them root to leaf // we'll leave the #if here since, cumulatively, it shows how to traverse // in both directions // #if !LEAFTOROOT SGX_DBGPRINT_PRINT_STRING_LTP("leaf cert to root cert direction, padding"); std::list<upse::Buffer>::reverse_iterator it; for (it = certChain.rbegin(); it != certChain.rend(); ++it) { int nSize = (*it).getSize(); nPaddedBytes += REQUIRED_PADDING_DWORD_ALIGNMENT(nSize); nCertChain += nSize; } #else SGX_DBGPRINT_PRINT_STRING_LTP("root cert to leaf cert direction, padding"); std::list<upse::Buffer>::iterator it; for (it = certChain.begin(); it != certChain.end(); ++it) { int nSize = (*it).getSize(); nPaddedBytes += REQUIRED_PADDING_DWORD_ALIGNMENT(nSize); nCertChain += nSize; } #endif SGX_DBGPRINT_PRINT_STRING_LTP("less cert padding"); //NRG: This doesn't work, but should. It should replace the previous nPaddedBytes = REQUIRED_PADDING_DWORD_ALIGNMENT(nCertChain); if(UINT16_MAX - ((int)sizeof(SIGMA_VLR_HEADER) + nPaddedBytes) < nCertChain){ break; } int nLength = static_cast<int>(sizeof(SIGMA_VLR_HEADER)) + nPaddedBytes + nCertChain; certChainVLR.Alloc(nLength); upse::BufferWriter bw(certChainVLR); VERIFIER_CERT_CHAIN_VLR* pVLR; uint8_t* p; if (AE_FAILED(bw.reserve(nLength, &p))) break; pVLR = (VERIFIER_CERT_CHAIN_VLR*)p; pVLR->VlrHeader.ID = VERIFIER_CERTIFICATE_CHAIN_VLR_ID; pVLR->VlrHeader.PaddedBytes = (UINT8)nPaddedBytes; pVLR->VlrHeader.Length = (UINT16)nLength; memset(pVLR->VerifierCertificateChain, 0, nPaddedBytes + nCertChain); int ndx = 0; // // see above // #if (!LEAFTOROOT) SGX_DBGPRINT_PRINT_STRING_LTP("leaf cert to root cert direction"); for (it = certChain.rbegin(); it != certChain.rend(); ++it) { memcpy_s(pVLR->VerifierCertificateChain + ndx, (*it).getSize(), (*it).getData(), (*it).getSize()); ndx += (*it).getSize(); } #else SGX_DBGPRINT_PRINT_STRING_LTP("root cert to leaf cert direction"); for (it = certChain.begin(); it != certChain.end(); ++it) { memcpy_s(pVLR->VerifierCertificateChain + ndx, (*it).getSize(), (*it).getData(), (*it).getSize()); ndx += (*it).getSize(); } #endif status = AE_SUCCESS; } while (0); } catch(...) { } SGX_DBGPRINT_PRINT_FUNCTION_AND_RETURNVAL(__FUNCTION__, status); return status; }
ae_error_t CertificateProvisioningProtocol::msg1_generate(const GroupId gid, upse::Buffer& serializedMsg1) { ae_error_t status = AE_FAILURE; tlv_status_t tlv_status = TLV_UNKNOWN_ERROR; GroupId be_gid; //gid from init_quote is little endian, change to bigendian for backend server here be_gid.data[0]=gid.data[3]; be_gid.data[1]=gid.data[2]; be_gid.data[2]=gid.data[1]; be_gid.data[3]=gid.data[0]; provision_request_header_t header; memset(&header, 0, sizeof(header)); TLVsMsg seq2_0_tlv_cipher_text; TLVsMsg seq2_1_tlv_block_cipher_info; TLVsMsg seq3_0_tlv_block_cipher_text; TLVsMsg seq3_1_tlv_epid_gid; TLVsMsg seq4_0_tlv_mac; do { status = get_random_value(XID_SIZE, TransactionID); if (AE_FAILED(status)) break; // Prepare sequence 2.1 -- Block Cipher Text TLV with SK status = msg1_create_seq2_1(seq2_1_tlv_block_cipher_info); if (AE_FAILED(status)) break; // Prepare sequence 2.0 -- Cipher Text TLV with KeyID and encrypted 2.1 status = msg1_create_seq2_0(seq2_1_tlv_block_cipher_info, seq2_0_tlv_cipher_text); if (AE_FAILED(status)) break; // Prepare sequence 3.1 -- EPID GID TLV tlv_status = seq3_1_tlv_epid_gid.add_epid_gid(be_gid); status = tlv_error_2_pve_error(tlv_status); if (AE_FAILED(status)) break; // Derive EK1 upse::Buffer EK1; status = aesCMAC(M1SK, TransactionID, EK1); if (AE_FAILED(status)) break; // Create Request Header (we need to calculate size before AES-GCM CMAC) status = msg1_create_header(seq2_0_tlv_cipher_text.get_tlv_msg_size(), seq3_1_tlv_epid_gid.get_tlv_msg_size(), TransactionID, header); if (AE_FAILED(status)) break; // Prepare sequence 3.0 -- Block Cipher Text TLV with IV and encrypted 3.1 upse::Buffer mac; status = msg1_create_seq3_0(seq3_1_tlv_epid_gid, header, EK1, seq3_0_tlv_block_cipher_text, mac); if (AE_FAILED(status)) break; // Prepare sequence 4.0 -- MAC TLV tlv_status = seq4_0_tlv_mac.add_mac(mac.getData()); status = tlv_error_2_pve_error(tlv_status); if (AE_FAILED(status)) break; //********************************************************************* // Prepare serialized message buffer //********************************************************************* uint32_t size_msg1 = static_cast<uint32_t>(PROVISION_REQUEST_HEADER_SIZE) + seq2_0_tlv_cipher_text.get_tlv_msg_size() + seq3_0_tlv_block_cipher_text.get_tlv_msg_size() + seq4_0_tlv_mac.get_tlv_msg_size(); status = serializedMsg1.Alloc(size_msg1); if (AE_FAILED(status)) break; serializedMsg1.zeroMemory(); upse::BufferWriter bwMsg1(serializedMsg1); // Write serialized request header to serialized message status = bwMsg1.writeRaw((uint8_t*)&header, sizeof(header)); if (AE_FAILED(status)) break; // Write sequence 2.0 - Cipher Text TLV (contains 2.1 as encrypted payload) status = bwMsg1.writeRaw(const_cast<uint8_t*>(seq2_0_tlv_cipher_text.get_tlv_msg()), seq2_0_tlv_cipher_text.get_tlv_msg_size()); if (AE_FAILED(status)) break; // Write sequence 3.0 - Block Cipher Text TLV (contains 3.1 as encrypted payload) status = bwMsg1.writeRaw(const_cast<uint8_t*>(seq3_0_tlv_block_cipher_text.get_tlv_msg()), seq3_0_tlv_block_cipher_text.get_tlv_msg_size()); if (AE_FAILED(status)) break; // Write sequence 4.0 - MAC TLV status = bwMsg1.writeRaw(const_cast<uint8_t*>(seq4_0_tlv_mac.get_tlv_msg()), seq4_0_tlv_mac.get_tlv_msg_size()); if (AE_FAILED(status)) break; status = AE_SUCCESS; } while (0); return status; }
ae_error_t CertificateProvisioningProtocol::msg3_generate(const upse::Buffer& csrBuffer, const upse::Buffer& quoteBuffer, upse::Buffer& serializedMsg3) { ae_error_t status = AE_FAILURE; tlv_status_t tlv_status = TLV_UNKNOWN_ERROR; provision_request_header_t serializedHeader; memset(&serializedHeader, 0, sizeof(serializedHeader)); TLVsMsg seq2_0_tlv_nonce; TLVsMsg seq3_0_tlv_block_cipher_text; TLVsMsg seq3_1_tlv_quote; TLVsMsg seq3_2_tlv_quote_signature; TLVsMsg seq3_3_tlv_x509_csr; TLVsMsg seq4_0_tlv_mac; do { tlv_status = seq2_0_tlv_nonce.add_nonce(Nonce.getData(), Nonce.getSize()); status = tlv_error_2_pve_error(tlv_status); if (AE_FAILED(status)) break; status = msg3_seq3_1_create_quote_tlv(quoteBuffer, seq3_1_tlv_quote); if (AE_FAILED(status)) break; status = msg3_seq3_2_create_quote_signature_tlv(quoteBuffer, seq3_2_tlv_quote_signature); if (AE_FAILED(status)) break; tlv_status = seq3_3_tlv_x509_csr.add_x509_csr(csrBuffer.getData(), csrBuffer.getSize()); status = tlv_error_2_pve_error(tlv_status); if (AE_FAILED(status)) break; status = msg3_create_header(TransactionID, seq2_0_tlv_nonce.get_tlv_msg_size(), seq3_1_tlv_quote.get_tlv_msg_size(), seq3_2_tlv_quote_signature.get_tlv_msg_size(), seq3_3_tlv_x509_csr.get_tlv_msg_size(), serializedHeader); if (AE_FAILED(status)) break; upse::Buffer mac; status = msg3_seq3_0_create_block_cipher_text_tlv(seq3_1_tlv_quote, seq3_2_tlv_quote_signature, seq3_3_tlv_x509_csr, seq2_0_tlv_nonce, serializedHeader, EK2, seq3_0_tlv_block_cipher_text, mac); if (AE_FAILED(status)) break; tlv_status = seq4_0_tlv_mac.add_mac(mac.getData()); status = tlv_error_2_pve_error(tlv_status); if (AE_FAILED(status)) break; //********************************************************************* // Prepare serialized message buffer //********************************************************************* uint32_t size_msg3 = static_cast<uint32_t>(PROVISION_REQUEST_HEADER_SIZE + seq2_0_tlv_nonce.get_tlv_msg_size() + seq3_0_tlv_block_cipher_text.get_tlv_msg_size() + seq4_0_tlv_mac.get_tlv_msg_size()); status = serializedMsg3.Alloc(size_msg3); if (AE_FAILED(status)) break; serializedMsg3.zeroMemory(); upse::BufferWriter bwMsg3(serializedMsg3); // Write serialized request header to serialized message status = bwMsg3.writeRaw((uint8_t*)&serializedHeader, sizeof(serializedHeader)); if (AE_FAILED(status)) break; // Write sequence 2.0 - Nonce TLV status = bwMsg3.writeRaw(const_cast<uint8_t*>(seq2_0_tlv_nonce.get_tlv_msg()), seq2_0_tlv_nonce.get_tlv_msg_size()); if (AE_FAILED(status)) break; // Write sequence 3.0 - Block Cipher Text TLV (contains 3.1, 3.2, and 3.3 as encrypted payload) status = bwMsg3.writeRaw(const_cast<uint8_t*>(seq3_0_tlv_block_cipher_text.get_tlv_msg()), seq3_0_tlv_block_cipher_text.get_tlv_msg_size()); if (AE_FAILED(status)) break; // Write sequence 4.0 - MAC TLV status = bwMsg3.writeRaw(const_cast<uint8_t*>(seq4_0_tlv_mac.get_tlv_msg()), seq4_0_tlv_mac.get_tlv_msg_size()); if (AE_FAILED(status)) break; status = AE_SUCCESS; } while (0); return status; }
ae_error_t prepare_for_certificate_provisioning ( /*in */ UINT64 nonce64, /*in */ const sgx_target_info_t* pTargetInfo, /*in */ UINT16 nMax_CSR_pse, /*out*/ UINT8* pCSR_pse, /*out*/ UINT16* pnLen_CSR_pse, /*out*/ sgx_report_t* pREPORT, /*i/o*/ pairing_blob_t* pPairingBlob ) { // Flow: 1) Check pointers for buffer data sizes // 2) If buffers are too small, return and tell caller size required // 3) Validate pointers and ensure buffers are within the enclave // 4) Generate a new private/public ECDSA key pair // 5) Request signed CSR template // 6) Calculate HASH_pse of (CSR_pse || nonce64) // 7) Generate REPORT with HASH_pse as the REPORTDATA, targeting QE // 8) Copy private key and public key into unsealed_pairing buffer // 9) Seal pairing blob // 10) Return Sealed pairing blob, generated CSR, REPORT, and status ae_error_t status = AE_FAILURE; pairing_data_t pairingData; EcDsaPrivKey privateKey; EcDsaPubKey publicKey; uint8_t temp_instance_id[16]; SignCSR CSR; size_t nMaxSizeCSR = CSR.GetMaxSize(); sgx_ecc_state_handle_t csr_ecc_handle = NULL; memset(&pairingData, 0, sizeof(pairingData)); ///////////////////////////////////////////////////////////////// do { //********************************************************************* // Validate pointers and sizes //********************************************************************* BREAK_IF_TRUE((NULL == pPairingBlob), status, PSE_PR_BAD_POINTER_ERROR); // save SW_INSTANCE_ID memcpy(temp_instance_id, pPairingBlob->plaintext.pse_instance_id, sizeof(temp_instance_id)); { BREAK_IF_TRUE((NULL == pTargetInfo), status, PSE_PR_BAD_POINTER_ERROR); BREAK_IF_TRUE((NULL == pREPORT), status, PSE_PR_BAD_POINTER_ERROR); BREAK_IF_TRUE((NULL == pCSR_pse || NULL == pnLen_CSR_pse), status, PSE_PR_BAD_POINTER_ERROR); BREAK_IF_TRUE((nMax_CSR_pse < nMaxSizeCSR), status, PSE_PR_PARAMETER_ERROR); BREAK_IF_FALSE(sgx_is_within_enclave(pCSR_pse, nMaxSizeCSR), status, PSE_PR_BAD_POINTER_ERROR); //********************************************************************* // Generate a new ECDSA Key Pair //********************************************************************* sgx_status_t sgx_status = sgx_ecc256_open_context(&csr_ecc_handle); BREAK_IF_TRUE((SGX_ERROR_OUT_OF_MEMORY == sgx_status), status, PSE_PR_INSUFFICIENT_MEMORY_ERROR); BREAK_IF_TRUE((SGX_SUCCESS != sgx_status), status, PSE_PR_KEY_PAIR_GENERATION_ERROR); sgx_status = sgx_ecc256_create_key_pair((sgx_ec256_private_t *)privateKey, (sgx_ec256_public_t*)publicKey, csr_ecc_handle); BREAK_IF_TRUE((SGX_SUCCESS != sgx_status), status, PSE_PR_KEY_PAIR_GENERATION_ERROR); *pnLen_CSR_pse = (uint16_t)nMaxSizeCSR; //********************************************************************* // Get a signed Certificate Signing Request from the template //********************************************************************* status = CSR.GetSignedTemplate(&privateKey, &publicKey, csr_ecc_handle, pCSR_pse, pnLen_CSR_pse); BREAK_IF_FAILED(status); //********************************************************************* // Calculate HASH_pse of (CSR_pse || nonce64) //********************************************************************* PrepareHashSHA256 hash; SHA256_HASH computedHash; status = hash.Update(pCSR_pse, *pnLen_CSR_pse); BREAK_IF_FAILED(status); status = hash.Update(&nonce64, sizeof(nonce64)); BREAK_IF_FAILED(status); status = hash.Finalize(&computedHash); BREAK_IF_FAILED(status); //********************************************************************* // Generate a REPORT with HASH_pse //********************************************************************* sgx_report_data_t report_data = {{0}}; memcpy(&report_data, &computedHash, sizeof(computedHash)); if (SGX_SUCCESS != sgx_create_report(const_cast<sgx_target_info_t*>(pTargetInfo), &report_data, (sgx_report_t*)pREPORT)) { status = PSE_PR_CREATE_REPORT_ERROR; break; } //********************************************************************* // Try to unseal the pairing data //********************************************************************* status = UnsealPairingBlob(pPairingBlob, &pairingData); if (AE_FAILED(status)) memset_s(&pairingData, sizeof(pairingData), 0, sizeof(pairingData)); //********************************************************************* // Seal ECDSA Verifier Private Key into blob //********************************************************************* memcpy(pairingData.secret_data.VerifierPrivateKey, &privateKey, sizeof(EcDsaPrivKey)); } // "Public" PSE Cert // Set pairingData.plaintext.pse_instance_id using saved temp_instance_id memcpy(pairingData.plaintext.pse_instance_id, temp_instance_id, sizeof(pairingData.plaintext.pse_instance_id)); status = SealPairingBlob(&pairingData, pPairingBlob); BREAK_IF_FAILED(status); //********************************************************************* // WE PASSED ALL BARRIERS TO SUCCESS //********************************************************************* status = AE_SUCCESS; // OutputOctets("::tPrepareForCertificateProvisioning:: New CSR generated", NULL, 0); } while (false); // Defense-in-depth: clear the data on stack that contains enclave secret. memset_s(&pairingData, sizeof(pairingData), 0, sizeof(pairingData)); memset_s(&privateKey, sizeof(privateKey), 0, sizeof(privateKey)); if (csr_ecc_handle != NULL) sgx_ecc256_close_context(csr_ecc_handle); return map_error_for_return(status); }
ae_error_t CertificateProvisioningProtocol::msg3_seq3_0_create_block_cipher_text_tlv(const TLVsMsg& quote, const TLVsMsg& epidSigTLV, const TLVsMsg& csrTLV, const TLVsMsg& nonceTLV, const provision_request_header_t& requestHeader, const upse::Buffer& ek2, TLVsMsg& blockCipherTextTLV, upse::Buffer& mac) { ae_error_t status = AE_FAILURE; tlv_status_t tlv_status; upse::Buffer plainText; upse::Buffer encryptedPayload; do { status = get_random_value(IV_SIZE, M3IV); if (AE_FAILED(status)) break; status = plainText.Alloc(quote.get_tlv_msg_size() + epidSigTLV.get_tlv_msg_size() + csrTLV.get_tlv_msg_size()); if (AE_FAILED(status)) break; upse::BufferWriter plainTextWriter(plainText); status = plainTextWriter.writeRaw(quote.get_tlv_msg(), quote.get_tlv_msg_size()); if (AE_FAILED(status)) break; status = plainTextWriter.writeRaw(epidSigTLV.get_tlv_msg(), epidSigTLV.get_tlv_msg_size()); if (AE_FAILED(status)) break; status = plainTextWriter.writeRaw(csrTLV.get_tlv_msg(), csrTLV.get_tlv_msg_size()); if (AE_FAILED(status)) break; uint32_t payloadSize = BLOCK_CIPHER_TEXT_TLV_PAYLOAD_SIZE(plainText.getSize()); uint32_t blockCipherTextHeaderSize = get_tlv_total_size(payloadSize) - payloadSize; // Calculate AAD (concatenation of Request header, Nonce, Block Cipher Text TLV header and IV from Block Cipher Text TLV) upse::Buffer aad; status = aad.Alloc(static_cast<uint32_t>(sizeof(requestHeader) + nonceTLV.get_tlv_msg_size() + blockCipherTextHeaderSize + M3IV.getSize())); if (AE_FAILED(status)) break; TLVsMsg tmpBlockCipherTextTLV; tlv_status = tmpBlockCipherTextTLV.add_block_cipher_text(M3IV.getData(), NULL, plainText.getSize()); status = tlv_error_2_pve_error(tlv_status); if (AE_FAILED(status)) break; upse::BufferWriter aadWriter(aad); status = aadWriter.writeRaw((const uint8_t*)&requestHeader, sizeof(requestHeader)); if (AE_FAILED(status)) break; status = aadWriter.writeRaw(nonceTLV.get_tlv_msg(), nonceTLV.get_tlv_msg_size()); if (AE_FAILED(status)) break; status = aadWriter.writeRaw(tmpBlockCipherTextTLV.get_tlv_msg(), blockCipherTextHeaderSize); if (AE_FAILED(status)) break; status = aadWriter.writeRaw(M3IV.getData(), M3IV.getSize()); if (AE_FAILED(status)) break; status = aesGCMEncrypt(M3IV, ek2, plainText, aad, encryptedPayload, mac); if (AE_FAILED(status)) break; tlv_status = blockCipherTextTLV.add_block_cipher_text(M3IV.getData(), encryptedPayload.getData(), encryptedPayload.getSize()); status = tlv_error_2_pve_error(tlv_status); if (AE_FAILED(status)) break; status = AE_SUCCESS; } while (0); return status; }
ae_error_t SigmaHelper::GetRLsFromServer ( /*out*/ upse::Buffer& sigRlOut, /*out*/ upse::Buffer& privRlOut ) { // // iKGF serves up binary (legacy) versions of EPID 1.1 RLs // all we need to do is convey the GID in the URL itself // for example, https://trustedservices.intel.com/content/crl/Signature_<GID>.crl // so, we get url out of config file and concatenate with filename that's // specific to the type of RL ae_error_t sigRetValue = AE_FAILURE; ae_error_t privRetValue = AE_FAILURE; const char *url = EndpointSelectionInfo::instance().get_server_url(REVOCATION_LIST_RETRIEVAL); if (url == NULL) { return OAL_CONFIG_FILE_ERROR; } uint8_t* p1 = const_cast<uint8_t*>(m_gid.getData()); do { if ((m_gid.getSize() < 1) || (m_gid.getSize() > 4)) break; char msg[9]; for (unsigned i = 0; i < m_gid.getSize(); i++) { sprintf_s((char*) msg+2*i, 3, "%02X", *(p1+m_gid.getSize()-1-i)); } std::string gidString(msg); unsigned numLeading0s = 8 - static_cast<unsigned>(gidString.length()); for (unsigned i = 0; i < numLeading0s; i++) { gidString = '0' + gidString; } //if config file entry doesn't have trailing "/" , add it. std::string s_url = url; if(s_url.size()>0&&s_url[s_url.size()-1]!='/') s_url+='/'; std::string stringUrl = s_url + "Signature_" + gidString + ".crl"; uint8_t *recv=NULL; uint32_t recv_size = 0; sigRetValue = AESMNetworkEncoding::aesm_send_recv_msg(stringUrl.c_str(), NULL, 0, recv, recv_size, GET, false); if (AE_SUCCESS != sigRetValue) { sigRlOut.Alloc(0); } else { sigRlOut.Alloc(recv_size); upse::BufferWriter bw(sigRlOut); bw.writeRaw(recv, recv_size); AESMNetworkEncoding::aesm_free_response_msg(recv); } stringUrl = s_url + "Product_" + gidString + ".crl"; recv=NULL; recv_size = 0; privRetValue = AESMNetworkEncoding::aesm_send_recv_msg(stringUrl.c_str(), NULL, 0, recv, recv_size, GET, false); if (AE_SUCCESS != privRetValue) { privRlOut.Alloc(0); } else { privRlOut.Alloc(recv_size); upse::BufferWriter bw(privRlOut); bw.writeRaw(recv, recv_size); aesm_free_network_response_buffer(recv); } } while (0); if (AE_FAILED(privRetValue)) { SGX_DBGPRINT_PRINT_STRING_LTP("PrivRL not retrieved: continuing without PrivRL"); } if (AE_FAILED(sigRetValue)) { SGX_DBGPRINT_PRINT_STRING_LTP("SigRL not retrieved: continuing without SigRL"); } if ((privRetValue == AE_SUCCESS) && (sigRetValue == AE_SUCCESS)) { return AE_SUCCESS; } else if (sigRetValue != AE_SUCCESS) { return AESM_PSE_PR_GET_SIGRL_ERROR; } else { return AESM_PSE_PR_GET_PRIVRL_ERROR; } }