Skip to main content

auths_crypto/
ssh.rs

1//! OpenSSH public key parsing for Ed25519 keys.
2
3use ssh_key::PublicKey;
4
5/// Errors from parsing an OpenSSH Ed25519 public key.
6#[derive(Debug, Clone, thiserror::Error, PartialEq, Eq)]
7#[non_exhaustive]
8pub enum SshKeyError {
9    #[error("Malformed or invalid OpenSSH public key: {0}")]
10    InvalidFormat(String),
11
12    #[error("Unsupported key type: expected ssh-ed25519")]
13    UnsupportedKeyType,
14}
15
16impl crate::AuthsErrorInfo for SshKeyError {
17    fn error_code(&self) -> &'static str {
18        match self {
19            Self::InvalidFormat(_) => "AUTHS-E1301",
20            Self::UnsupportedKeyType => "AUTHS-E1302",
21        }
22    }
23
24    fn suggestion(&self) -> Option<&'static str> {
25        match self {
26            Self::InvalidFormat(_) => Some("Check that the public key is a valid OpenSSH format"),
27            Self::UnsupportedKeyType => Some("Only ssh-ed25519 keys are supported"),
28        }
29    }
30}
31
32/// Parse an OpenSSH Ed25519 public key line and return the raw 32-byte public key.
33///
34/// Args:
35/// * `openssh_pub`: A full OpenSSH public key line, e.g. `"ssh-ed25519 AAAA... comment"`.
36///
37/// Usage:
38/// ```ignore
39/// let raw = openssh_pub_to_raw_ed25519("ssh-ed25519 AAAA...")?;
40/// assert_eq!(raw.len(), 32);
41/// ```
42pub fn openssh_pub_to_raw_ed25519(openssh_pub: &str) -> Result<[u8; 32], SshKeyError> {
43    let public_key = PublicKey::from_openssh(openssh_pub)
44        .map_err(|e| SshKeyError::InvalidFormat(e.to_string()))?;
45
46    let ed25519_key = public_key
47        .key_data()
48        .ed25519()
49        .ok_or(SshKeyError::UnsupportedKeyType)?;
50
51    Ok(ed25519_key.0)
52}