-
Notifications
You must be signed in to change notification settings - Fork 154
Porting existing Fog Ledger tests to Router #3138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
1765353
Port existing tests to router server binary, except key image
awygle 90f99c7
Port key image test in router_connection.rs to streaming API
awygle dd0fc71
Fixups from rebase
awygle 7409117
remove logging statements
awygle ee1edb2
All Ledger tests now use portpicker to select ports
awygle 0e96fb6
Fog router support for the unary API (#3123)
NotGyro 6ab1ef5
Apply suggestions from code review
awygle f89ffa6
Pull request feedback
awygle File filter 8000
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,259 @@ | ||
// Copyright (c) 2023 The MobileCoin Foundation | ||
|
||
use aes_gcm::Aes256Gcm; | ||
use futures::{executor::block_on, SinkExt, TryStreamExt}; | ||
use grpcio::{ChannelBuilder, ClientDuplexReceiver, ClientDuplexSender, Environment}; | ||
use mc_attest_ake::{ | ||
AuthResponseInput, ClientInitiate, Error as AttestAkeError, Ready, Start, Transition, | ||
}; | ||
use mc_attest_core::VerificationReport; | ||
use mc_attest_verifier::Verifier; | ||
use mc_common::logger::{log, o, Logger}; | ||
use mc_crypto_keys::X25519; | ||
use mc_crypto_noise::CipherError; | ||
use mc_crypto_rand::McRng; | ||
use mc_fog_api::{ | ||
attest::{AuthMessage, Message}, | ||
ledger::{LedgerRequest, LedgerResponse}, | ||
ledger_grpc::LedgerApiClient, | ||
}; | ||
use mc_fog_types::ledger::{CheckKeyImagesRequest, CheckKeyImagesResponse, KeyImageQuery}; | ||
use mc_fog_uri::FogLedgerUri; | ||
use mc_transaction_core::ring_signature::KeyImage; | ||
use mc_util_grpc::ConnectionUriGrpcioChannel; | ||
use mc_util_serial::DecodeError; | ||
use mc_util_uri::{ConnectionUri, UriConversionError}; | ||
use sha2::Sha512; | ||
use std::sync::Arc; | ||
|
||
/// A high-level object mediating requests to the fog ledger router service | ||
pub struct LedgerGrpcClient { | ||
awygle marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// A logger object | ||
logger: Logger, | ||
|
||
/// The URI of the router to communicate with | ||
uri: FogLedgerUri, | ||
|
||
/// An object which can verify a fog node's provided IAS report | ||
verifier: Verifier, | ||
|
||
/// The AKE state machine object, if one is available. | ||
attest_cipher: Option<Ready<Aes256Gcm>>, | ||
|
||
/// Sends requests to the fog ledger router | ||
request_sender: ClientDuplexSender<LedgerRequest>, | ||
|
||
/// Receives responses from the fog ledger router | ||
response_receiver: ClientDuplexReceiver<LedgerResponse>, | ||
|
||
/// Low-lever ledger API client | ||
_client: LedgerApiClient, | ||
} | ||
|
||
impl LedgerGrpcClient { | ||
/// Creates a new fog ledger router grpc client and opens a streaming | ||
/// connection to the fog ledger router service. | ||
/// | ||
/// Arguments: | ||
/// * uri: The Uri to connect to | ||
/// * verifier: The attestation verifier | ||
/// * env: A grpc environment (thread pool) to use for this connection | ||
/// * logger: For logging | ||
pub fn new( | ||
uri: FogLedgerUri, | ||
verifier: Verifier, | ||
env: Arc<Environment>, | ||
logger: Logger, | ||
) -> Self { | ||
let logger = logger.new(o!("mc.fog.ledger.router.uri" => uri.to_string())); | ||
|
||
let ch = ChannelBuilder::default_channel_builder(env).connect_to_uri(&uri, &logger); | ||
let client = LedgerApiClient::new(ch); | ||
let (request_sender, response_receiver) = client | ||
.request() | ||
.expect("Could not retrieve grpc sender and receiver."); | ||
|
||
Self { | ||
logger, | ||
attest_cipher: None, | ||
_client: client, | ||
request_sender, | ||
response_receiver, | ||
uri, | ||
verifier, | ||
} | ||
} | ||
|
||
fn is_attested(&self) -> bool { | ||
self.attest_cipher.is_some() | ||
} | ||
|
||
async fn attest(&mut self) -> Result<VerificationReport, Error> { | ||
// If we have an existing attestation, nuke it. | ||
self.deattest(); | ||
|
||
let mut csprng = McRng::default(); | ||
|
||
let initiator = Start::new(self.uri.responder_id()?.to_string()); | ||
|
||
let init_input = ClientInitiate::<X25519, Aes256Gcm, Sha512>::default(); | ||
let (initiator, auth_request_output) = initiator.try_next(&mut csprng, init_input)?; | ||
|
||
let attested_message: AuthMessage = auth_request_output.into(); | ||
let mut request = LedgerRequest::new(); | ||
request.set_auth(attested_message); | ||
self.request_sender | ||
.send((request.clone(), grpcio::WriteFlags::default())) | ||
.await?; | ||
|
||
let mut response = self | ||
.response_receiver | ||
.try_next() | ||
.await? | ||
.ok_or(Error::ResponseNotReceived)?; | ||
let auth_response_msg = response.take_auth(); | ||
|
||
// Process server response, check if key exchange is successful | ||
let auth_response_event = | ||
AuthResponseInput::new(auth_response_msg.into(), self.verifier.clone()); | ||
let (initiator, verification_report) = | ||
initiator.try_next(&mut csprng, auth_response_event)?; | ||
|
||
self.attest_cipher = Some(initiator); | ||
|
||
Ok(verification_report) | ||
} | ||
|
||
fn deattest(&mut self) { | ||
if self.is_attested() { | ||
log::trace!(self.logger, "Tearing down existing attested connection."); | ||
self.attest_cipher = None; | ||
} | ||
} | ||
|
||
/// Check one or more key images against the ledger router service | ||
pub async fn check_key_images( | ||
1E79 &mut self, | ||
key_images: &[KeyImage], | ||
) -> Result<CheckKeyImagesResponse, Error> { | ||
log::trace!(self.logger, "Check key images was called"); | ||
if !self.is_attested() { | ||
let verification_report = self.attest().await; | ||
verification_report?; | ||
} | ||
|
||
let key_images_queries = key_images | ||
.iter() | ||
.map(|&key_image| KeyImageQuery { | ||
key_image, | ||
start_block: 0, | ||
F438 }) | ||
.collect(); | ||
let key_images_request = CheckKeyImagesRequest { | ||
queries: key_images_queries, | ||
}; | ||
|
||
// No authenticated data associated with ledger query | ||
let aad = vec![]; | ||
awygle marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
let msg = { | ||
let attest_cipher = self | ||
.attest_cipher | ||
.as_mut() | ||
.expect("no enclave_connection even though attest succeeded"); | ||
|
||
let mut msg = Message::new(); | ||
msg.set_channel_id(Vec::from(attest_cipher.binding())); | ||
msg.set_aad(aad.clone()); | ||
|
||
let plaintext_bytes = mc_util_serial::encode(&key_images_request); | ||
|
||
let request_ciphertext = attest_cipher.encrypt(&aad, &plaintext_bytes)?; | ||
msg.set_data(request_ciphertext); | ||
msg | ||
}; | ||
let mut request = LedgerRequest::new(); | ||
request.set_check_key_images(msg); | ||
|
||
self.request_sender | ||
.send((request.clone(), grpcio::WriteFlags::default())) | ||
.await?; | ||
|
||
let message = self | ||
.response_receiver | ||
.try_next() | ||
.await? | ||
.ok_or(Error::ResponseNotReceived)? | ||
.take_check_key_image_response(); | ||
|
||
{ | ||
let attest_cipher = self | ||
.attest_cipher | ||
.as_mut() | ||
.expect("no enclave_connection even though attest succeeded"); | ||
|
||
let plaintext_bytes = attest_cipher.decrypt(message.get_aad(), message.get_data())?; | ||
let plaintext_response: CheckKeyImagesResponse = | ||
mc_util_serial::decode(&plaintext_bytes)?; | ||
Ok(plaintext_response) | ||
} | ||
} | ||
} | ||
|
||
impl Drop for LedgerGrpcClient { | ||
fn drop(&mut self) { | ||
block_on(self.request_sender.close()).expect("Couldn't close the router request sender"); | ||
} | ||
} | ||
|
||
/// Errors related to the Fog View Router Client. | ||
#[derive(Debug)] | ||
pub enum Error { | ||
/// Decode errors. | ||
Decode(DecodeError), | ||
|
||
/// Uri conversion errors. | ||
UriConversion(UriConversionError), | ||
|
||
/// Cipher errors. | ||
Cipher(CipherError), | ||
|
||
/// Attestation errors. | ||
Attestation(AttestAkeError), | ||
|
||
/// Grpc errors. | ||
Grpc(grpcio::Error), | ||
|
||
/// Response not received | ||
ResponseNotReceived, | ||
} | ||
|
||
impl From<DecodeError> for Error { | ||
fn from(err: DecodeError) -> Self { | ||
Self::Decode(err) | ||
} | ||
} | ||
|
||
impl From<CipherError> for Error { | ||
fn from(err: CipherError) -> Self { | ||
Self::Cipher(err) | ||
} | ||
} | ||
|
||
impl From<grpcio::Error> for Error { | ||
fn from(err: grpcio::Error) -> Self { | ||
Self::Grpc(err) | ||
} | ||
} | ||
|
||
impl From<UriConversionError> for Error { | ||
fn from(err: UriConversionError) -> Self { | ||
Self::UriConversion(err) | ||
} | ||
} | ||
|
||
impl From<AttestAkeError> for Error { | ||
fn from(err: AttestAkeError) -> Self { | ||
Self::Attestation(err) | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.