diff --git a/services/identity/src/grpc_utils.rs b/services/identity/src/grpc_utils.rs --- a/services/identity/src/grpc_utils.rs +++ b/services/identity/src/grpc_utils.rs @@ -50,28 +50,38 @@ self, signing_public_key: &str, ) -> Result { - let signature_bytes = general_purpose::STANDARD_NO_PAD - .decode(&self.signature) - .map_err(|_| Status::invalid_argument("signature invalid"))?; - - let signature = Signature::from_bytes(&signature_bytes) - .map_err(|_| Status::invalid_argument("signature invalid"))?; - - let public_key_bytes = general_purpose::STANDARD_NO_PAD - .decode(signing_public_key) - .map_err(|_| Status::failed_precondition("malformed key"))?; - - let public_key: PublicKey = PublicKey::from_bytes(&public_key_bytes) - .map_err(|_| Status::failed_precondition("malformed key"))?; - - public_key - .verify(self.nonce.as_bytes(), &signature) - .map_err(|_| Status::permission_denied("verification failed"))?; - + ed25519_verify(signing_public_key, &self.nonce, &self.signature)?; Ok(self.nonce) } } +/// Verifies ed25519-signed message. Returns Ok if the signature is valid. +/// Public key and signature should be base64-encoded strings. +pub fn ed25519_verify( + signing_public_key: &str, + message: &str, + signature: &str, +) -> Result<(), Status> { + let signature_bytes = general_purpose::STANDARD_NO_PAD + .decode(signature) + .map_err(|_| Status::invalid_argument("signature invalid"))?; + + let signature = Signature::from_bytes(&signature_bytes) + .map_err(|_| Status::invalid_argument("signature invalid"))?; + + let public_key_bytes = general_purpose::STANDARD_NO_PAD + .decode(signing_public_key) + .map_err(|_| Status::failed_precondition("malformed key"))?; + + let public_key: PublicKey = PublicKey::from_bytes(&public_key_bytes) + .map_err(|_| Status::failed_precondition("malformed key"))?; + + public_key + .verify(message.as_bytes(), &signature) + .map_err(|_| Status::permission_denied("verification failed"))?; + Ok(()) +} + pub struct DeviceKeysInfo { pub device_info: DeviceRow, pub content_one_time_key: Option, diff --git a/services/identity/src/reserved_users.rs b/services/identity/src/reserved_users.rs --- a/services/identity/src/reserved_users.rs +++ b/services/identity/src/reserved_users.rs @@ -1,7 +1,5 @@ -use base64::{engine::general_purpose, Engine as _}; use chrono::{DateTime, Utc}; use constant_time_eq::constant_time_eq; -use ed25519_dalek::{PublicKey, Signature, Verifier}; use serde::Deserialize; use tonic::Status; @@ -53,28 +51,16 @@ return Err(Status::invalid_argument("message invalid")); } - let signature_bytes = general_purpose::STANDARD_NO_PAD - .decode(keyserver_signature) - .map_err(|_| Status::invalid_argument("signature invalid"))?; - - let signature = Signature::from_bytes(&signature_bytes) - .map_err(|_| Status::invalid_argument("signature invalid"))?; - let public_key_string = CONFIG .keyserver_public_key - .clone() + .as_deref() .ok_or_else(|| Status::failed_precondition("missing key"))?; - let public_key_bytes = general_purpose::STANDARD_NO_PAD - .decode(public_key_string) - .map_err(|_| Status::failed_precondition("malformed key"))?; - - let public_key: PublicKey = PublicKey::from_bytes(&public_key_bytes) - .map_err(|_| Status::failed_precondition("malformed key"))?; - - public_key - .verify(keyserver_message.as_bytes(), &signature) - .map_err(|_| Status::permission_denied("verification failed"))?; + crate::grpc_utils::ed25519_verify( + public_key_string, + keyserver_message, + keyserver_signature, + )?; Ok(deserialized_message) }