Skip to content

Commit 957d3b5

Browse files
authored
Use Traits (#378)
* Added From + TryFrom Traits * Added Support for AsRef<Path> + Read + Write * PublicKey Changes + Formatting Fixes * io Traits for PublicKey + PrivateKey
1 parent 921f3c8 commit 957d3b5

6 files changed

Lines changed: 71 additions & 9 deletions

File tree

ssh-key/src/dot_ssh.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,12 @@ impl DotSsh {
7272

7373
/// Write a private key into `~/.ssh`.
7474
pub fn write_private_key(&self, filename: impl AsRef<Path>, key: &PrivateKey) -> Result<()> {
75-
key.write_openssh_file(&self.path.join(filename), Default::default())
75+
key.write_openssh_file(self.path.join(filename), Default::default())
7676
}
7777

7878
/// Write a public key into `~/.ssh`.
7979
pub fn write_public_key(&self, filename: impl AsRef<Path>, key: &PublicKey) -> Result<()> {
80-
key.write_openssh_file(&self.path.join(filename))
80+
key.write_openssh_file(self.path.join(filename))
8181
}
8282
}
8383

@@ -100,7 +100,7 @@ impl Iterator for PrivateKeysIter {
100100
loop {
101101
let entry = self.read_dir.next()?.ok()?;
102102

103-
if let Ok(key) = PrivateKey::read_openssh_file(&entry.path()) {
103+
if let Ok(key) = PrivateKey::read_openssh_file(entry.path()) {
104104
return Some(key);
105105
}
106106
}
@@ -119,7 +119,7 @@ impl Iterator for PublicKeysIter {
119119
loop {
120120
let entry = self.read_dir.next()?.ok()?;
121121

122-
if let Ok(key) = PublicKey::read_openssh_file(&entry.path()) {
122+
if let Ok(key) = PublicKey::read_openssh_file(entry.path()) {
123123
return Some(key);
124124
}
125125
}

ssh-key/src/private.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,11 @@ use rand_core::CryptoRng;
163163
#[cfg(feature = "std")]
164164
use std::{fs, path::Path};
165165

166+
#[cfg(feature = "std")]
167+
use std::io::{self, Read, Write};
168+
166169
#[cfg(all(unix, feature = "std"))]
167-
use std::{io::Write, os::unix::fs::OpenOptionsExt};
170+
use std::os::unix::fs::OpenOptionsExt;
168171

169172
/// Error message for infallible conversions (used by `expect`)
170173
const CONVERSION_ERROR_MSG: &str = "SSH private key conversion error";
@@ -343,15 +346,34 @@ impl PrivateKey {
343346

344347
/// Read private key from an OpenSSH-formatted PEM file.
345348
#[cfg(feature = "std")]
346-
pub fn read_openssh_file(path: &Path) -> Result<Self> {
349+
pub fn read_openssh<R: Read>(reader: &mut R) -> Result<Self> {
350+
let pem = Zeroizing::new(io::read_to_string(reader)?);
351+
Self::from_openssh(&*pem)
352+
}
353+
354+
/// Read private key from an OpenSSH-formatted PEM file.
355+
#[cfg(feature = "std")]
356+
pub fn read_openssh_file<P: AsRef<Path>>(path: P) -> Result<Self> {
347357
// TODO(tarcieri): verify file permissions match `UNIX_FILE_PERMISSIONS`
348358
let pem = Zeroizing::new(fs::read_to_string(path)?);
349359
Self::from_openssh(&*pem)
350360
}
351361

352362
/// Write private key as an OpenSSH-formatted PEM file.
353363
#[cfg(feature = "std")]
354-
pub fn write_openssh_file(&self, path: &Path, line_ending: LineEnding) -> Result<()> {
364+
pub fn write_openssh<W: Write>(&self, writer: &mut W, line_ending: LineEnding) -> Result<()> {
365+
let pem = self.to_openssh(line_ending)?;
366+
writer.write_all(pem.as_bytes())?;
367+
Ok(())
368+
}
369+
370+
/// Write private key as an OpenSSH-formatted PEM file.
371+
#[cfg(feature = "std")]
372+
pub fn write_openssh_file<P: AsRef<Path>>(
373+
&self,
374+
path: P,
375+
line_ending: LineEnding,
376+
) -> Result<()> {
355377
let pem = self.to_openssh(line_ending)?;
356378

357379
#[cfg(not(unix))]

ssh-key/src/private/dsa.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ impl PartialEq for DsaPrivateKey {
6565
}
6666
}
6767

68+
impl TryFrom<Mpint> for DsaPrivateKey {
69+
type Error = Error;
70+
71+
fn try_from(x: Mpint) -> Result<Self> {
72+
Self::new(x)
73+
}
74+
}
75+
6876
impl Decode for DsaPrivateKey {
6977
type Error = Error;
7078

ssh-key/src/private/ecdsa.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ impl<const SIZE: usize> Encode for EcdsaPrivateKey<SIZE> {
8888
}
8989
}
9090

91+
impl<const SIZE: usize> From<[u8; SIZE]> for EcdsaPrivateKey<SIZE> {
92+
fn from(bytes: [u8; SIZE]) -> Self {
93+
Self { bytes }
94+
}
95+
}
96+
9197
impl<const SIZE: usize> AsRef<[u8; SIZE]> for EcdsaPrivateKey<SIZE> {
9298
fn as_ref(&self) -> &[u8; SIZE] {
9399
&self.bytes

ssh-key/src/private/opaque.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ impl OpaqueKeypair {
7777
}
7878
}
7979

80+
impl From<Vec<u8>> for OpaquePrivateKeyBytes {
81+
fn from(bytes: Vec<u8>) -> Self {
82+
Self(bytes)
83+
}
84+
}
85+
8086
impl Decode for OpaquePrivateKeyBytes {
8187
type Error = Error;
8288

ssh-key/src/public.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ use serde::{Deserialize, Serialize, de, ser};
5050
#[cfg(feature = "std")]
5151
use std::{fs, path::Path};
5252

53+
#[cfg(feature = "std")]
54+
use std::io::{self, Read, Write};
55+
5356
#[cfg(doc)]
5457
use crate::PrivateKey;
5558

@@ -237,14 +240,31 @@ impl PublicKey {
237240

238241
/// Read public key from an OpenSSH-formatted file.
239242
#[cfg(feature = "std")]
240-
pub fn read_openssh_file(path: &Path) -> Result<Self> {
243+
pub fn read_openssh<R: Read>(reader: &mut R) -> Result<Self> {
244+
let input = io::read_to_string(reader)?;
245+
Self::from_openssh(&input)
246+
}
247+
248+
/// Read public key from an OpenSSH-formatted file.
249+
#[cfg(feature = "std")]
250+
pub fn read_openssh_file<P: AsRef<Path>>(path: P) -> Result<Self> {
241251
let input = fs::read_to_string(path)?;
242252
Self::from_openssh(&input)
243253
}
244254

245255
/// Write public key as an OpenSSH-formatted file.
246256
#[cfg(feature = "std")]
247-
pub fn write_openssh_file(&self, path: &Path) -> Result<()> {
257+
pub fn write_openssh<W: Write>(&self, writer: &mut W) -> Result<()> {
258+
let mut encoded = self.to_openssh()?;
259+
encoded.push('\n'); // TODO(tarcieri): OS-specific line endings?
260+
261+
writer.write_all(encoded.as_bytes())?;
262+
Ok(())
263+
}
264+
265+
/// Write public key as an OpenSSH-formatted file.
266+
#[cfg(feature = "std")]
267+
pub fn write_openssh_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
248268
let mut encoded = self.to_openssh()?;
249269
encoded.push('\n'); // TODO(tarcieri): OS-specific line endings?
250270

0 commit comments

Comments
 (0)