Add support for IASv4 for remote attestation
This commit is contained in:
parent
0d9e9aaaad
commit
f3c5c9efe1
@ -4,14 +4,14 @@ Binary: kbupd-enclave
|
||||
Architecture: amd64
|
||||
Version: 1.0
|
||||
Checksums-Md5:
|
||||
7eaa99647090389e9ac1beeba147341f 590772 kbupd-enclave_1.0_amd64.deb
|
||||
ba23fd0b25f3204da0cf3ba59ed7c54b 592228 kbupd-enclave_1.0_amd64.deb
|
||||
Checksums-Sha1:
|
||||
6b5aabb72f1123decede3f65ad80e3ed8e5d50f6 590772 kbupd-enclave_1.0_amd64.deb
|
||||
51130f444f5a0c61289975ba10cb27d60e7301b6 592228 kbupd-enclave_1.0_amd64.deb
|
||||
Checksums-Sha256:
|
||||
61602c437d9dcf8c56bb06a89a1acc1d8af02043cf8333b7605598d45b5ad7fe 590772 kbupd-enclave_1.0_amd64.deb
|
||||
9b3b543c52e23008f2e56151b6cb2db89dc14c06921132c7545993ce10709f2d 592228 kbupd-enclave_1.0_amd64.deb
|
||||
Build-Origin: Debian
|
||||
Build-Architecture: amd64
|
||||
Build-Date: Tue, 01 Sep 2020 18:24:01 +0000
|
||||
Build-Date: Mon, 03 Jan 2022 23:24:02 +0000
|
||||
Installed-Build-Depends:
|
||||
autoconf (= 2.69-11),
|
||||
automake (= 1:1.16.1-4),
|
||||
|
||||
@ -109,6 +109,7 @@ message EnclaveFrontendConfig {
|
||||
required uint32 pending_request_count = 5;
|
||||
required uint32 pending_request_ttl = 6;
|
||||
required uint32 max_backup_data_length = 7;
|
||||
required uint32 ias_version = 8;
|
||||
}
|
||||
|
||||
message SourcePartitionConfig {
|
||||
@ -132,6 +133,7 @@ message EnclaveReplicaConfig {
|
||||
required uint32 storage_page_cache_size = 10;
|
||||
required uint32 raft_log_index_page_cache_size = 13;
|
||||
required uint32 max_frontend_count = 14;
|
||||
required uint32 ias_version = 15;
|
||||
}
|
||||
|
||||
message StartReplicaGroupRequest {
|
||||
|
||||
@ -144,6 +144,8 @@ pub struct EnclaveFrontendConfig {
|
||||
pub pending_request_ttl: u32,
|
||||
#[prost(uint32, required, tag = "7")]
|
||||
pub max_backup_data_length: u32,
|
||||
#[prost(uint32, required, tag = "8")]
|
||||
pub ias_version: u32,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SourcePartitionConfig {
|
||||
@ -181,6 +183,8 @@ pub struct EnclaveReplicaConfig {
|
||||
pub raft_log_index_page_cache_size: u32,
|
||||
#[prost(uint32, required, tag = "14")]
|
||||
pub max_frontend_count: u32,
|
||||
#[prost(uint32, required, tag = "15")]
|
||||
pub ias_version: u32,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct StartReplicaGroupRequest {
|
||||
|
||||
@ -56,6 +56,7 @@ pub struct NodeParams {
|
||||
node_key: Rc<[u8]>,
|
||||
node_id: NodeId,
|
||||
node_type: NodeType,
|
||||
ias_version: u32,
|
||||
}
|
||||
|
||||
pub struct RemoteSender<M>
|
||||
@ -462,7 +463,7 @@ where
|
||||
match self.accept_connection(&connect_request.noise_data) {
|
||||
Ok((noise, their_handshake_hash)) => match self.auth_type {
|
||||
RemoteAuthorizationType::Mutual | RemoteAuthorizationType::RemoteOnly => {
|
||||
match validate_ias_report(connect_request.ias_report.as_ref(), &their_handshake_hash.hash) {
|
||||
match validate_ias_report(connect_request.ias_report.as_ref(), self.node_params.ias_version, &their_handshake_hash.hash) {
|
||||
Ok(attestation) => {
|
||||
*session = SessionState::Accepted {
|
||||
noise,
|
||||
@ -611,7 +612,7 @@ where
|
||||
} => (noise, their_handshake_hash, final_handshake_hash),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
match validate_ias_report(Some(&ias_report), &their_handshake_hash.hash) {
|
||||
match validate_ias_report(Some(&ias_report), self.node_params.ias_version, &their_handshake_hash.hash) {
|
||||
Ok(attestation) => {
|
||||
let handshake_hash = final_handshake_hash;
|
||||
*session = SessionState::Authorized {
|
||||
@ -634,7 +635,7 @@ where
|
||||
attestation,
|
||||
handshake_hash,
|
||||
..
|
||||
} => match validate_ias_report(Some(&ias_report), &handshake_hash.get_hash_for_node(&self.remote_node_id)) {
|
||||
} => match validate_ias_report(Some(&ias_report), self.node_params.ias_version, &handshake_hash.get_hash_for_node(&self.remote_node_id)) {
|
||||
Ok(new_attestation) => {
|
||||
verbose!("validated attestation report for {}: {}", &self.remote_node_id, &new_attestation);
|
||||
*attestation = Some(new_attestation);
|
||||
@ -823,6 +824,7 @@ fn parse_ias_timestamp(timestamp: &str) -> Result<u64, AttestationVerificationEr
|
||||
|
||||
fn validate_ias_report(
|
||||
maybe_ias_report: Option<&IasReport>,
|
||||
ias_version: u32,
|
||||
expected_report_data: &[u8],
|
||||
) -> Result<AttestationParameters, AttestationVerificationError>
|
||||
{
|
||||
@ -845,12 +847,32 @@ fn validate_ias_report(
|
||||
|
||||
let body: IasReportBody = serde_json::from_slice(&ias_report.body[..]).map_err(AttestationVerificationError::InvalidJson)?;
|
||||
|
||||
if body.version != 3 {
|
||||
if body.version != ias_version as u64 {
|
||||
return Err(AttestationVerificationError::WrongVersion(body.version));
|
||||
}
|
||||
|
||||
match body.isvEnclaveQuoteStatus.as_str() {
|
||||
"OK" => {}
|
||||
"SW_HARDENING_NEEDED" => {
|
||||
// To quote from Intel's documentation:
|
||||
//
|
||||
// > An attestation response may report “SW_HARDENING_NEEDED” for attestation requests
|
||||
// > originating from Intel® SGX-enabled platforms that have applied the microcode and
|
||||
// > SGX platform software update and are properly configured but are affected by
|
||||
// > INTEL-SA-00334. In this case a Remote Attestation Verifier should evaluate the
|
||||
// > potential risk of an attack on these platforms and whether the attesting enclave
|
||||
// > employs adequate software hardening to mitigate the risk.
|
||||
//
|
||||
// We have, indeed, applied software mitigations for INTEL-SA-00334, and can consider
|
||||
// SW_HARDENING_NEEDED an acceptable status as long as the only named advisory is the
|
||||
// one we've already mitigated.
|
||||
//
|
||||
// The check for INTEL-SA-00334 was introduced in IASv4, and should never appear under
|
||||
// IASv3.
|
||||
if ias_version < 4 || body.advisoryIDs != vec![String::from("INTEL-SA-00334")] {
|
||||
return Err(AttestationVerificationError::AttestationError(body.isvEnclaveQuoteStatus));
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "insecure")]
|
||||
"GROUP_OUT_OF_DATE" | "CONFIGURATION_NEEDED" => {}
|
||||
"SIGRL_VERSION_MISMATCH" => {
|
||||
@ -911,6 +933,8 @@ pub struct IasReportBody {
|
||||
pub version: u64,
|
||||
|
||||
pub timestamp: String,
|
||||
|
||||
pub advisoryIDs: Vec<String>,
|
||||
}
|
||||
|
||||
impl fmt::Display for AttestationVerificationError {
|
||||
@ -963,7 +987,7 @@ impl Deref for NodeId {
|
||||
//
|
||||
|
||||
impl NodeParams {
|
||||
pub fn generate(node_type: NodeType) -> Self {
|
||||
pub fn generate(node_type: NodeType, ias_version: u32) -> Self {
|
||||
let params = NOISE_PARAMS.parse().unwrap_or_else(|_| unreachable!());
|
||||
let builder = snow::Builder::with_resolver(params, Box::new(SnowResolver));
|
||||
let keypair = builder.generate_keypair().unwrap_or_else(|_| unreachable!());
|
||||
@ -972,6 +996,7 @@ impl NodeParams {
|
||||
node_key: keypair.private.into(),
|
||||
node_id: keypair.public.into(),
|
||||
node_type,
|
||||
ias_version,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -66,9 +66,9 @@ enum QeInfoRequestState {
|
||||
impl<T> PeerManager<T>
|
||||
where T: Peer
|
||||
{
|
||||
pub fn new(node_type: NodeType) -> Self {
|
||||
pub fn new(node_type: NodeType, ias_version: u32) -> Self {
|
||||
Self {
|
||||
node_params: Rc::new(NodeParams::generate(node_type)),
|
||||
node_params: Rc::new(NodeParams::generate(node_type, ias_version)),
|
||||
noise_buffers: Default::default(),
|
||||
connecting_peers: Default::default(),
|
||||
qe_info_req: QeInfoRequestState::None,
|
||||
|
||||
@ -87,9 +87,11 @@ pub struct PendingClientRequest {
|
||||
|
||||
impl FrontendState {
|
||||
pub fn init(request: StartFrontendRequest) -> Self {
|
||||
let ias_version = request.config.ias_version;
|
||||
|
||||
let mut state = Self {
|
||||
config: request.config,
|
||||
replicas: PeerManager::new(NODE_TYPE),
|
||||
replicas: PeerManager::new(NODE_TYPE, ias_version),
|
||||
partitions: Default::default(),
|
||||
key_ranges: Default::default(),
|
||||
last_request_id: Default::default(),
|
||||
|
||||
@ -80,8 +80,10 @@ enum PeerMessage {
|
||||
|
||||
impl ReplicaState {
|
||||
pub fn init(request: StartReplicaRequest) -> Self {
|
||||
let ias_version = request.config.ias_version;
|
||||
|
||||
let state = Self {
|
||||
peers: PeerManager::new(NodeType::Replica),
|
||||
peers: PeerManager::new(NodeType::Replica, ias_version),
|
||||
config: request.config,
|
||||
frontends: Lru::new(),
|
||||
partition: None,
|
||||
|
||||
2
service/.gitignore
vendored
2
service/.gitignore
vendored
@ -5,3 +5,5 @@
|
||||
/config/*.staging.pem
|
||||
/config/*.testing.yml
|
||||
/config/*.testing.pem
|
||||
/config/frontend.staging*.yml
|
||||
/config/frontend.production*.yml
|
||||
|
||||
2
service/Cargo.lock
generated
2
service/Cargo.lock
generated
@ -648,7 +648,7 @@ checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
|
||||
|
||||
[[package]]
|
||||
name = "kbupd"
|
||||
version = "1.0.104"
|
||||
version = "1.0.105"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"byteorder",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
authors = ["Open Whisper Systems"]
|
||||
name = "kbupd"
|
||||
version = "1.0.104"
|
||||
version = "1.0.105"
|
||||
license = "AGPL-3.0-or-later"
|
||||
description = "Key Backup Service Daemon"
|
||||
edition = "2018"
|
||||
|
||||
Binary file not shown.
@ -13,11 +13,12 @@ use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use failure::{format_err, ResultExt};
|
||||
use failure::{bail, format_err, ResultExt};
|
||||
use futures::future;
|
||||
use futures::prelude::*;
|
||||
use hyper::Uri;
|
||||
use hyper::client::connect::HttpConnector;
|
||||
use ias_client::IasApiVersion;
|
||||
use kbupd_config::metrics::*;
|
||||
use kbupd_config::FrontendConfig;
|
||||
use kbuptlsd::prelude::*;
|
||||
@ -96,8 +97,15 @@ impl FrontendService {
|
||||
hostname: TlsClientProxyHostnameArgument::Hostname(hostname)
|
||||
})
|
||||
.context("error creating intel attestation tls proxy client")?;
|
||||
|
||||
let ias_version = match config.attestation.iasVersion {
|
||||
None | Some(3) => IasApiVersion::ApiVer3,
|
||||
Some(4) => IasApiVersion::ApiVer4,
|
||||
_ => bail!("unrecognized IAS version: {}", config.attestation.iasVersion.unwrap())
|
||||
};
|
||||
|
||||
let new_intel_client =
|
||||
new_ias_client(&config.attestation.host, &config.attestation.apiKey, intel_client_proxy).context("error creating intel attestation client")?;
|
||||
new_ias_client(&config.attestation.host, ias_version, &config.attestation.apiKey, intel_client_proxy).context("error creating intel attestation client")?;
|
||||
handshake_manager = Some(HandshakeManager::new(
|
||||
enclave_manager_tx.clone(),
|
||||
new_intel_client.clone(),
|
||||
@ -137,6 +145,7 @@ impl FrontendService {
|
||||
let enclave_spid = config.attestation.spid;
|
||||
let enclave_executor = runtime.executor();
|
||||
let enclave_directory = cmdline_config.enclave_directory.to_owned();
|
||||
let ias_version = config.attestation.iasVersion.unwrap_or(3);
|
||||
let enclave_thread = thread::spawn(move || -> Result<(), failure::Error> {
|
||||
let mut enclaves = Vec::with_capacity(enclave_configs.len());
|
||||
for (enclave_config, partitions) in enclave_configs {
|
||||
@ -160,6 +169,7 @@ impl FrontendService {
|
||||
pending_request_ttl: util::duration::as_ticks(pending_request_ttl, timer_tick_interval),
|
||||
pending_request_count: enclave_config.pendingRequestCount,
|
||||
max_backup_data_length: enclave_config.maxBackupDataLength,
|
||||
ias_version,
|
||||
};
|
||||
|
||||
let mut partition_configs = Vec::new();
|
||||
|
||||
@ -13,11 +13,11 @@ use kbuptlsd::prelude::*;
|
||||
|
||||
pub type KbupdIasClient = IasClient<TlsProxyConnector<HttpConnector>>;
|
||||
|
||||
pub fn new_ias_client(host: &str, api_key: &str, tls_proxy: TlsClientProxySpawner) -> Result<KbupdIasClient, failure::Error> {
|
||||
pub fn new_ias_client(host: &str, ias_version: IasApiVersion, api_key: &str, tls_proxy: TlsClientProxySpawner) -> Result<KbupdIasClient, failure::Error> {
|
||||
let mut http_connector = HttpConnector::new(1);
|
||||
http_connector.enforce_http(false);
|
||||
|
||||
let tls_connector = TlsProxyConnector::new(Arc::new(tls_proxy), http_connector);
|
||||
|
||||
IasClient::new(host, Some(IasApiVersion::ApiVer3), Some(api_key), tls_connector)
|
||||
IasClient::new(host, Some(ias_version), Some(api_key), tls_connector)
|
||||
}
|
||||
|
||||
@ -109,6 +109,7 @@ message EnclaveFrontendConfig {
|
||||
required uint32 pending_request_count = 5;
|
||||
required uint32 pending_request_ttl = 6;
|
||||
required uint32 max_backup_data_length = 7;
|
||||
required uint32 ias_version = 8;
|
||||
}
|
||||
|
||||
message SourcePartitionConfig {
|
||||
@ -132,6 +133,7 @@ message EnclaveReplicaConfig {
|
||||
required uint32 storage_page_cache_size = 10;
|
||||
required uint32 raft_log_index_page_cache_size = 13;
|
||||
required uint32 max_frontend_count = 14;
|
||||
required uint32 ias_version = 15;
|
||||
}
|
||||
|
||||
message StartReplicaGroupRequest {
|
||||
|
||||
@ -11,10 +11,11 @@ use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use failure::ResultExt;
|
||||
use failure::{bail, ResultExt};
|
||||
use futures::prelude::*;
|
||||
use hyper::Uri;
|
||||
use hyper::client::connect::HttpConnector;
|
||||
use ias_client::IasApiVersion;
|
||||
use kbupd_config::metrics::*;
|
||||
use kbupd_config::ReplicaConfig;
|
||||
use kbuptlsd::prelude::*;
|
||||
@ -82,6 +83,12 @@ impl ReplicaService {
|
||||
.host()
|
||||
.expect("attestation host does not contain a hostname"));
|
||||
|
||||
let ias_version = match config.attestation.iasVersion {
|
||||
None | Some(3) => IasApiVersion::ApiVer3,
|
||||
Some(4) => IasApiVersion::ApiVer4,
|
||||
_ => bail!("unrecognized IAS version: {}", config.attestation.iasVersion.unwrap())
|
||||
};
|
||||
|
||||
let intel_client_proxy =
|
||||
TlsClientProxySpawner::new(cmdline_config.kbuptlsd_bin_path.to_owned(), TlsClientProxyArguments::NoConfig {
|
||||
ca: TlsClientProxyCaArgument::System,
|
||||
@ -89,7 +96,7 @@ impl ReplicaService {
|
||||
hostname: TlsClientProxyHostnameArgument::Hostname(hostname)
|
||||
})
|
||||
.context("error creating intel attestation tls client proxy")?;
|
||||
Some(new_ias_client(&config.attestation.host, &config.attestation.apiKey, intel_client_proxy).context("error creating intel attestation client")?)
|
||||
Some(new_ias_client(&config.attestation.host, ias_version, &config.attestation.apiKey, intel_client_proxy).context("error creating intel attestation client")?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -126,8 +133,8 @@ impl ReplicaService {
|
||||
transfer_chunk_size: config.enclave.transferChunkSize,
|
||||
storage_page_cache_size: Default::default(), // unused
|
||||
max_frontend_count: config.enclave.maxFrontendCount,
|
||||
|
||||
raft_log_index_page_cache_size: 10,
|
||||
ias_version: config.attestation.iasVersion.unwrap_or(3),
|
||||
};
|
||||
|
||||
info!(
|
||||
|
||||
@ -76,6 +76,8 @@ pub struct FrontendAttestationConfig {
|
||||
pub disabled: bool,
|
||||
|
||||
pub apiKey: String,
|
||||
|
||||
pub iasVersion: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
||||
@ -39,6 +39,8 @@ pub struct ReplicaAttestationConfig {
|
||||
pub disabled: bool,
|
||||
|
||||
pub apiKey: String,
|
||||
|
||||
pub iasVersion: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user