From b08b5fb36d5312458e3fc1561a5ae20dd9b05b5d Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Fri, 11 Mar 2022 14:11:06 -0700 Subject: [PATCH] ssh-key: add file I/O methods to `PublicKey` --- .github/workflows/ssh-key.yml | 2 +- ssh-key/Cargo.toml | 2 +- ssh-key/README.md | 3 ++- ssh-key/src/public.rs | 20 ++++++++++++++++++++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ssh-key.yml b/.github/workflows/ssh-key.yml index 7b6bb85a6..afb6806b9 100644 --- a/.github/workflows/ssh-key.yml +++ b/.github/workflows/ssh-key.yml @@ -39,7 +39,7 @@ jobs: target: ${{ matrix.target }} override: true - uses: RustCrypto/actions/cargo-hack-install@master - - run: cargo hack build --target ${{ matrix.target }} --feature-powerset --exclude-features std + - run: cargo hack build --target ${{ matrix.target }} --feature-powerset --exclude-features default,std minimal-versions: uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master diff --git a/ssh-key/Cargo.toml b/ssh-key/Cargo.toml index 7b3a37867..ca00511c5 100644 --- a/ssh-key/Cargo.toml +++ b/ssh-key/Cargo.toml @@ -29,7 +29,7 @@ hex-literal = "0.3" tempfile = "3" [features] -default = ["alloc", "ecdsa"] +default = ["ecdsa", "std"] alloc = ["zeroize/alloc"] ecdsa = ["sec1"] std = ["alloc", "base64ct/std"] diff --git a/ssh-key/README.md b/ssh-key/README.md index 0d765ba5a..be3653566 100644 --- a/ssh-key/README.md +++ b/ssh-key/README.md @@ -27,9 +27,10 @@ and `authorized_keys` files. - [x] Parsing `autorized_keys` files - [x] Built-in zeroize support for private keys -#### TODO: +#### TODO - [ ] Encrypted private key support +- [ ] SSH certificate support - [ ] Legacy SSH key (pre-OpenSSH) format support - [ ] Integrations with other RustCrypto crates (e.g. `ecdsa`, `ed25519`, `rsa`) - [ ] FIDO2 key support diff --git a/ssh-key/src/public.rs b/ssh-key/src/public.rs index b1118835c..d03f42aa7 100644 --- a/ssh-key/src/public.rs +++ b/ssh-key/src/public.rs @@ -29,6 +29,9 @@ use alloc::{ string::{String, ToString}, }; +#[cfg(feature = "std")] +use std::{fs, path::Path}; + /// SSH public key. #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct PublicKey { @@ -104,6 +107,23 @@ impl PublicKey { Ok(String::from_utf8(buf)?) } + /// Read public key from an OpenSSH-formatted PEM file. + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + pub fn read_openssh_file(path: &Path) -> Result { + let input = fs::read_to_string(path)?; + Self::from_openssh(&*input) + } + + /// Write public key as an OpenSSH-formatted PEM file. + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + pub fn write_openssh_file(&self, path: &Path) -> Result<()> { + let encoded = self.to_openssh()?; + fs::write(path, encoded.as_bytes())?; + Ok(()) + } + /// Get the digital signature [`Algorithm`] used by this key. pub fn algorithm(&self) -> Algorithm { self.key_data.algorithm()