diff --git a/keyserver/addons/rust-node-addon/src/identity_client.rs b/keyserver/addons/rust-node-addon/src/identity_client.rs --- a/keyserver/addons/rust-node-addon/src/identity_client.rs +++ b/keyserver/addons/rust-node-addon/src/identity_client.rs @@ -31,10 +31,9 @@ #[instrument(skip_all)] pub async fn register_user( user_id: String, - device_id: String, + signing_public_key: String, username: String, password: String, - user_public_key: String, ) -> Result { let channel = Channel::from_static(&IDENTITY_SERVICE_SOCKET_ADDR) .connect() @@ -68,10 +67,9 @@ let (registration_request, client_registration) = pake_registration_start( &mut client_rng, user_id, + signing_public_key, &password, - device_id, username, - user_public_key, )?; send_to_mpsc(tx.clone(), registration_request).await?; @@ -163,10 +161,9 @@ fn pake_registration_start( rng: &mut (impl Rng + CryptoRng), user_id: String, + signing_public_key: String, password: &str, - device_id: String, username: String, - user_public_key: String, ) -> Result<(RegistrationRequest, ClientRegistration)> { let client_registration_start_result = ClientRegistration::::start(rng, password.as_bytes()).map_err( @@ -182,10 +179,9 @@ data: Some(PakeRegistrationRequestAndUserId( PakeRegistrationRequestAndUserIdStruct { user_id, - device_id, pake_registration_request, username, - user_public_key, + signing_public_key, }, )), }, diff --git a/native/native_rust_library/src/identity_client.rs b/native/native_rust_library/src/identity_client.rs --- a/native/native_rust_library/src/identity_client.rs +++ b/native/native_rust_library/src/identity_client.rs @@ -58,7 +58,7 @@ pub async fn verify_user_token( mut client: Box, user_id: String, - device_id: String, + signing_public_key: String, access_token: String, ) -> Result { Ok( @@ -66,7 +66,7 @@ .identity_client .verify_user_token(VerifyUserTokenRequest { user_id, - device_id, + signing_public_key, access_token, }) .await? @@ -78,10 +78,9 @@ pub async fn register_user( mut client: Box, user_id: String, - device_id: String, + signing_public_key: String, username: String, password: String, - user_public_key: String, ) -> Result { // Create a RegistrationRequest channel and use ReceiverStream to turn the // MPSC receiver into a Stream for outbound messages @@ -103,9 +102,8 @@ &mut client_rng, user_id, &password, - device_id, + signing_public_key, username, - user_public_key, )?; if let Err(e) = tx.send(registration_request).await { error!("Response was dropped: {}", e); @@ -140,9 +138,8 @@ pub async fn login_user_pake( mut client: Box, user_id: String, - device_id: String, + signing_public_key: String, password: String, - user_public_key: String, ) -> Result { // Create a LoginRequest channel and use ReceiverStream to turn the // MPSC receiver into a Stream for outbound messages @@ -166,7 +163,7 @@ data: Some(PakeCredentialRequestAndUserId( PakeCredentialRequestAndUserIdStruct { user_id, - device_id, + signing_public_key, pake_credential_request: client_login_start_result .message .serialize() @@ -174,7 +171,6 @@ error!("Could not serialize credential request: {}", e); Status::failed_precondition("PAKE failure") })?, - user_public_key, }, )), })), @@ -204,10 +200,9 @@ pub async fn login_user_wallet( mut client: Box, user_id: String, - device_id: String, + signing_public_key: String, siwe_message: String, siwe_signature: Vec, - user_public_key: String, ) -> Result { // Create a LoginRequest channel and use ReceiverStream to turn the // MPSC receiver into a Stream for outbound messages @@ -227,10 +222,9 @@ let login_request = LoginRequest { data: Some(WalletLoginRequest(WalletLoginRequestStruct { user_id, - device_id, + signing_public_key, siwe_message, siwe_signature, - user_public_key, })), }; if let Err(e) = tx.send(login_request).await { @@ -247,9 +241,8 @@ rng: &mut (impl Rng + CryptoRng), user_id: String, password: &str, - device_id: String, + signing_public_key: String, username: String, - user_public_key: String, ) -> Result<(RegistrationRequest, ClientRegistration), Status> { let client_registration_start_result = ClientRegistration::::start(rng, password.as_bytes()).map_err( @@ -265,10 +258,9 @@ data: Some(PakeRegistrationRequestAndUserId( PakeRegistrationRequestAndUserIdStruct { user_id, - device_id, + signing_public_key, pake_registration_request, username, - user_public_key, }, )), }, diff --git a/native/native_rust_library/src/lib.rs b/native/native_rust_library/src/lib.rs --- a/native/native_rust_library/src/lib.rs +++ b/native/native_rust_library/src/lib.rs @@ -55,7 +55,7 @@ fn identity_verify_user_token_blocking( client: Box, user_id: String, - device_id: String, + signing_public_key: String, access_token: String, ) -> Result; @@ -63,29 +63,26 @@ fn identity_register_user_blocking( client: Box, user_id: String, - device_id: String, + signing_public_key: String, username: String, password: String, - user_public_key: String, ) -> Result; #[cxx_name = "identityLoginUserPakeBlocking"] fn identity_login_user_pake_blocking( client: Box, user_id: String, - device_id: String, + signing_public_key: String, password: String, - user_public_key: String, ) -> Result; #[cxx_name = "identityLoginUserWalletBlocking"] fn identity_login_user_wallet_blocking( client: Box, user_id: String, - device_id: String, + signing_public_key: String, siwe_message: String, siwe_signature: Vec, - user_public_key: String, ) -> Result; // Tunnelbroker Service Client @@ -125,13 +122,13 @@ fn identity_verify_user_token_blocking( client: Box, user_id: String, - device_id: String, + signing_public_key: String, access_token: String, ) -> Result { RUNTIME.block_on(identity_client::verify_user_token( client, user_id, - device_id, + signing_public_key, access_token, )) } @@ -140,18 +137,16 @@ fn identity_register_user_blocking( client: Box, user_id: String, - device_id: String, + signing_public_key: String, username: String, password: String, - user_public_key: String, ) -> Result { RUNTIME.block_on(identity_client::register_user( client, user_id, - device_id, + signing_public_key, username, password, - user_public_key, )) } @@ -159,16 +154,14 @@ fn identity_login_user_pake_blocking( client: Box, user_id: String, - device_id: String, + signing_public_key: String, password: String, - user_public_key: String, ) -> Result { RUNTIME.block_on(identity_client::login_user_pake( client, user_id, - device_id, + signing_public_key, password, - user_public_key, )) } @@ -176,18 +169,16 @@ fn identity_login_user_wallet_blocking( client: Box, user_id: String, - device_id: String, + signing_public_key: String, siwe_message: String, siwe_signature: Vec, - user_public_key: String, ) -> Result { RUNTIME.block_on(identity_client::login_user_wallet( client, user_id, - device_id, + signing_public_key, siwe_message, siwe_signature, - user_public_key, )) } diff --git a/services/identity/src/constants.rs b/services/identity/src/constants.rs --- a/services/identity/src/constants.rs +++ b/services/identity/src/constants.rs @@ -10,16 +10,15 @@ pub const USERS_TABLE_PARTITION_KEY: &str = "userID"; pub const USERS_TABLE_REGISTRATION_ATTRIBUTE: &str = "pakeRegistrationData"; pub const USERS_TABLE_USERNAME_ATTRIBUTE: &str = "username"; -pub const USERS_TABLE_USER_PUBLIC_KEY_ATTRIBUTE: &str = "userPublicKey"; pub const USERS_TABLE_DEVICES_ATTRIBUTE: &str = "devices"; -pub const USERS_TABLE_DEVICES_MAP_ATTRIBUTE_NAME: &str = "deviceID"; +pub const USERS_TABLE_DEVICES_MAP_ATTRIBUTE_NAME: &str = "signingPublicKey"; pub const USERS_TABLE_WALLET_ADDRESS_ATTRIBUTE: &str = "walletAddress"; pub const USERS_TABLE_USERNAME_INDEX: &str = "username-index"; pub const USERS_TABLE_WALLET_ADDRESS_INDEX: &str = "walletAddress-index"; pub const ACCESS_TOKEN_TABLE: &str = "identity-tokens"; pub const ACCESS_TOKEN_TABLE_PARTITION_KEY: &str = "userID"; -pub const ACCESS_TOKEN_SORT_KEY: &str = "deviceID"; +pub const ACCESS_TOKEN_SORT_KEY: &str = "signingPublicKey"; pub const ACCESS_TOKEN_TABLE_CREATED_ATTRIBUTE: &str = "created"; pub const ACCESS_TOKEN_TABLE_AUTH_TYPE_ATTRIBUTE: &str = "authType"; pub const ACCESS_TOKEN_TABLE_VALID_ATTRIBUTE: &str = "valid"; 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 @@ -22,8 +22,7 @@ USERS_TABLE_DEVICES_ATTRIBUTE, USERS_TABLE_DEVICES_MAP_ATTRIBUTE_NAME, USERS_TABLE_PARTITION_KEY, USERS_TABLE_REGISTRATION_ATTRIBUTE, USERS_TABLE_USERNAME_ATTRIBUTE, USERS_TABLE_USERNAME_INDEX, - USERS_TABLE_USER_PUBLIC_KEY_ATTRIBUTE, USERS_TABLE_WALLET_ADDRESS_ATTRIBUTE, - USERS_TABLE_WALLET_ADDRESS_INDEX, + USERS_TABLE_WALLET_ADDRESS_ATTRIBUTE, USERS_TABLE_WALLET_ADDRESS_INDEX, }; use crate::nonce::NonceData; use crate::token::{AccessTokenData, AuthType}; @@ -74,10 +73,9 @@ pub async fn update_users_table( &self, user_id: String, - device_id: String, + signing_public_key: Option, registration: Option>, username: Option, - user_public_key: Option, ) -> Result { let mut update_expression_parts = Vec::new(); let mut expression_attribute_names = HashMap::new(); @@ -96,22 +94,17 @@ expression_attribute_values .insert(":u".to_string(), AttributeValue::S(username)); }; - if let Some(public_key) = user_public_key { + if let Some(public_key) = signing_public_key { update_expression_parts.push(format!( "{}.#{} = :k", USERS_TABLE_DEVICES_ATTRIBUTE, USERS_TABLE_DEVICES_MAP_ATTRIBUTE_NAME, )); expression_attribute_names.insert( format!("#{}", USERS_TABLE_DEVICES_MAP_ATTRIBUTE_NAME), - device_id, - ); - expression_attribute_values.insert( - ":k".to_string(), - AttributeValue::M(HashMap::from([( - USERS_TABLE_USER_PUBLIC_KEY_ATTRIBUTE.to_string(), - AttributeValue::S(public_key), - )])), + public_key, ); + expression_attribute_values + .insert(":k".to_string(), AttributeValue::M(HashMap::new())); }; self @@ -142,10 +135,9 @@ pub async fn add_user_to_users_table( &self, user_id: String, - device_id: String, registration: ServerRegistration, username: String, - user_public_key: String, + signing_public_key: String, ) -> Result { let item = HashMap::from([ ( @@ -163,11 +155,8 @@ ( USERS_TABLE_DEVICES_ATTRIBUTE.to_string(), AttributeValue::M(HashMap::from([( - device_id, - AttributeValue::M(HashMap::from([( - USERS_TABLE_USER_PUBLIC_KEY_ATTRIBUTE.to_string(), - AttributeValue::S(user_public_key), - )])), + signing_public_key, + AttributeValue::M(HashMap::new()), )])), ), ]); @@ -213,14 +202,17 @@ pub async fn get_access_token_data( &self, user_id: String, - device_id: String, + signing_public_key: String, ) -> Result, Error> { let primary_key = create_composite_primary_key( ( ACCESS_TOKEN_TABLE_PARTITION_KEY.to_string(), user_id.clone(), ), - (ACCESS_TOKEN_SORT_KEY.to_string(), device_id.clone()), + ( + ACCESS_TOKEN_SORT_KEY.to_string(), + signing_public_key.clone(), + ), ); let get_item_result = self .client @@ -249,7 +241,7 @@ )?; Ok(Some(AccessTokenData { user_id, - device_id, + signing_public_key, access_token, created, auth_type, @@ -258,15 +250,15 @@ } Ok(_) => { info!( - "No item found for user {} and device {} in token table", - user_id, device_id + "No item found for user {} and signing public key {} in token table", + user_id, signing_public_key ); Ok(None) } Err(e) => { error!( - "DynamoDB client failed to get token for user {} on device {}: {}", - user_id, device_id, e + "DynamoDB client failed to get token for user {} with signing public key {}: {}", + user_id, signing_public_key, e ); Err(Error::AwsSdk(e.into())) } @@ -284,7 +276,7 @@ ), ( ACCESS_TOKEN_SORT_KEY.to_string(), - AttributeValue::S(access_token_data.device_id), + AttributeValue::S(access_token_data.signing_public_key), ), ( ACCESS_TOKEN_TABLE_TOKEN_ATTRIBUTE.to_string(), 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 @@ -172,7 +172,7 @@ let message = request.into_inner(); let token_valid = match self .client - .get_access_token_data(message.user_id, message.device_id) + .get_access_token_data(message.user_id, message.signing_public_key) .await { Ok(Some(access_token_data)) => constant_time_eq( @@ -275,19 +275,19 @@ client: DatabaseClient, auth_type: AuthType, user_id: &str, - device_id: &str, + signing_public_key: &str, rng: &mut (impl Rng + CryptoRng), ) -> Result { - if user_id.is_empty() || device_id.is_empty() { + if user_id.is_empty() || signing_public_key.is_empty() { error!( - "Incomplete data: user ID \"{}\", device ID \"{}\"", - user_id, device_id + "Incomplete data: user ID \"{}\", signing public key \"{}\"", + user_id, signing_public_key ); return Err(Status::aborted("user not found")); } let access_token_data = AccessTokenData::new( user_id.to_string(), - device_id.to_string(), + signing_public_key.to_string(), auth_type, rng, ); @@ -302,14 +302,14 @@ fn parse_and_verify_siwe_message( user_id: &str, - device_id: &str, + signing_public_key: &str, siwe_message: &str, siwe_signature: Vec, ) -> Result<(), Status> { - if user_id.is_empty() || device_id.is_empty() { + if user_id.is_empty() || signing_public_key.is_empty() { error!( - "Incomplete data: user ID {}, device ID {}", - user_id, device_id + "Incomplete data: user ID {}, signing public key {}", + user_id, signing_public_key ); return Err(Status::aborted("user not found")); } @@ -334,8 +334,8 @@ ) { Err(e) => { error!( - "Signature verification failed for user {} on device {}: {}", - user_id, device_id, e + "Signature verification failed for user {} with signing public key {}: {}", + user_id, signing_public_key, e ); Err(Status::unauthenticated("message not authenticated")) } @@ -350,17 +350,16 @@ ) -> Result { parse_and_verify_siwe_message( &wallet_login_request.user_id, - &wallet_login_request.device_id, + &wallet_login_request.signing_public_key, &wallet_login_request.siwe_message, wallet_login_request.siwe_signature, )?; client .update_users_table( wallet_login_request.user_id.clone(), - wallet_login_request.device_id.clone(), + Some(wallet_login_request.signing_public_key.clone()), None, None, - Some(wallet_login_request.user_public_key), ) .await .map_err(handle_db_error)?; @@ -370,7 +369,7 @@ client, AuthType::Wallet, &wallet_login_request.user_id, - &wallet_login_request.device_id, + &wallet_login_request.signing_public_key, rng, ) .await?, @@ -430,18 +429,17 @@ async fn pake_login_finish( user_id: &str, - device_id: &str, - user_public_key: &str, + signing_public_key: &str, client: DatabaseClient, server_login: ServerLogin, pake_credential_finalization: &[u8], rng: &mut (impl Rng + CryptoRng), pake_workflow: PakeWorkflow, ) -> Result { - if user_id.is_empty() || device_id.is_empty() { + if user_id.is_empty() || signing_public_key.is_empty() { error!( - "Incomplete data: user ID {}, device ID {}", - user_id, device_id + "Incomplete data: user ID {}, signing public key {}", + user_id, signing_public_key ); return Err(Status::aborted("user not found")); } @@ -464,18 +462,23 @@ client .update_users_table( user_id.to_string(), - device_id.to_string(), + Some(signing_public_key.to_string()), None, None, - Some(user_public_key.to_string()), ) .await .map_err(handle_db_error)?; } Ok(PakeLoginResponseStruct { data: Some(AccessToken( - put_token_helper(client, AuthType::Password, user_id, device_id, rng) - .await?, + put_token_helper( + client, + AuthType::Password, + user_id, + signing_public_key, + rng, + ) + .await?, )), }) } @@ -511,12 +514,11 @@ async fn pake_registration_finish( user_id: &str, - device_id: &str, client: DatabaseClient, registration_upload_bytes: &[u8], server_registration: Option>, username: &str, - user_public_key: &str, + signing_public_key: &str, ) -> Result<(), Status> { if user_id.is_empty() { error!("Incomplete data: user ID not provided"); @@ -543,10 +545,9 @@ match client .add_user_to_users_table( user_id.to_string(), - device_id.to_string(), server_registration_finish_result, username.to_string(), - user_public_key.to_string(), + signing_public_key.to_string(), ) .await { diff --git a/services/identity/src/service/login.rs b/services/identity/src/service/login.rs --- a/services/identity/src/service/login.rs +++ b/services/identity/src/service/login.rs @@ -1,8 +1,7 @@ use super::*; pub struct LoginState { user_id: String, - device_id: String, - user_public_key: String, + signing_public_key: String, pake_state: ServerLogin, } pub async fn handle_login_request( @@ -48,8 +47,8 @@ Ok(Some(LoginState { user_id: pake_credential_request_and_user_id.user_id, - device_id: pake_credential_request_and_user_id.device_id, - user_public_key: pake_credential_request_and_user_id.user_public_key, + signing_public_key: pake_credential_request_and_user_id + .signing_public_key, pake_state: response_and_state.pake_state, })) } @@ -72,8 +71,7 @@ })) => { let login_finish_result = pake_login_finish( &login_state.user_id, - &login_state.device_id, - &login_state.user_public_key, + &login_state.signing_public_key, client, login_state.pake_state, &pake_credential_finalization, diff --git a/services/identity/src/service/registration.rs b/services/identity/src/service/registration.rs --- a/services/identity/src/service/registration.rs +++ b/services/identity/src/service/registration.rs @@ -1,9 +1,8 @@ use super::*; pub struct RegistrationState { user_id: String, - device_id: String, username: String, - user_public_key: String, + signing_public_key: String, pub pake_state: Option>, } @@ -48,9 +47,9 @@ Ok(RegistrationState { user_id: pake_registration_request_and_user_id.user_id, - device_id: pake_registration_request_and_user_id.device_id, username: pake_registration_request_and_user_id.username, - user_public_key: pake_registration_request_and_user_id.user_public_key, + signing_public_key: pake_registration_request_and_user_id + .signing_public_key, pake_state: Some(response_and_state.pake_state), }) } @@ -74,13 +73,12 @@ })) => { let response_and_state = match pake_registration_finish( ®istration_state.user_id, - ®istration_state.device_id, client.clone(), &pake_registration_upload_and_credential_request .pake_registration_upload, Some(pake_state), ®istration_state.username, - ®istration_state.user_public_key, + ®istration_state.signing_public_key, ) .await { @@ -126,8 +124,7 @@ })) => { let login_finish_result = pake_login_finish( ®istration_state.user_id, - ®istration_state.device_id, - ®istration_state.user_public_key, + ®istration_state.signing_public_key, client, server_login, &pake_credential_finalization, diff --git a/services/identity/src/token.rs b/services/identity/src/token.rs --- a/services/identity/src/token.rs +++ b/services/identity/src/token.rs @@ -15,7 +15,7 @@ #[derive(Clone)] pub struct AccessTokenData { pub user_id: String, - pub device_id: String, + pub signing_public_key: String, pub access_token: String, pub created: DateTime, pub auth_type: AuthType, @@ -25,13 +25,13 @@ impl AccessTokenData { pub fn new( user_id: String, - device_id: String, + signing_public_key: String, auth_type: AuthType, rng: &mut (impl Rng + CryptoRng), ) -> Self { AccessTokenData { user_id, - device_id, + signing_public_key, access_token: Alphanumeric.sample_string(rng, ACCESS_TOKEN_LENGTH), created: Utc::now(), auth_type, diff --git a/services/terraform/dynamodb.tf b/services/terraform/dynamodb.tf --- a/services/terraform/dynamodb.tf +++ b/services/terraform/dynamodb.tf @@ -196,7 +196,7 @@ resource "aws_dynamodb_table" "identity-tokens" { name = "identity-tokens" hash_key = "userID" - range_key = "deviceID" + range_key = "signingPublicKey" write_capacity = 10 read_capacity = 10 @@ -206,7 +206,7 @@ } attribute { - name = "deviceID" + name = "signingPublicKey" type = "S" } } diff --git a/shared/protos/identity.proto b/shared/protos/identity.proto --- a/shared/protos/identity.proto +++ b/shared/protos/identity.proto @@ -28,19 +28,19 @@ message PakeRegistrationRequestAndUserID { string userID = 1; - string deviceID = 2; + // ed25519 key for the given user's device + string signingPublicKey = 2; // Message sent to initiate PAKE registration (step 1) bytes pakeRegistrationRequest = 3; string username = 4; - string userPublicKey = 5; } message PakeCredentialRequestAndUserID { string userID = 1; - string deviceID = 2; + // ed25519 key for the given user's device + string signingPublicKey = 2; // Message sent to initiate PAKE login (step 1) bytes pakeCredentialRequest = 3; - string userPublicKey = 4; } message PakeLoginRequest { @@ -71,10 +71,10 @@ message WalletLoginRequest { string userID = 1; - string deviceID = 2; + // ed25519 key for the given user's device + string signingPublicKey = 2; string siweMessage = 3; bytes siweSignature = 4; - string userPublicKey = 5; } message WalletLoginResponse { @@ -124,7 +124,8 @@ message VerifyUserTokenRequest { string userID = 1; - string deviceID = 2; + // ed25519 key for the given user's device + string signingPublicKey = 2; string accessToken = 3; }