0
0
mirror of https://github.com/signalapp/libsignal.git synced 2024-09-20 03:52:17 +02:00

attest: update svr2 constants

This commit is contained in:
Ravi Khadiwala 2023-05-11 15:25:45 -05:00 committed by ravi-signal
parent 806ceb93eb
commit c70f19d294
5 changed files with 83 additions and 37 deletions

View File

@ -53,9 +53,9 @@ public class SgxClientTest {
ServiceType.CDS2
},
{
Hex.fromStringCondensed("f25dfd3b18adc4c0dc190bae1edd603ceca81b42a10b1de52f74db99b338619e"),
Hex.fromStringCondensed("a8a261420a6bb9b61aa25bf8a79e8bd20d7652531feb3381cbffd446d270be95"),
svr2Handshake,
Instant.ofEpochSecond(1676529724),
Instant.ofEpochSecond(1683836600),
ServiceType.SVR2
}
});

View File

@ -30,19 +30,19 @@ public class Svr2ClientTest {
@Test
public void testSaltWithGroupId() throws IOException, AttestationDataException {
final byte[] svr2Handshake = ResourceReader.readAll(SgxClientTest.class.getResourceAsStream("svr2handshakestart.data"));
final byte[] mrenclave = Hex.fromStringCondensed("f25dfd3b18adc4c0dc190bae1edd603ceca81b42a10b1de52f74db99b338619e");
final Instant instant = Instant.ofEpochSecond(1676529724);
final byte[] mrenclave = Hex.fromStringCondensed("a8a261420a6bb9b61aa25bf8a79e8bd20d7652531feb3381cbffd446d270be95");
final Instant instant = Instant.ofEpochSecond(1683836600);
final byte[] pin = "password".getBytes(StandardCharsets.UTF_8);
final byte[] username = "username".getBytes(StandardCharsets.UTF_8);
final long groupId = 3862621253427332054L;
final long groupId = Long.parseUnsignedLong("15525669046665930652");
final Svr2Client svr2Client = Svr2Client.create_NOT_FOR_PRODUCTION(mrenclave, svr2Handshake, instant);
Assert.assertEquals(48, svr2Client.initialRequest().length);
final PinHash actual = svr2Client.hashPin(pin, username);
final byte[] expectedSalt = HKDF.deriveSecrets(username, bebytes(groupId), new byte[]{}, 32);
final byte[] knownSalt = Hex.fromStringCondensed("d6159ba30f90b6eb6ccf1ec844427f052baaf0705da849767471744cdb3f8a5e");
final byte[] knownSalt = Hex.fromStringCondensed("260d1f6d233c9326e8ba744e778b7b127147c7211d9bc3219ab3b7394766c508");
Assert.assertArrayEquals(knownSalt, expectedSalt);
final PinHash expected = PinHash.create(pin, expectedSalt);

View File

@ -5,6 +5,7 @@
use std::collections::HashMap;
use hex_literal::hex;
use lazy_static::lazy_static;
use prost::Message;
@ -16,7 +17,10 @@ use crate::sgx_session::{Error, Result};
lazy_static! {
/// Map from MREnclave to intel SW advisories that are known to be mitigated in the
/// build with that MREnclave value
static ref ACCEPTABLE_SW_ADVISORIES: HashMap<MREnclave, &'static [&'static str]> = HashMap::new();
static ref ACCEPTABLE_SW_ADVISORIES: HashMap<MREnclave, &'static [&'static str]> = HashMap::from([
(hex!("a8a261420a6bb9b61aa25bf8a79e8bd20d7652531feb3381cbffd446d270be95"), &["INTEL-SA-00615", "INTEL-SA-00657"] as &[&str]),
(hex!("6ee1042f9e20f880326686dd4ba50c25359f01e9f733eeba4382bca001d45094"), &["INTEL-SA-00615", "INTEL-SA-00657"] as &[&str]),
]);
}
/// SW advisories known to be mitigated by default. If an MREnclave is provided that
@ -43,7 +47,20 @@ impl PartialEq<svr2::RaftGroupConfig> for RaftConfig {
lazy_static! {
/// Expected raft configuration for a given enclave.
static ref EXPECTED_RAFT_CONFIG: HashMap<MREnclave, &'static RaftConfig> = HashMap::new();
static ref EXPECTED_RAFT_CONFIG: HashMap<MREnclave, &'static RaftConfig> = HashMap::from([
(hex!("a8a261420a6bb9b61aa25bf8a79e8bd20d7652531feb3381cbffd446d270be95"), &RaftConfig {
min_voting_replicas: 3,
max_voting_replicas: 5,
super_majority: 0,
group_id: 15525669046665930652
}),
(hex!("6ee1042f9e20f880326686dd4ba50c25359f01e9f733eeba4382bca001d45094"), &RaftConfig {
min_voting_replicas: 4,
max_voting_replicas: 7,
super_majority: 2,
group_id: 3950115602363750357
}),
]);
}
pub struct Svr2Handshake {
@ -54,26 +71,32 @@ pub struct Svr2Handshake {
pub group_id: u64,
}
#[allow(dead_code)]
fn validate_raft_config(mrenclave: &[u8], raft_config: &svr2::RaftGroupConfig) -> Result<()> {
let expected_config =
*EXPECTED_RAFT_CONFIG
.get(mrenclave)
.ok_or(Error::AttestationDataError {
reason: format!("unknown mrenclave {:?}", mrenclave),
})?;
if expected_config != raft_config {
return Err(Error::AttestationDataError {
reason: format!("Unexpected raft config {:?}", raft_config),
});
}
Ok(())
}
pub fn new_handshake(
mrenclave: &[u8],
attestation_msg: &[u8],
current_time: std::time::SystemTime,
) -> Result<Svr2Handshake> {
new_handshake_with_constants(
mrenclave,
attestation_msg,
current_time,
ACCEPTABLE_SW_ADVISORIES
.get(mrenclave)
.unwrap_or(&DEFAULT_SW_ADVISORIES),
*EXPECTED_RAFT_CONFIG
.get(mrenclave)
.ok_or(Error::AttestationDataError {
reason: format!("unknown mrenclave {:?}", mrenclave),
})?,
)
}
fn new_handshake_with_constants(
mrenclave: &[u8],
attestation_msg: &[u8],
current_time: std::time::SystemTime,
acceptable_sw_advisories: &[&str],
expected_raft_config: &RaftConfig,
) -> Result<Svr2Handshake> {
// Deserialize attestation handshake start.
let handshake_start = svr2::ClientHandshakeStart::decode(attestation_msg)?;
@ -81,9 +104,7 @@ pub fn new_handshake(
mrenclave,
&handshake_start.evidence,
&handshake_start.endorsement,
ACCEPTABLE_SW_ADVISORIES
.get(mrenclave)
.unwrap_or(&DEFAULT_SW_ADVISORIES),
acceptable_sw_advisories,
current_time,
)?;
@ -93,10 +114,13 @@ pub fn new_handshake(
.ok_or(Error::AttestationDataError {
reason: "Claims must contain a raft group config".to_string(),
})?;
let actual_config = svr2::RaftGroupConfig::decode(&**config)?;
// Once we have expected server raft configurations, we can validate the raft config too
// validate_raft_config(mrenclave, &actual_config)?;
let actual_config = svr2::RaftGroupConfig::decode(&**config)?;
if expected_raft_config != &actual_config {
return Err(Error::AttestationDataError {
reason: format!("Unexpected raft config {:?}", expected_raft_config),
});
}
Ok(Svr2Handshake {
handshake,
@ -116,12 +140,34 @@ mod tests {
#[test]
fn attest_svr2() {
let handshake_bytes = read_test_file("tests/data/svr2handshakestart.data");
let current_time = SystemTime::UNIX_EPOCH + Duration::from_secs(1676529724);
let current_time = SystemTime::UNIX_EPOCH + Duration::from_secs(1683836600);
let mrenclave_bytes =
hex!("f25dfd3b18adc4c0dc190bae1edd603ceca81b42a10b1de52f74db99b338619e");
hex!("a8a261420a6bb9b61aa25bf8a79e8bd20d7652531feb3381cbffd446d270be95");
new_handshake(&mrenclave_bytes, &handshake_bytes, current_time).unwrap();
}
#[test]
fn attest_svr2_bad_config() {
let handshake_bytes = read_test_file("tests/data/svr2handshakestart.data");
let current_time = SystemTime::UNIX_EPOCH + Duration::from_secs(1683836600);
let mrenclave_bytes =
hex!("a8a261420a6bb9b61aa25bf8a79e8bd20d7652531feb3381cbffd446d270be95");
assert!(new_handshake_with_constants(
&mrenclave_bytes,
&handshake_bytes,
current_time,
&[],
&RaftConfig {
min_voting_replicas: 3,
max_voting_replicas: 5,
super_majority: 0,
group_id: 0, // wrong
},
)
.is_err());
}
fn matches(
min_voting_replicas: u32,
max_voting_replicas: u32,

View File

@ -23,10 +23,10 @@ class SgxTests: TestCaseBase {
(
ServiceType.svr2,
// echo f25dfd3b18adc4c0dc190bae1edd603ceca81b42a10b1de52f74db99b338619e | xxd -r -p | base64
Data(base64Encoded: "8l39OxitxMDcGQuuHt1gPOyoG0KhCx3lL3TbmbM4YZ4=")!,
// echo a8a261420a6bb9b61aa25bf8a79e8bd20d7652531feb3381cbffd446d270be95 | xxd -r -p | base64
Data(base64Encoded: "qKJhQgprubYaolv4p56L0g12UlMf6zOBy//URtJwvpU=")!,
SgxTests.readResource(forName: "svr2handshakestart.data"),
Date(timeIntervalSince1970: 1_676_529_724)
Date(timeIntervalSince1970: 1_683_836_600)
),
]
@ -110,8 +110,8 @@ class SgxTests: TestCaseBase {
let pin = Array("password".utf8)
let username = Array("username".utf8)
// echo "d6159ba30f90b6eb6ccf1ec844427f052baaf0705da849767471744cdb3f8a5e" | xxd -r -p | base64
let knownSalt = Data(base64Encoded: "1hWbow+Qtutszx7IREJ/BSuq8HBdqEl2dHF0TNs/il4=")!
// echo "260d1f6d233c9326e8ba744e778b7b127147c7211d9bc3219ab3b7394766c508" | xxd -r -p | base64
let knownSalt = Data(base64Encoded: "Jg0fbSM8kybounROd4t7EnFHxyEdm8MhmrO3OUdmxQg=")!
let client = try! Svr2Client.create_NOT_FOR_PRODUCTION(mrenclave: mrenclave, attestationMessage: attestationMsg, currentDate: currentDate)
let pinHash = try! client.hashPin(pin, forUser: username)