sgx_status_t sgx_verify_report(const sgx_report_t *report) { sgx_mac_t mac; sgx_key_request_t key_request; sgx_key_128bit_t key; sgx_status_t err = SGX_ERROR_UNEXPECTED; //check parameter if(!report||!sgx_is_within_enclave(report, sizeof(*report))) { return SGX_ERROR_INVALID_PARAMETER; } memset(&mac, 0, sizeof(sgx_mac_t)); memset(&key_request, 0, sizeof(sgx_key_request_t)); memset(&key, 0, sizeof(sgx_key_128bit_t)); //prepare the key_request key_request.key_name = SGX_KEYSELECT_REPORT; memcpy_s(&key_request.key_id, sizeof(key_request.key_id), &report->key_id, sizeof(report->key_id)); //get the report key // Since the key_request is not an input parameter by caller, // we suppose sgx_get_key would never return the following error code: // SGX_ERROR_INVALID_PARAMETER // SGX_ERROR_INVALID_ATTRIBUTE // SGX_ERROR_INVALID_CPUSVN // SGX_ERROR_INVALID_ISVSVN // SGX_ERROR_INVALID_KEYNAME err = sgx_get_key(&key_request, &key); if(err != SGX_SUCCESS) { return err; // err must be SGX_ERROR_OUT_OF_MEMORY or SGX_ERROR_UNEXPECTED } //get the report mac err = sgx_rijndael128_cmac_msg((sgx_cmac_128bit_key_t*)&key, (const uint8_t *)(&report->body), sizeof(sgx_report_body_t), &mac); memset_s (&key, sizeof(sgx_key_128bit_t), 0, sizeof(sgx_key_128bit_t)); if (SGX_SUCCESS != err) { if(err != SGX_ERROR_OUT_OF_MEMORY) err = SGX_ERROR_UNEXPECTED; return err; } if(consttime_memequal(mac, report->mac, sizeof(sgx_mac_t)) == 0) { return SGX_ERROR_MAC_MISMATCH; } else { return SGX_SUCCESS; } }
sgx_status_t verify_att_result_mac(sgx_ra_context_t context, uint8_t* p_message, size_t message_size, uint8_t* p_mac, size_t mac_size) { sgx_status_t ret; sgx_ec_key_128bit_t mk_key; if(mac_size != sizeof(sgx_mac_t)) { ret = SGX_ERROR_INVALID_PARAMETER; return ret; } if(message_size > UINT32_MAX) { ret = SGX_ERROR_INVALID_PARAMETER; return ret; } do { uint8_t mac[SGX_CMAC_MAC_SIZE] = {0}; ret = sgx_ra_get_keys(context, SGX_RA_KEY_MK, &mk_key); if(SGX_SUCCESS != ret) { break; } ret = sgx_rijndael128_cmac_msg(&mk_key, p_message, (uint32_t)message_size, &mac); if(SGX_SUCCESS != ret) { break; } if(0 == consttime_memequal(p_mac, mac, sizeof(mac))) { ret = SGX_ERROR_MAC_MISMATCH; break; } } while(0); return ret; }
extern "C" sgx_status_t sgx_ra_proc_msg2_trusted( sgx_ra_context_t context, const sgx_ra_msg2_t *p_msg2, //(g_b||spid||quote_type|| KDF_ID ||sign_gb_ga||cmac||sig_rl_size||sig_rl) const sgx_target_info_t *p_qe_target, sgx_report_t *p_report, sgx_quote_nonce_t* p_nonce) { sgx_status_t se_ret = SGX_ERROR_UNEXPECTED; //p_msg2[in] p_qe_target[in] p_report[out] p_nonce[out] in EDL file if(vector_size(&g_ra_db) <= context || !p_msg2 || !p_qe_target || !p_report || !p_nonce) return SGX_ERROR_INVALID_PARAMETER; ra_db_item_t* item = NULL; if(0 != vector_get(&g_ra_db, context, reinterpret_cast<void**>(&item)) || item == NULL ) return SGX_ERROR_INVALID_PARAMETER; sgx_ec256_private_t a; memset(&a, 0, sizeof(a)); // Create gb_ga sgx_ec256_public_t gb_ga[2]; sgx_ec256_public_t sp_pubkey; sgx_ec_key_128bit_t smkey = {0}; sgx_ec_key_128bit_t skey = {0}; sgx_ec_key_128bit_t mkey = {0}; sgx_ec_key_128bit_t vkey = {0}; sgx_ra_derive_secret_keys_t ra_key_cb = NULL; memset(&gb_ga[0], 0, sizeof(gb_ga)); sgx_spin_lock(&item->item_lock); //sgx_ra_get_ga must have been called if (item->state != ra_get_gaed) { sgx_spin_unlock(&item->item_lock); return SGX_ERROR_INVALID_STATE; } memcpy(&a, &item->a, sizeof(a)); memcpy(&gb_ga[1], &item->g_a, sizeof(gb_ga[1])); memcpy(&sp_pubkey, &item->sp_pubkey, sizeof(sp_pubkey)); ra_key_cb = DEC_KDF_POINTER(item->derive_key_cb); sgx_spin_unlock(&item->item_lock); memcpy(&gb_ga[0], &p_msg2->g_b, sizeof(gb_ga[0])); sgx_ecc_state_handle_t ecc_state = NULL; // ecc_state need to be freed when exit. se_ret = sgx_ecc256_open_context(&ecc_state); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; return se_ret; } sgx_ec256_dh_shared_t dh_key; memset(&dh_key, 0, sizeof(dh_key)); sgx_ec256_public_t* p_msg2_g_b = const_cast<sgx_ec256_public_t*>(&p_msg2->g_b); se_ret = sgx_ecc256_compute_shared_dhkey(&a, (sgx_ec256_public_t*)p_msg2_g_b, &dh_key, ecc_state); if(SGX_SUCCESS != se_ret) { if (SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; sgx_ecc256_close_context(ecc_state); return se_ret; } // Verify signature of gb_ga uint8_t result; sgx_ec256_signature_t* p_msg2_sign_gb_ga = const_cast<sgx_ec256_signature_t*>(&p_msg2->sign_gb_ga); se_ret = sgx_ecdsa_verify((uint8_t *)&gb_ga, sizeof(gb_ga), &sp_pubkey, p_msg2_sign_gb_ga, &result, ecc_state); if(SGX_SUCCESS != se_ret) { if (SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; sgx_ecc256_close_context(ecc_state); return se_ret; } if(SGX_EC_VALID != result) { sgx_ecc256_close_context(ecc_state); return SGX_ERROR_INVALID_SIGNATURE; } do { if(NULL != ra_key_cb) { se_ret = ra_key_cb(&dh_key, p_msg2->kdf_id, &smkey, &skey, &mkey, &vkey); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret && SGX_ERROR_INVALID_PARAMETER != se_ret && SGX_ERROR_KDF_MISMATCH != se_ret) se_ret = SGX_ERROR_UNEXPECTED; break; } } else if (p_msg2->kdf_id == 0x0001) { se_ret = derive_key(&dh_key, "SMK", (uint32_t)(sizeof("SMK") -1), &smkey); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; break; } se_ret = derive_key(&dh_key, "SK", (uint32_t)(sizeof("SK") -1), &skey); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; break; } se_ret = derive_key(&dh_key, "MK", (uint32_t)(sizeof("MK") -1), &mkey); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; break; } se_ret = derive_key(&dh_key, "VK", (uint32_t)(sizeof("VK") -1), &vkey); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; break; } } else { se_ret = SGX_ERROR_KDF_MISMATCH; break; } sgx_cmac_128bit_tag_t mac; uint32_t maced_size = offsetof(sgx_ra_msg2_t, mac); se_ret = sgx_rijndael128_cmac_msg(&smkey, (const uint8_t *)p_msg2, maced_size, &mac); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; break; } //Check mac if(0 == consttime_memequal(mac, p_msg2->mac, sizeof(mac))) { se_ret = SGX_ERROR_MAC_MISMATCH; break; } //create a nonce se_ret =sgx_read_rand((uint8_t*)p_nonce, sizeof(sgx_quote_nonce_t)); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; break; } sgx_spin_lock(&item->item_lock); //sgx_ra_get_ga must have been called if (item->state != ra_get_gaed) { se_ret = SGX_ERROR_INVALID_STATE; sgx_spin_unlock(&item->item_lock); break; } memcpy(&item->g_b, &p_msg2->g_b, sizeof(item->g_b)); memcpy(&item->smk_key, smkey, sizeof(item->smk_key)); memcpy(&item->sk_key, skey, sizeof(item->sk_key)); memcpy(&item->mk_key, mkey, sizeof(item->mk_key)); memcpy(&item->vk_key, vkey, sizeof(item->vk_key)); memcpy(&item->qe_target, p_qe_target, sizeof(sgx_target_info_t)); memcpy(&item->quote_nonce, p_nonce, sizeof(sgx_quote_nonce_t)); sgx_report_data_t report_data = {{0}}; se_static_assert(sizeof(sgx_report_data_t)>=sizeof(sgx_sha256_hash_t)); // H = SHA256(ga || gb || VK_CMAC) uint32_t sha256ed_size = offsetof(ra_db_item_t, sp_pubkey); //report_data is 512bits, H is 256bits. The H is in the lower 256 bits of report data while the higher 256 bits are all zeros. se_ret = sgx_sha256_msg((uint8_t *)&item->g_a, sha256ed_size, (sgx_sha256_hash_t *)&report_data); if(SGX_SUCCESS != se_ret) { if (SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; sgx_spin_unlock(&item->item_lock); break; } //REPORTDATA = H se_ret = sgx_create_report(p_qe_target, &report_data, p_report); if (SGX_SUCCESS != se_ret) { if(SGX_ERROR_OUT_OF_MEMORY != se_ret) se_ret = SGX_ERROR_UNEXPECTED; sgx_spin_unlock(&item->item_lock); break; } item->state = ra_proc_msg2ed; sgx_spin_unlock(&item->item_lock); }while(0); memset_s(&dh_key, sizeof(dh_key), 0, sizeof(dh_key)); sgx_ecc256_close_context(ecc_state); memset_s(&a, sizeof(sgx_ec256_private_t),0, sizeof(sgx_ec256_private_t)); memset_s(smkey, sizeof(sgx_ec_key_128bit_t),0, sizeof(sgx_ec_key_128bit_t)); memset_s(skey, sizeof(sgx_ec_key_128bit_t),0, sizeof(sgx_ec_key_128bit_t)); memset_s(mkey, sizeof(sgx_ec_key_128bit_t),0, sizeof(sgx_ec_key_128bit_t)); memset_s(vkey, sizeof(sgx_ec_key_128bit_t),0, sizeof(sgx_ec_key_128bit_t)); return se_ret; }
sgx_status_t sgx_rijndael128GCM_decrypt(const sgx_aes_gcm_128bit_key_t *p_key, const uint8_t *p_src, uint32_t src_len, uint8_t *p_dst, const uint8_t *p_iv, uint32_t iv_len, const uint8_t *p_aad, uint32_t aad_len, const sgx_aes_gcm_128bit_tag_t *p_in_mac) { IppStatus error_code = ippStsNoErr; uint8_t l_tag[SGX_AESGCM_MAC_SIZE]; IppsAES_GCMState* pState = NULL; int ippStateSize = 0; if ((p_key == NULL) || ((src_len > 0) && (p_dst == NULL)) || ((src_len > 0) && (p_src == NULL)) || (p_in_mac == NULL) || (iv_len != SGX_AESGCM_IV_SIZE) || ((aad_len > 0) && (p_aad == NULL)) || (p_iv == NULL) || ((p_src == NULL) && (p_aad == NULL))) { return SGX_ERROR_INVALID_PARAMETER; } // Autenthication Tag returned by Decrypt to be compared with Tag created during seal memset(&l_tag, 0, SGX_AESGCM_MAC_SIZE); error_code = ippsAES_GCMGetSize(&ippStateSize); if (error_code != ippStsNoErr) { return SGX_ERROR_UNEXPECTED; } pState = (IppsAES_GCMState*)malloc(ippStateSize); if (pState == NULL) { return SGX_ERROR_OUT_OF_MEMORY; } error_code = ippsAES_GCMInit((const Ipp8u *)p_key, SGX_AESGCM_KEY_SIZE, pState, ippStateSize); if (error_code != ippStsNoErr) { // Clear temp State before free. memset_s(pState, ippStateSize, 0, ippStateSize); free(pState); switch (error_code) { case ippStsMemAllocErr: return SGX_ERROR_OUT_OF_MEMORY; case ippStsNullPtrErr: case ippStsLengthErr: return SGX_ERROR_INVALID_PARAMETER; default: return SGX_ERROR_UNEXPECTED; } } error_code = ippsAES_GCMStart(p_iv, SGX_AESGCM_IV_SIZE, p_aad, aad_len, pState); if (error_code != ippStsNoErr) { // Clear temp State before free. memset_s(pState, ippStateSize, 0, ippStateSize); free(pState); switch (error_code) { case ippStsNullPtrErr: case ippStsLengthErr: return SGX_ERROR_INVALID_PARAMETER; default: return SGX_ERROR_UNEXPECTED; } } if (src_len > 0) { error_code = ippsAES_GCMDecrypt(p_src, p_dst, src_len, pState); if (error_code != ippStsNoErr) { // Clear temp State before free. memset_s(pState, ippStateSize, 0, ippStateSize); free(pState); switch (error_code) { case ippStsNullPtrErr: return SGX_ERROR_INVALID_PARAMETER; default: return SGX_ERROR_UNEXPECTED; } } } error_code = ippsAES_GCMGetTag((Ipp8u *)l_tag, SGX_AESGCM_MAC_SIZE, pState); if (error_code != ippStsNoErr) { // Clear temp State before free. memset_s(p_dst, src_len, 0, src_len); memset_s(pState, ippStateSize, 0, ippStateSize); free(pState); switch (error_code) { case ippStsNullPtrErr: case ippStsLengthErr: return SGX_ERROR_INVALID_PARAMETER; default: return SGX_ERROR_UNEXPECTED; } } // Clear temp State before free. memset_s(pState, ippStateSize, 0, ippStateSize); free(pState); // Verify current data tag = data tag generated when sealing the data blob if (consttime_memequal(p_in_mac, &l_tag, SGX_AESGCM_MAC_SIZE) == 0) { memset_s(p_dst, src_len, 0, src_len); memset_s(&l_tag, SGX_AESGCM_MAC_SIZE, 0, SGX_AESGCM_MAC_SIZE); return SGX_ERROR_MAC_MISMATCH; } memset_s(&l_tag, SGX_AESGCM_MAC_SIZE, 0, SGX_AESGCM_MAC_SIZE); return SGX_SUCCESS; }
/* * ESP input callback from the crypto driver. */ static int esp_input_cb(struct cryptop *crp) { u_int8_t lastthree[3], aalg[AH_ALEN_MAX]; int s, hlen, skip, protoff, error; struct mbuf *m; struct cryptodesc *crd; const struct auth_hash *esph; const struct enc_xform *espx; struct tdb_crypto *tc; struct m_tag *mtag; struct secasvar *sav; struct secasindex *saidx; void *ptr; u_int16_t dport; u_int16_t sport; crd = crp->crp_desc; IPSEC_ASSERT(crd != NULL, ("esp_input_cb: null crypto descriptor!")); tc = (struct tdb_crypto *) crp->crp_opaque; IPSEC_ASSERT(tc != NULL, ("esp_input_cb: null opaque crypto data area!")); skip = tc->tc_skip; protoff = tc->tc_protoff; mtag = (struct m_tag *) tc->tc_ptr; m = (struct mbuf *) crp->crp_buf; /* find the source port for NAT-T */ nat_t_ports_get(m, &dport, &sport); s = splsoftnet(); mutex_enter(softnet_lock); sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, sport, dport); if (sav == NULL) { ESP_STATINC(ESP_STAT_NOTDB); DPRINTF(("esp_input_cb: SA expired while in crypto " "(SA %s/%08lx proto %u)\n", ipsec_address(&tc->tc_dst), (u_long) ntohl(tc->tc_spi), tc->tc_proto)); error = ENOBUFS; /*XXX*/ goto bad; } saidx = &sav->sah->saidx; IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET || saidx->dst.sa.sa_family == AF_INET6, ("esp_input_cb: unexpected protocol family %u", saidx->dst.sa.sa_family)); esph = sav->tdb_authalgxform; espx = sav->tdb_encalgxform; /* Check for crypto errors */ if (crp->crp_etype) { /* Reset the session ID */ if (sav->tdb_cryptoid != 0) sav->tdb_cryptoid = crp->crp_sid; if (crp->crp_etype == EAGAIN) { KEY_FREESAV(&sav); mutex_exit(softnet_lock); splx(s); return crypto_dispatch(crp); } ESP_STATINC(ESP_STAT_NOXFORM); DPRINTF(("esp_input_cb: crypto error %d\n", crp->crp_etype)); error = crp->crp_etype; goto bad; } /* Shouldn't happen... */ if (m == NULL) { ESP_STATINC(ESP_STAT_CRYPTO); DPRINTF(("esp_input_cb: bogus returned buffer from crypto\n")); error = EINVAL; goto bad; } ESP_STATINC(ESP_STAT_HIST + sav->alg_enc); /* If authentication was performed, check now. */ if (esph != NULL) { /* * If we have a tag, it means an IPsec-aware NIC did * the verification for us. Otherwise we need to * check the authentication calculation. */ AH_STATINC(AH_STAT_HIST + sav->alg_auth); if (mtag == NULL) { /* Copy the authenticator from the packet */ m_copydata(m, m->m_pkthdr.len - esph->authsize, esph->authsize, aalg); ptr = (tc + 1); /* Verify authenticator */ if (!consttime_memequal(ptr, aalg, esph->authsize)) { DPRINTF(("esp_input_cb: " "authentication hash mismatch for packet in SA %s/%08lx\n", ipsec_address(&saidx->dst), (u_long) ntohl(sav->spi))); ESP_STATINC(ESP_STAT_BADAUTH); error = EACCES; goto bad; } } /* Remove trailing authenticator */ m_adj(m, -(esph->authsize)); } /* Release the crypto descriptors */ free(tc, M_XDATA), tc = NULL; crypto_freereq(crp), crp = NULL; /* * Packet is now decrypted. */ m->m_flags |= M_DECRYPTED; /* * Update replay sequence number, if appropriate. */ if (sav->replay) { u_int32_t seq; m_copydata(m, skip + offsetof(struct newesp, esp_seq), sizeof (seq), &seq); if (ipsec_updatereplay(ntohl(seq), sav)) { DPRINTF(("%s: packet replay check for %s\n", __func__, ipsec_logsastr(sav))); ESP_STATINC(ESP_STAT_REPLAY); error = ENOBUFS; goto bad; } }
/* * Verify the given hostname, address and host key using DNS. * Returns 0 if lookup succeeds, -1 otherwise */ int verify_host_key_dns(const char *hostname, struct sockaddr *address, struct sshkey *hostkey, int *flags) { u_int counter; int result; struct rrsetinfo *fingerprints = NULL; u_int8_t hostkey_algorithm; u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED; u_char *hostkey_digest; size_t hostkey_digest_len; u_int8_t dnskey_algorithm; u_int8_t dnskey_digest_type; u_char *dnskey_digest; size_t dnskey_digest_len; *flags = 0; debug3("verify_host_key_dns"); if (hostkey == NULL) fatal("No key to look up!"); if (is_numeric_hostname(hostname)) { debug("skipped DNS lookup for numerical hostname"); return -1; } result = getrrsetbyname(hostname, DNS_RDATACLASS_IN, DNS_RDATATYPE_SSHFP, 0, &fingerprints); if (result) { verbose("DNS lookup error: %s", dns_result_totext(result)); return -1; } if (fingerprints->rri_flags & RRSET_VALIDATED) { *flags |= DNS_VERIFY_SECURE; debug("found %d secure fingerprints in DNS", fingerprints->rri_nrdatas); } else { debug("found %d insecure fingerprints in DNS", fingerprints->rri_nrdatas); } /* Initialize default host key parameters */ if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, &hostkey_digest, &hostkey_digest_len, hostkey)) { error("Error calculating host key fingerprint."); freerrset(fingerprints); return -1; } if (fingerprints->rri_nrdatas) *flags |= DNS_VERIFY_FOUND; for (counter = 0; counter < fingerprints->rri_nrdatas; counter++) { /* * Extract the key from the answer. Ignore any badly * formatted fingerprints. */ if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type, &dnskey_digest, &dnskey_digest_len, fingerprints->rri_rdatas[counter].rdi_data, fingerprints->rri_rdatas[counter].rdi_length)) { verbose("Error parsing fingerprint from DNS."); continue; } if (hostkey_digest_type != dnskey_digest_type) { hostkey_digest_type = dnskey_digest_type; free(hostkey_digest); /* Initialize host key parameters */ if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, &hostkey_digest, &hostkey_digest_len, hostkey)) { error("Error calculating key fingerprint."); freerrset(fingerprints); return -1; } } /* Check if the current key is the same as the given key */ if (hostkey_algorithm == dnskey_algorithm && hostkey_digest_type == dnskey_digest_type) { if (hostkey_digest_len == dnskey_digest_len && consttime_memequal(hostkey_digest, dnskey_digest, hostkey_digest_len)) *flags |= DNS_VERIFY_MATCH; } free(dnskey_digest); } free(hostkey_digest); /* from sshkey_fingerprint_raw() */ freerrset(fingerprints); if (*flags & DNS_VERIFY_FOUND) if (*flags & DNS_VERIFY_MATCH) debug("matching host key fingerprint found in DNS"); else debug("mismatching host key fingerprint found in DNS"); else debug("no host key fingerprint found in DNS"); return 0; }