Skip to content

Commit

Permalink
Decode RSA keys in PKCS#1
Browse files Browse the repository at this point in the history
  • Loading branch information
honzasp committed Aug 7, 2022
1 parent 1f33690 commit 3dc7540
Show file tree
Hide file tree
Showing 17 changed files with 586 additions and 44 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ poly1305 = "0.7"
rand = {version = "0.8", features = ["getrandom"]}
rand_0_7 = {version = "0.7", package = "rand"} # because of x25519-dalek
rand_chacha = "0.3"
rsa = {version = "0.6", default-features = false}
rsa = {version = "0.6"}
sha-1 = {version = "0.10", default-features = false}
sha2 = "0.10"
thiserror = "1.0"
Expand Down
3 changes: 2 additions & 1 deletion src/client/client_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,8 @@ pub struct AcceptTunnel {

/// The address on the SSH server that the remote peer has connected to.
///
/// This should be equal to the address that you have passed to [`Client::bind_tunnel()`].
/// This should be equal to the address that you have passed to
/// [`Client::bind_tunnel()`][super::Client::bind_tunnel()].
pub connected_addr: (String, u16),

/// The address of the remote peer.
Expand Down
3 changes: 3 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::fmt;
use rsa::pkcs1;
use crate::codes::{disconnect, open};

/// Result type for our [`Error`].
Expand Down Expand Up @@ -68,6 +69,8 @@ pub enum Error {
ClientDisconnected,
#[error("could not parse PEM file")]
Pem(pem::PemError),
#[error("could not parse file in PKCS#1 format")]
Pkcs1(pkcs1::Error),
#[error("unexpected PEM tag {0:?}, expected {1:?}")]
BadPemTag(String, String),
#[error("bad passphrase when decoding key")]
Expand Down
6 changes: 5 additions & 1 deletion src/keys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ pub use self::openssh::{
decode_openssh_pem_keypair, decode_openssh_binary_keypair,
decode_openssh_pem_keypair_nopass, decode_openssh_binary_keypair_nopass,
};
pub use self::pkcs1::{
decode_pkcs1_pem_privkey_nopass, decode_pkcs1_der_privkey,
decode_pkcs1_pem_pubkey, decode_pkcs1_der_pubkey,
};

mod openssh;
mod pkcs1;

fn decode_pem(pem_data: &[u8], expected_tag: &'static str) -> Result<Vec<u8>> {
let pem = pem::parse(pem_data).map_err(Error::Pem)?;
Expand All @@ -16,4 +21,3 @@ fn decode_pem(pem_data: &[u8], expected_tag: &'static str) -> Result<Vec<u8>> {
}
Ok(pem.contents)
}

44 changes: 44 additions & 0 deletions src/keys/pkcs1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use rsa::pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey};
use crate::error::{Result, Error};
use crate::pubkey::{RsaPrivkey, RsaPubkey};

/// Decode a private RSA key from PKCS#1 PEM format without decryption.
///
/// Files in this format start with `-----BEGIN RSA PRIVATE KEY-----`, followed by base64-encoded
/// DER data (see [`decode_pkcs1_der_privkey()`]).
///
/// Encrypted PKCS#1 keys have a PEM header such as `Proc-Type: 4,ENCRYPTED` after the `-----BEGIN
/// RSA PRIVATE KEY-----` header. At this moment, we do not support such keys.
pub fn decode_pkcs1_pem_privkey_nopass(pem_data: &str) -> Result<RsaPrivkey> {
let privkey = rsa::RsaPrivateKey::from_pkcs1_pem(pem_data).map_err(Error::Pkcs1)?;
Ok(RsaPrivkey { privkey })
}

/// Decode a private RSA key from PKCS#1 binary DER format.
///
/// You will rarely encounter the binary DER format in the wild. If you key starts with `-----BEGIN
/// RSA PRIVATE KEY-----`, the DER data is wrapped in PEM format (see
/// [`decode_pkcs1_pem_privkey_nopass()`]).
pub fn decode_pkcs1_der_privkey(der_data: &[u8]) -> Result<RsaPrivkey> {
let privkey = rsa::RsaPrivateKey::from_pkcs1_der(der_data).map_err(Error::Pkcs1)?;
Ok(RsaPrivkey { privkey })
}

/// Decode a public RSA key from PKCS#1 PEM format.
///
/// Files in this format start with `-----BEGIN RSA PUBLIC KEY-----`, followed by base64-encoded
/// DER data (see [`decode_pkcs1_der_pubkey()`]).
pub fn decode_pkcs1_pem_pubkey(pem_data: &str) -> Result<RsaPubkey> {
let pubkey = rsa::RsaPublicKey::from_pkcs1_pem(pem_data).map_err(Error::Pkcs1)?;
Ok(RsaPubkey { pubkey })
}

/// Decode a public RSA key from PKCS#1 binary DER format.
///
/// You will rarely encounter the binary DER format in the wild. If you key starts with `-----BEGIN
/// RSA PUBLIC KEY-----`, the DER data is wrapped in PEM format (see
/// [`decode_pkcs1_pem_pubkey()`]).
pub fn decode_pkcs1_der_pubkey(der_data: &[u8]) -> Result<RsaPubkey> {
let pubkey = rsa::RsaPublicKey::from_pkcs1_der(der_data).map_err(Error::Pkcs1)?;
Ok(RsaPubkey { pubkey })
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub use ecdsa::elliptic_curve;
pub use ed25519_dalek;
pub use p256;
pub use p384;
pub use pem;
pub use rsa;

pub mod cipher;
Expand Down
30 changes: 30 additions & 0 deletions tests/keys/encrypted_pkcs1
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CTR,E235B936ECDB5ED10F40C646EFBFCABB

Yi4qwFGtN4YUIyvk7ZoGVE0jzNR/pZAO4XwEjNG1/wlU0xI2s6ywAcJvW0+MJyWw
JRIHXCT2QYjlRqC3HFo00lE0PLybLVE3HnKhEz1KFyLWrnTlQnUJ3c/eOzM1eygi
1oybeeUKQlJWo2y501cObGy86x2r0h/ZKtKyA2oRpvj6adiAEDDHi0mIBxgqi+Ty
1vdLUbIiV2vAugG6RcgcBirTx/RJ2qeg5JpHbGHjogqH2Ix+oGRnYM3Kgqwax3y1
TJ+1tiSH1WB1yir30ZvibEqRifZ1FrJpRdfsHR0oChK3AgL1ckn26FXQxmI4hc7o
cchakWspwEvCSaizZgN14oknpOheHUkFp1DBl2YXQoI/GD6cFiF0U9RdpzUuIC2S
mOpzqZg0nfaNuXTpgfg2sdqdci7Pqe5iRESdTtTyE8mQ8B+2luJ6UlAvwmlIprUs
afSiYmoG5p0z2kHslhkyUqKi9noKjNp3Xz66KCi0XBKWR5t0fK8gFfD9gqSw8dnj
1xy8e8gGwGbR8BX1nGX4W+bNPOv0Xqt5GFWkCFOq7efpYtjylmWIe3JVr/91cTDj
O/JhoOEQujqSFI1ArilWorSUMs0y3EFY1YNkT3mwc/Vg2iSM9eALvpEsBa1Dnqoc
QafCu0DlJw0SaT5os8YuNcG+L3PWx3eCWGE3ZpH8WEtwbnS4IiOz5yBwbvAXDXvR
DOe9ZQNYrxoKHOUHPUsuhyducoYrgIv8RpQ5fC5cGV3lC0SsW9VfNe7aA6U1JqiT
whhlUA2INVdF6UGNzm5Ofv06bAXMDJ8tnGFRnmqNDUlhvEnBmWX5NxtfoctF2Cww
IAVSN/cIpR4XAdZybA9kaYxjIpaz2aXnGNhp3Rtxc9jy5mx5JWki6mXXQaZqPJps
IqywZe4ykgD1uqo7/UjHSFZA1CFQOWVQmP4qKpaTI320kFonSZ1PLabURCUlLax1
Mgy/OyWrAOEu+sQOc6GKEFLnXK47XR72fGXjR1WN8cOhbSfz5XqwRj6qUljgYhUu
g7kHfd89Gbn5eyyxP8Fb6bE3oTbn8EV78uEqkaag6KsC4yMXaNldushowosbjcZ2
rnHKlSI0YJD4vxCaQsamlTRSjPCcmZcCbzo0EEP6Lyo1jFkxHtaCnKtVNoRIQyfP
o5JZpZNQL0+PHN7SiY2Tn41axZsmvJ3kms6CUnwDhve1BakYFpuo1zDef4Ugu4Bw
0E40wPsZZqjMsqazIRLRYB3+o7hlPYhtRJw8Jl6tymcrb1cZ8rvfZ2RJPmb91Js/
9tfwKmA9yc5ScCSfi7aVa3b/ROu9hOCeXtWGTd0fFKCobh/Fz5eOAvXKLM1aTa8m
VPr22x2q4NzWaGjYAE8kDQ3M7cwI2EgCoePNkqEwiuyVHIYrXY+kIJYwalxvAcdY
NhH7DZ9eRPoLX7Xfcetc0vmHju6c2n5MtPXhEK/EwnGVVzGYe3K/uX5d6pGwuNgP
2gG6s0nvDfzcJBZcGPtbsF0kufEWWsDU5udC/96uVmRas7C+bWo/pi9b7T05yvvd
hIjVvS7SgXC2XhG3PtjHrgspN/H/lNQzGoBT8XuADVzPepbC7dRR
-----END RSA PRIVATE KEY-----
9 changes: 9 additions & 0 deletions tests/keys/encrypted_pkcs1.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxEnHFfey5WPgemz3T2qn
alJU59OpzEJKAB8yFr9gur/4axy0Nqptp++Hs4X4No1VZWqqv+frNingB6w8p/x/
nX9oSlkdzbY38AiqRXQn/SfIaW8wyZvMZHBgcscu7KQ1FVpVVLbNmvNjQINJGQVs
w177RmoS3lV9nEFECDEBYSeiASIZtZ2SxPNqXeiRIHMXA7G5QDUVbMnMc6VMVi2F
o/yYfMAK+02zmOzCnEsaIKLAV8GHbQislRrPps4sZcv4hTHX005IAAcIKfFl9YZT
28IQbHcl69UwNQLlhBGQwlRMnfPkttvUpCMEp619NcTvlCSZfd0PH8uOPOcr5R1s
4QIDAQAB
-----END PUBLIC KEY-----
Loading

0 comments on commit 3dc7540

Please sign in to comment.