Page MenuHomePhabricator

D4285.diff
No OneTemporary

D4285.diff

diff --git a/services/identity/Cargo.lock b/services/identity/Cargo.lock
--- a/services/identity/Cargo.lock
+++ b/services/identity/Cargo.lock
@@ -119,6 +119,7 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
+ "block-padding",
"generic-array",
]
@@ -131,6 +132,12 @@
"generic-array",
]
+[[package]]
+name = "block-padding"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
+
[[package]]
name = "bumpalo"
version = "3.9.1"
@@ -266,6 +273,18 @@
"cfg-if",
]
+[[package]]
+name = "crypto-bigint"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03"
+dependencies = [
+ "generic-array",
+ "rand_core 0.6.3",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "crypto-common"
version = "0.1.3"
@@ -299,6 +318,12 @@
"zeroize",
]
+[[package]]
+name = "der"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4"
+
[[package]]
name = "derive_more"
version = "0.99.17"
@@ -364,12 +389,39 @@
"syn",
]
+[[package]]
+name = "ecdsa"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372"
+dependencies = [
+ "der",
+ "elliptic-curve",
+ "hmac",
+ "signature",
+]
+
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+[[package]]
+name = "elliptic-curve"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b"
+dependencies = [
+ "crypto-bigint",
+ "ff",
+ "generic-array",
+ "group",
+ "rand_core 0.6.3",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "fastrand"
version = "1.7.0"
@@ -379,6 +431,16 @@
"instant",
]
+[[package]]
+name = "ff"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f"
+dependencies = [
+ "rand_core 0.6.3",
+ "subtle",
+]
+
[[package]]
name = "fixedbitset"
version = "0.4.1"
@@ -529,6 +591,17 @@
"wasm-bindgen",
]
+[[package]]
+name = "group"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912"
+dependencies = [
+ "ff",
+ "rand_core 0.6.3",
+ "subtle",
+]
+
[[package]]
name = "h2"
version = "0.3.13"
@@ -706,7 +779,9 @@
"rusoto_core",
"rusoto_dynamodb",
"sha2",
+ "siwe",
"tokio",
+ "tokio-stream",
"tonic",
"tonic-build",
"tracing",
@@ -732,6 +807,15 @@
"cfg-if",
]
+[[package]]
+name = "iri-string"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f0f7638c1e223529f1bfdc48c8b133b9e0b434094d1d28473161ee48b235f78"
+dependencies = [
+ "nom",
+]
+
[[package]]
name = "itertools"
version = "0.10.3"
@@ -756,6 +840,24 @@
"wasm-bindgen",
]
+[[package]]
+name = "k256"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "903ae2481bcdfdb7b68e0a9baa4b7c9aff600b9ae2e8e5bb5833b8c91ab851ea"
+dependencies = [
+ "cfg-if",
+ "ecdsa",
+ "elliptic-curve",
+ "sha3",
+]
+
+[[package]]
+name = "keccak"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838"
+
[[package]]
name = "lazy_static"
version = "1.4.0"
@@ -794,6 +896,12 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
[[package]]
name = "mio"
version = "0.8.2"
@@ -841,6 +949,16 @@
"tempfile",
]
+[[package]]
+name = "nom"
+version = "7.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
[[package]]
name = "ntapi"
version = "0.3.7"
@@ -1393,6 +1511,18 @@
"opaque-debug",
]
+[[package]]
+name = "sha3"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809"
+dependencies = [
+ "block-buffer 0.9.0",
+ "digest 0.9.0",
+ "keccak",
+ "opaque-debug",
+]
+
[[package]]
name = "sharded-slab"
version = "0.1.4"
@@ -1417,6 +1547,32 @@
"libc",
]
+[[package]]
+name = "signature"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4"
+dependencies = [
+ "digest 0.9.0",
+ "rand_core 0.6.3",
+]
+
+[[package]]
+name = "siwe"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86f2d8ae2d4ae58df46e173aa496562ea857ac6a4f0d435ed30fcd19da0aaa79"
+dependencies = [
+ "chrono",
+ "hex",
+ "http",
+ "iri-string",
+ "k256",
+ "rand",
+ "sha3",
+ "thiserror",
+]
+
[[package]]
name = "slab"
version = "0.4.6"
@@ -1594,9 +1750,9 @@
[[package]]
name = "tokio-stream"
-version = "0.1.8"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3"
+checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9"
dependencies = [
"futures-core",
"pin-project-lite",
diff --git a/services/identity/Cargo.toml b/services/identity/Cargo.toml
--- a/services/identity/Cargo.toml
+++ b/services/identity/Cargo.toml
@@ -8,6 +8,7 @@
prost = "0.9"
futures-core = "0.3"
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
+tokio-stream = "0.1.9"
opaque-ke = { version = "1.2.0", features = ["std"] }
argon2 = "0.3"
curve25519-dalek = "3"
@@ -23,6 +24,7 @@
rand = "0.8"
bytes = "1.1"
constant_time_eq = "0.2.2"
+siwe = "0.3"
[build-dependencies]
tonic-build = "0.6"
diff --git a/services/identity/src/database.rs b/services/identity/src/database.rs
--- a/services/identity/src/database.rs
+++ b/services/identity/src/database.rs
@@ -13,6 +13,7 @@
use crate::opaque::Cipher;
use crate::token::{AccessTokenData, AuthType};
+#[derive(Clone)]
pub struct DatabaseClient {
client: DynamoDbClient,
}
diff --git a/services/identity/src/service.rs b/services/identity/src/service.rs
--- a/services/identity/src/service.rs
+++ b/services/identity/src/service.rs
@@ -1,9 +1,14 @@
+use chrono::Utc;
use constant_time_eq::constant_time_eq;
use futures_core::Stream;
+use rand::rngs::OsRng;
use rand::{CryptoRng, Rng};
use rusoto_core::RusotoError;
use rusoto_dynamodb::{GetItemError, PutItemError};
+use siwe::Message;
use std::pin::Pin;
+use tokio::sync::mpsc;
+use tokio_stream::{wrappers::ReceiverStream, StreamExt};
use tonic::{Request, Response, Status};
use tracing::{error, info, instrument};
@@ -14,11 +19,14 @@
pub use proto::identity_service_server::IdentityServiceServer;
use proto::{
identity_service_server::IdentityService,
+ login_request::Data::PakeLoginRequest,
+ login_request::Data::WalletLoginRequest,
login_response::Data::PakeLoginResponse,
login_response::Data::WalletLoginResponse,
pake_login_response::Data::AccessToken, LoginRequest, LoginResponse,
PakeLoginResponse as PakeLoginResponseStruct, RegistrationRequest,
RegistrationResponse, VerifyUserTokenRequest, VerifyUserTokenResponse,
+ WalletLoginRequest as WalletLoginRequestStruct,
WalletLoginResponse as WalletLoginResponseStruct,
};
@@ -56,12 +64,65 @@
type LoginUserStream =
Pin<Box<dyn Stream<Item = Result<LoginResponse, Status>> + Send + 'static>>;
+ #[instrument(skip(self))]
async fn login_user(
&self,
request: Request<tonic::Streaming<LoginRequest>>,
) -> Result<Response<Self::LoginUserStream>, Status> {
- println!("Got a login request: {:?}", request);
- unimplemented!()
+ let mut in_stream = request.into_inner();
+ let (tx, rx) = mpsc::channel(1);
+ let client = self.client.clone();
+ tokio::spawn(async move {
+ let mut num_messages_received = 0;
+ while let Some(message) = in_stream.next().await {
+ match message {
+ Ok(login_request) => {
+ if let Some(data) = login_request.data {
+ match data {
+ WalletLoginRequest(req) => {
+ if let Err(e) = tx
+ .send(
+ wallet_login_helper(
+ client,
+ req,
+ &mut OsRng,
+ num_messages_received,
+ )
+ .await,
+ )
+ .await
+ {
+ error!("Response was dropped: {}", e);
+ }
+ break;
+ }
+ PakeLoginRequest(_) => unimplemented!(),
+ }
+ } else {
+ error!("Received empty login request");
+ if let Err(e) = tx
+ .send(Err(Status::invalid_argument("invalid message")))
+ .await
+ {
+ error!("Response was dropped: {}", e);
+ }
+ break;
+ }
+ }
+ Err(e) => {
+ error!("Received an unexpected error: {}", e);
+ if let Err(e) = tx.send(Err(Status::unknown("unknown error"))).await
+ {
+ error!("Response was dropped: {}", e);
+ }
+ break;
+ }
+ }
+ num_messages_received += 1;
+ }
+ });
+ let out_stream = ReceiverStream::new(rx);
+ Ok(Response::new(Box::pin(out_stream) as Self::LoginUserStream))
}
#[instrument(skip(self))]
@@ -139,3 +200,78 @@
}
}
}
+
+fn parse_and_verify_siwe_message(
+ user_id: &str,
+ device_id: &str,
+ siwe_message: &str,
+ siwe_signature: Vec<u8>,
+) -> Result<(), Status> {
+ if user_id.is_empty() || device_id.is_empty() {
+ error!(
+ "Incomplete data: user ID {}, device ID {}",
+ user_id, device_id
+ );
+ return Err(Status::aborted("user not found"));
+ }
+ let siwe_message: Message = match siwe_message.parse() {
+ Ok(m) => m,
+ Err(e) => {
+ error!("Failed to parse SIWE message: {}", e);
+ return Err(Status::invalid_argument("invalid message"));
+ }
+ };
+ match siwe_message.verify(
+ match siwe_signature.try_into() {
+ Ok(s) => s,
+ Err(e) => {
+ error!("Conversion to SIWE signature failed: {:?}", e);
+ return Err(Status::invalid_argument("invalid message"));
+ }
+ },
+ None,
+ None,
+ Some(&Utc::now()),
+ ) {
+ Err(e) => {
+ error!(
+ "Signature verification failed for user {} on device {}: {}",
+ user_id, device_id, e
+ );
+ Err(Status::unauthenticated("message not authenticated"))
+ }
+ Ok(_) => Ok(()),
+ }
+}
+
+async fn wallet_login_helper(
+ client: DatabaseClient,
+ wallet_login_request: WalletLoginRequestStruct,
+ rng: &mut (impl Rng + CryptoRng),
+ num_messages_received: u8,
+) -> Result<LoginResponse, Status> {
+ if num_messages_received != 0 {
+ error!("Too many messages received in stream, aborting");
+ return Err(Status::aborted("please retry"));
+ }
+ match parse_and_verify_siwe_message(
+ &wallet_login_request.user_id,
+ &wallet_login_request.device_id,
+ &wallet_login_request.siwe_message,
+ wallet_login_request.siwe_signature,
+ ) {
+ Ok(()) => Ok(LoginResponse {
+ data: Some(WalletLoginResponse(WalletLoginResponseStruct {
+ access_token: put_token_helper(
+ client,
+ AuthType::Wallet,
+ &wallet_login_request.user_id,
+ &wallet_login_request.device_id,
+ rng,
+ )
+ .await?,
+ })),
+ }),
+ Err(e) => Err(e),
+ }
+}

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 1, 4:53 PM (21 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2399326
Default Alt Text
D4285.diff (12 KB)

Event Timeline