Skip to main content

auths_sdk/workflows/
git_integration.rs

1//! Git SSH key encoding utilities.
2
3use ssh_key::PublicKey as SshPublicKey;
4use ssh_key::public::Ed25519PublicKey;
5use thiserror::Error;
6
7/// Errors from SSH key encoding operations.
8#[derive(Debug, Error)]
9pub enum GitIntegrationError {
10    /// Raw public key bytes have an unexpected length.
11    #[error("invalid public key length: expected 32 (Ed25519), 33/65 (P-256), got {0}")]
12    InvalidKeyLength(usize),
13    /// SSH key encoding failed.
14    #[error("failed to encode SSH public key: {0}")]
15    SshKeyEncoding(String),
16}
17
18/// Convert a device public key to an OpenSSH public key string.
19///
20/// Args:
21/// * `key`: Device public key carrying its curve type.
22///
23/// Usage:
24/// ```ignore
25/// let openssh = public_key_to_ssh(&device_pk)?;
26/// ```
27pub fn public_key_to_ssh(
28    key: &auths_verifier::DevicePublicKey,
29) -> Result<String, GitIntegrationError> {
30    match key.curve() {
31        auths_crypto::CurveType::Ed25519 => {
32            let signing_pk = Ed25519PublicKey::try_from(key.as_bytes())
33                .map_err(|e| GitIntegrationError::SshKeyEncoding(e.to_string()))?;
34            let ssh_pk = SshPublicKey::from(signing_pk);
35            ssh_pk
36                .to_openssh()
37                .map_err(|e| GitIntegrationError::SshKeyEncoding(e.to_string()))
38        }
39        auths_crypto::CurveType::P256 => {
40            use ssh_key::public::{EcdsaPublicKey, KeyData};
41
42            let uncompressed_bytes = if key.len() == 33 {
43                use p256::ecdsa::VerifyingKey;
44                let vk = VerifyingKey::from_sec1_bytes(key.as_bytes()).map_err(|e| {
45                    GitIntegrationError::SshKeyEncoding(format!("P-256 key parse: {e}"))
46                })?;
47                vk.to_encoded_point(false).as_bytes().to_vec()
48            } else {
49                key.as_bytes().to_vec()
50            };
51
52            let ecdsa_pk = EcdsaPublicKey::from_sec1_bytes(&uncompressed_bytes)
53                .map_err(|e| GitIntegrationError::SshKeyEncoding(format!("ECDSA SSH key: {e}")))?;
54
55            let ssh_pk = SshPublicKey::from(KeyData::Ecdsa(ecdsa_pk));
56            ssh_pk
57                .to_openssh()
58                .map_err(|e| GitIntegrationError::SshKeyEncoding(e.to_string()))
59        }
60    }
61}