revert(auth): remove RSA support from authentication and related components
This commit is contained in:
@@ -203,7 +203,6 @@ pub mod grpc {
|
||||
|
||||
/// [`Bi`] adapter backed by a tonic gRPC bidirectional stream.
|
||||
///
|
||||
|
||||
/// Tonic receive errors are logged and treated as stream closure (`None`).
|
||||
/// The receive converter is only invoked for successful inbound transport
|
||||
/// items.
|
||||
|
||||
@@ -20,7 +20,7 @@ impl Display for ArbiterUrl {
|
||||
"{ARBITER_URL_SCHEME}://{}:{}?{CERT_QUERY_KEY}={}",
|
||||
self.host,
|
||||
self.port,
|
||||
BASE64_URL_SAFE.encode(self.ca_cert.to_vec())
|
||||
BASE64_URL_SAFE.encode(&self.ca_cert)
|
||||
);
|
||||
if let Some(token) = &self.bootstrap_token {
|
||||
base.push_str(&format!("&{BOOTSTRAP_TOKEN_QUERY_KEY}={}", token));
|
||||
|
||||
@@ -43,9 +43,6 @@ restructed = "0.2.2"
|
||||
strum = { version = "0.27.2", features = ["derive"] }
|
||||
pem = "3.0.6"
|
||||
k256.workspace = true
|
||||
rsa.workspace = true
|
||||
sha2.workspace = true
|
||||
spki.workspace = true
|
||||
alloy.workspace = true
|
||||
arbiter-tokens-registry.path = "../arbiter-tokens-registry"
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ use tracing::error;
|
||||
|
||||
use crate::actors::user_agent::{
|
||||
UserAgentConnection,
|
||||
auth::state::{AuthContext, AuthPublicKey, AuthStateMachine}, session::UserAgentSession,
|
||||
auth::state::{AuthContext, AuthPublicKey, AuthStateMachine},
|
||||
session::UserAgentSession,
|
||||
};
|
||||
|
||||
#[derive(thiserror::Error, Debug, PartialEq)]
|
||||
@@ -51,12 +52,6 @@ fn parse_pubkey(key_type: ProtoKeyType, pubkey: Vec<u8>) -> Result<AuthPublicKey
|
||||
.map_err(|_| Error::InvalidAuthPubkeyEncoding)?;
|
||||
Ok(AuthPublicKey::EcdsaSecp256k1(key))
|
||||
}
|
||||
ProtoKeyType::Rsa => {
|
||||
use rsa::pkcs8::DecodePublicKey as _;
|
||||
let key = rsa::RsaPublicKey::from_public_key_der(&pubkey)
|
||||
.map_err(|_| Error::InvalidAuthPubkeyEncoding)?;
|
||||
Ok(AuthPublicKey::Rsa(key))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +126,9 @@ pub async fn authenticate(props: &mut UserAgentConnection) -> Result<AuthPublicK
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn authenticate_and_create(mut props: UserAgentConnection) -> Result<UserAgentSession, Error> {
|
||||
pub async fn authenticate_and_create(
|
||||
mut props: UserAgentConnection,
|
||||
) -> Result<UserAgentSession, Error> {
|
||||
let _key = authenticate(&mut props).await?;
|
||||
let session = UserAgentSession::new(props);
|
||||
Ok(session)
|
||||
|
||||
@@ -11,30 +11,22 @@ use crate::{
|
||||
db::{models::KeyType, schema},
|
||||
};
|
||||
|
||||
/// Abstraction over Ed25519 / ECDSA-secp256k1 / RSA public keys used during the auth handshake.
|
||||
/// Abstraction over Ed25519 / ECDSA-secp256k1 public keys used during the auth handshake.
|
||||
#[derive(Clone)]
|
||||
pub enum AuthPublicKey {
|
||||
Ed25519(ed25519_dalek::VerifyingKey),
|
||||
/// Compressed SEC1 public key; signature bytes are raw 64-byte (r||s).
|
||||
EcdsaSecp256k1(k256::ecdsa::VerifyingKey),
|
||||
/// RSA-2048+ public key; signature bytes are PSS+SHA-256.
|
||||
Rsa(rsa::RsaPublicKey),
|
||||
}
|
||||
|
||||
impl AuthPublicKey {
|
||||
/// Canonical bytes stored in DB and echoed back in the challenge.
|
||||
/// Ed25519: raw 32 bytes. ECDSA: SEC1 compressed 33 bytes. RSA: DER-encoded SPKI.
|
||||
/// Ed25519: raw 32 bytes. ECDSA: SEC1 compressed 33 bytes.
|
||||
pub fn to_stored_bytes(&self) -> Vec<u8> {
|
||||
match self {
|
||||
AuthPublicKey::Ed25519(k) => k.to_bytes().to_vec(),
|
||||
// SEC1 compressed (33 bytes) is the natural compact format for secp256k1
|
||||
AuthPublicKey::EcdsaSecp256k1(k) => k.to_encoded_point(true).as_bytes().to_vec(),
|
||||
AuthPublicKey::Rsa(k) => {
|
||||
use rsa::pkcs8::EncodePublicKey as _;
|
||||
k.to_public_key_der()
|
||||
.expect("rsa SPKI encoding is infallible")
|
||||
.to_vec()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +34,6 @@ impl AuthPublicKey {
|
||||
match self {
|
||||
AuthPublicKey::Ed25519(_) => KeyType::Ed25519,
|
||||
AuthPublicKey::EcdsaSecp256k1(_) => KeyType::EcdsaSecp256k1,
|
||||
AuthPublicKey::Rsa(_) => KeyType::Rsa,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,15 +161,6 @@ impl AuthStateMachineContext for AuthContext<'_> {
|
||||
})?;
|
||||
vk.verify(&formatted, &sig).is_ok()
|
||||
}
|
||||
AuthPublicKey::Rsa(pk) => {
|
||||
use rsa::signature::Verifier as _;
|
||||
let verifying_key = rsa::pss::VerifyingKey::<sha2::Sha256>::new(pk.clone());
|
||||
let sig = rsa::pss::Signature::try_from(solution.as_slice()).map_err(|_| {
|
||||
error!(?solution, "Invalid RSA signature bytes");
|
||||
Error::InvalidChallengeSolution
|
||||
})?;
|
||||
verifying_key.verify(&formatted, &sig).is_ok()
|
||||
}
|
||||
};
|
||||
|
||||
Ok(valid)
|
||||
@@ -284,13 +266,6 @@ impl AuthStateMachineContext for AuthContext<'_> {
|
||||
.expect("ecdsa key was already validated in parse_auth_event"),
|
||||
)
|
||||
}
|
||||
crate::db::models::KeyType::Rsa => {
|
||||
use rsa::pkcs8::DecodePublicKey as _;
|
||||
AuthPublicKey::Rsa(
|
||||
rsa::RsaPublicKey::from_public_key_der(&bytes)
|
||||
.expect("rsa key was already validated in parse_auth_event"),
|
||||
)
|
||||
}
|
||||
};
|
||||
Ok(rebuilt)
|
||||
}
|
||||
|
||||
@@ -81,7 +81,6 @@ pub mod types {
|
||||
pub enum KeyType {
|
||||
Ed25519 = 1,
|
||||
EcdsaSecp256k1 = 2,
|
||||
Rsa = 3,
|
||||
}
|
||||
|
||||
impl ToSql<Integer, Sqlite> for KeyType {
|
||||
@@ -104,7 +103,6 @@ pub mod types {
|
||||
match bytes.read_long() {
|
||||
1 => Ok(KeyType::Ed25519),
|
||||
2 => Ok(KeyType::EcdsaSecp256k1),
|
||||
3 => Ok(KeyType::Rsa),
|
||||
other => Err(format!("Unknown KeyType discriminant: {other}").into()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,6 @@ ed25519-dalek.workspace = true
|
||||
smlang.workspace = true
|
||||
x25519-dalek.workspace = true
|
||||
k256.workspace = true
|
||||
rsa.workspace = true
|
||||
sha2.workspace = true
|
||||
spki.workspace = true
|
||||
rand.workspace = true
|
||||
thiserror.workspace = true
|
||||
tokio-stream.workspace = true
|
||||
|
||||
@@ -16,10 +16,8 @@ use tracing::{error, info};
|
||||
/// Signing key variants supported by the user-agent auth protocol.
|
||||
pub enum SigningKeyEnum {
|
||||
Ed25519(ed25519_dalek::SigningKey),
|
||||
/// secp256k1 ECDSA; public key is sent as DER SPKI; signature is raw 64-byte (r||s).
|
||||
/// secp256k1 ECDSA; public key is sent as SEC1 compressed 33 bytes; signature is raw 64-byte (r||s).
|
||||
EcdsaSecp256k1(k256::ecdsa::SigningKey),
|
||||
/// RSA; public key is sent as DER SPKI; signature is PSS+SHA-256.
|
||||
Rsa(rsa::RsaPrivateKey),
|
||||
}
|
||||
|
||||
impl SigningKeyEnum {
|
||||
@@ -31,13 +29,6 @@ impl SigningKeyEnum {
|
||||
SigningKeyEnum::EcdsaSecp256k1(k) => {
|
||||
k.verifying_key().to_encoded_point(true).as_bytes().to_vec()
|
||||
}
|
||||
SigningKeyEnum::Rsa(k) => {
|
||||
use rsa::pkcs8::EncodePublicKey as _;
|
||||
k.to_public_key()
|
||||
.to_public_key_der()
|
||||
.expect("rsa SPKI encoding is infallible")
|
||||
.to_vec()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +37,6 @@ impl SigningKeyEnum {
|
||||
match self {
|
||||
SigningKeyEnum::Ed25519(_) => ProtoKeyType::Ed25519,
|
||||
SigningKeyEnum::EcdsaSecp256k1(_) => ProtoKeyType::EcdsaSecp256k1,
|
||||
SigningKeyEnum::Rsa(_) => ProtoKeyType::Rsa,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,15 +52,6 @@ impl SigningKeyEnum {
|
||||
let sig: k256::ecdsa::Signature = k.sign(msg);
|
||||
sig.to_bytes().to_vec()
|
||||
}
|
||||
SigningKeyEnum::Rsa(k) => {
|
||||
use rsa::signature::RandomizedSigner as _;
|
||||
let signing_key = rsa::pss::BlindedSigningKey::<sha2::Sha256>::new(k.clone());
|
||||
// Use rand_core OsRng from the rsa crate's re-exported rand_core (0.6.x),
|
||||
// which is the version rsa's signature API expects.
|
||||
let sig = signing_key.sign_with_rng(&mut rsa::rand_core::OsRng, msg);
|
||||
use rsa::signature::SignatureEncoding as _;
|
||||
sig.to_vec()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user