Changeset View
Standalone View
shared/protos/identity_client.proto
- This file was added.
syntax = "proto3"; | ||||||||||
package identity.client; | ||||||||||
// RPCs betwen a client (iOS, Android, or web) to identity service | ||||||||||
varunUnsubmitted Done Inline Actions
varun: | ||||||||||
jonAuthorUnsubmitted Done Inline Actionsmade it from -> to // RPCs from a client (iOS, Android, or web) to identity service To show client vs server distinction jon: made it `from` -> `to`
```
// RPCs from a client (iOS, Android, or web) to identity service
```… | ||||||||||
service IdentityClientService { | ||||||||||
// Called by user to register with the Identity Service (PAKE only) | ||||||||||
rpc RegisterUser(stream RegistrationRequest) returns (stream | ||||||||||
RegistrationResponse) {} | ||||||||||
// Called by user to update password and receive new access token | ||||||||||
rpc UpdateUserPassword(stream UpdateUserPasswordRequest) returns | ||||||||||
(stream UpdateUserPasswordResponse) {} | ||||||||||
// Called by user to register device and get an access token | ||||||||||
rpc LoginPasswordUser(OpaqueLoginRequest) returns (OpaqueLoginResponse) {} | ||||||||||
rpc LoginWalletUser(WalletLoginRequest) returns (WalletLoginResponse) {} | ||||||||||
// Called by a user to delete their own account | ||||||||||
rpc DeleteUser(DeleteUserRequest) returns (Empty) {} | ||||||||||
varunUnsubmitted Done Inline Actionswe can remove this extra line varun: we can remove this extra line | ||||||||||
jonAuthorUnsubmitted Done Inline ActionsPersonally I like the separation, I think it makes is a lot easier to parse. Currently it's being used to block the CRUD account RPCs vs the others. jon: Personally I like the separation, I think it makes is a lot easier to parse. Currently it's… | ||||||||||
// Called by users and keyservers to get userID corresponding to a wallet | ||||||||||
// address or username | ||||||||||
rpc GetUserID(GetUserIDRequest) returns (GetUserIDResponse) {} | ||||||||||
varunUnsubmitted Done Inline Actionsthink we can just get rid of this RPC, right? varun: think we can just get rid of this RPC, right? | ||||||||||
jonAuthorUnsubmitted Done Inline ActionsThere's nothing that should need it short term, so why not. jon: There's nothing that should need it short term, so why not. | ||||||||||
// Called by clients to get a nonce for a Sign-In with Ethereum message | ||||||||||
rpc GenerateNonce(Empty) returns (GenerateNonceResponse) {} | ||||||||||
// Called by clients to get session initialization info needed to open a new | ||||||||||
// channel of communication with a given user | ||||||||||
rpc GetSessionInitializationInfo(GetSessionInitializationInfoRequest) returns | ||||||||||
(GetSessionInitializationInfoResponse) {} | ||||||||||
} | ||||||||||
// Helper types | ||||||||||
message Empty {} | ||||||||||
// Request for registering a new user | ||||||||||
message ClientRegistrationRequest { | ||||||||||
// ed25519 key for the given user's device | ||||||||||
string signingPublicKey = 1; | ||||||||||
varunUnsubmitted Done Inline Actionsi introduced this name originally, but it's a little ambiguous. primaryEd25519PublicKey would be my suggestion. we should use whatever we decide on everywhere in this file https://linear.app/comm/issue/ENG-3224/change-signingpublickey-to-something-more-descriptive varun: i introduced this name originally, but it's a little ambiguous. `primaryEd25519PublicKey` would… | ||||||||||
jonAuthorUnsubmitted Done Inline ActionsI would rather have deviceEd25519PublicKey, as primary makes it sound as if you're registering the primary device which is out of scope for this work. clientEd25519PublicKey might be more appropriate if keyservers will never touch this endpoint. jon: I would rather have `deviceEd25519PublicKey`, as `primary` makes it sound as if you're… | ||||||||||
// Message sent to initiate PAKE registration (step 1) | ||||||||||
bytes opaqueRegistrationRequest = 2; | ||||||||||
string username = 3; | ||||||||||
// Information specific to a user's device needed to open a new channel of | ||||||||||
// communication with this user | ||||||||||
SessionInitializationInfo sessionInitializationInfo = 4; | ||||||||||
} | ||||||||||
message SessionInitializationInfo { | ||||||||||
string payload = 1; | ||||||||||
string payloadSignature = 2; // payload signed with the signing ed25519 key | ||||||||||
optional string socialProof = 3; // signed message used for SIWE (optional) | ||||||||||
} | ||||||||||
ashoatUnsubmitted Done Inline ActionsI think we need to add:
ashoat: I think we need to add:
1. One-time identity prekey
2. One-time notif prekey
3. Signed… | ||||||||||
varunUnsubmitted Done Inline Actionsvarun: question for @jon and @ashoat : should we have separate fields for each prekey or just have a… | ||||||||||
jonAuthorUnsubmitted Done Inline ActionsIf we have to handle them differently, then they should be different. I'm still a little confused on the use case of many prekeys, so I'll defer to @ashoat on this. From my understanding of X3DH, this should be: // Split SessionInitialization into two parts: // GetSessionInitializationInfo: Data needed to start a session with another user // PutSessionInitializationInfo: Data needed for other start a session with you message GetSessionInitializationInfo { string payload = 1; // JSON encoded Identity key + signed PreKey (IK + SPK) string payloadSignature = 2; // ed25519 prekey signature: Sig(IK, Encode(SPK)) optional string socialProof = 3; // signed message used for SIWE (optional) string defaultOpk = 4; // one-time prekey used for all non-notif traffic with user string notifOpk = 4; // one-time prekey used for issuing notifs to user } // Part of ClientRegistrationRequest message PutSessionInitializationInfo { string payload = 1; // JSON encoded Identity key + signed PreKey (IK + SPK) string payloadSignature = 2; // ed25519 prekey signature: Sig(IK, Encode(SPK)) optional string socialProof = 3; // signed message used for SIWE (optional) repeated string onetimePrekeys = 4; // ~10 or more onetime keys. Used to establish new connections. } The need for different "threads" of communication (identity vs notifs) can be achieved by using different onetime prekeys. jon: If we have to handle them differently, then they should be different.
I'm still a little… | ||||||||||
ashoatUnsubmitted Done Inline Actions
ashoat: 1. Signed prekeys need to be separated out of `payload`. Since they are recycled, they will be… | ||||||||||
// RegisterUser | ||||||||||
// Messages sent from a client to Identity Service | ||||||||||
message RegistrationRequest { | ||||||||||
oneof data { | ||||||||||
// First message in PAKE registration + user information | ||||||||||
ClientRegistrationRequest registrationRequest = 1; | ||||||||||
// Final message in PAKE registration | ||||||||||
bytes opaqueCredentialFinalization = 2; | ||||||||||
varunUnsubmitted Done Inline Actionsthis should be opaqueRegistrationUpload for consistency with opaque-ke's terminology varun: this should be `opaqueRegistrationUpload` for consistency with opaque-ke's terminology | ||||||||||
} | ||||||||||
} | ||||||||||
// Messages sent from Identity Service to client | ||||||||||
message RegistrationResponse { | ||||||||||
oneof data { | ||||||||||
// sent to the user upon reception of the PAKE registration attempt | ||||||||||
// (step 2) | ||||||||||
bytes registrationResponse = 1; | ||||||||||
varunUnsubmitted Done Inline Actionsprefix this with opaque? varun: prefix this with opaque? | ||||||||||
// After successful unpacking of user credentials, return token | ||||||||||
string accessToken = 2; | ||||||||||
} | ||||||||||
} | ||||||||||
// UpdateUserPassword | ||||||||||
// Request for updating a user, similar to registration but need a | ||||||||||
// access token to validate user before updating password | ||||||||||
message InitialUpdateUserPasswordRequest { | ||||||||||
// ed25519 key for the given user's device | ||||||||||
string signingPublicKey = 1; | ||||||||||
// Message sent to initiate PAKE registration (step 1) | ||||||||||
bytes opaqueRegistrationRequest = 2; | ||||||||||
string username = 3; | ||||||||||
// Information specific to a user's device needed to open a new channel of | ||||||||||
// communication with this user | ||||||||||
SessionInitializationInfo sessionInitializationInfo = 4; | ||||||||||
// Used to validate user, before attempting to update password | ||||||||||
string accessToken = 5; | ||||||||||
} | ||||||||||
// Do a user registration, but overwrite the existing credentials | ||||||||||
// after validation of user | ||||||||||
message UpdateUserPasswordRequest { | ||||||||||
oneof data { | ||||||||||
InitialUpdateUserPasswordRequest updateRequest = 1; | ||||||||||
bytes clientRegistrationFinalization = 2; | ||||||||||
varunUnsubmitted Done Inline Actionssame feedback as above about keeping consistent with opaque-ke terminology varun: same feedback as above about keeping consistent with opaque-ke terminology | ||||||||||
} | ||||||||||
} | ||||||||||
message UpdateUserPasswordResponse { | ||||||||||
oneof data { | ||||||||||
bytes opaqueRegistrationResponse = 1; | ||||||||||
// After successful unpacking of user credentials, return token | ||||||||||
varunUnsubmitted Done Inline Actionsmaybe emphasize that this is a new token varun: maybe emphasize that this is a new token | ||||||||||
string accessToken = 2; | ||||||||||
} | ||||||||||
} | ||||||||||
// LoginUser | ||||||||||
message OpaqueLoginRequest { | ||||||||||
varunUnsubmitted Done Inline Actionswe're sure that we don't need to send the CredentialFinalization bytes to the server after getting back the CredentialResponse? I know we're not using the session key, but want to make sure the server has properly authenticated the client at this point, and is not relying on some piece of information sent in the third message (CredentialFinalization) of the protocol varun: we're sure that we don't need to send the CredentialFinalization bytes to the server after… | ||||||||||
jonAuthorUnsubmitted Done Inline ActionsI was initially wrong, we still need to finish on the server side. https://docs.rs/opaque-ke/2.0.0/opaque_ke/struct.ServerLogin.html#method.start the ServerLogin::start creates a challenge, which isn't verified until ServerLogin::finish jon: I was initially wrong, we still need to finish on the server side. https://docs.rs/opaque-ke/2. | ||||||||||
string username = 1; | ||||||||||
// ed25519 key for the given user's device | ||||||||||
string signingPublicKey = 2; | ||||||||||
// Message sent to initiate PAKE login (step 1) | ||||||||||
bytes opaqueLoginRequest = 3; | ||||||||||
// Information specific to a user's device needed to open a new channel of | ||||||||||
// communication with this user | ||||||||||
SessionInitializationInfo sessionInitializationInfo = 4; | ||||||||||
} | ||||||||||
message OpaqueLoginResponse { | ||||||||||
// Answer sent to the user upon reception of the PAKE login attempt, | ||||||||||
// containing a sealed envelope with the user's private key (step 2) | ||||||||||
bytes opaqueCredentialResponse = 1; | ||||||||||
string accessToken = 2; | ||||||||||
} | ||||||||||
message WalletLoginRequest { | ||||||||||
// ed25519 key for the given user's device | ||||||||||
string signingPublicKey = 1; | ||||||||||
string siweMessage = 2; | ||||||||||
string siweSignature = 3; | ||||||||||
// Information specific to a user's device needed to open a new channel of | ||||||||||
// communication with this user | ||||||||||
SessionInitializationInfo sessionInitializationInfo = 4; | ||||||||||
} | ||||||||||
message WalletLoginResponse { | ||||||||||
string accessToken = 1; | ||||||||||
} | ||||||||||
// DeleteUser | ||||||||||
message DeleteUserRequest { | ||||||||||
string accessToken = 1; | ||||||||||
} | ||||||||||
// GetUserID | ||||||||||
message GetUserIDRequest { | ||||||||||
enum AuthType { | ||||||||||
PASSWORD = 0; | ||||||||||
WALLET = 1; | ||||||||||
} | ||||||||||
AuthType authType = 1; | ||||||||||
string userInfo = 2; | ||||||||||
} | ||||||||||
message GetUserIDResponse { | ||||||||||
string userID = 1; | ||||||||||
} | ||||||||||
// GenerateNonce | ||||||||||
message GenerateNonceResponse{ | ||||||||||
string nonce = 1; | ||||||||||
} | ||||||||||
// GetSessionInitializationInfo | ||||||||||
message GetSessionInitializationInfoRequest { | ||||||||||
oneof identifier { | ||||||||||
string username = 1; | ||||||||||
string walletAddress = 2; | ||||||||||
} | ||||||||||
} | ||||||||||
message GetSessionInitializationInfoResponse { | ||||||||||
// Map is keyed on devices' public ed25519 key used for signing | ||||||||||
map<string, SessionInitializationInfo> devices = 1; | ||||||||||
} |