1use pkcs8::EncodePrivateKey;
2use rsa::RsaPrivateKey;
3use ssh_key::{PrivateKey, private::RsaKeypair};
4
5use crate::error::SshKeyExportError;
6
7fn convert_rsa_keypair(keypair: &RsaKeypair) -> Result<RsaPrivateKey, ssh_key::Error> {
11 Ok(rsa::RsaPrivateKey::from_components(
12 rsa::BigUint::try_from(&keypair.public.n)?,
13 rsa::BigUint::try_from(&keypair.public.e)?,
14 rsa::BigUint::try_from(&keypair.private.d)?,
15 vec![
16 rsa::BigUint::try_from(&keypair.private.p)?,
17 rsa::BigUint::try_from(&keypair.private.q)?,
18 ],
19 )?)
20}
21
22pub fn export_pkcs8_der_key(private_key: &str) -> Result<Vec<u8>, SshKeyExportError> {
27 let private_key =
29 PrivateKey::from_openssh(private_key).map_err(|_| SshKeyExportError::KeyConversion)?;
30
31 match private_key.key_data() {
32 ssh_key::private::KeypairData::Ed25519(keypair) => {
33 let sk: ed25519_dalek::SigningKey = keypair
34 .try_into()
35 .map_err(|_| SshKeyExportError::KeyConversion)?;
36
37 Ok(sk
38 .to_pkcs8_der()
39 .map_err(|_| SshKeyExportError::KeyConversion)?
40 .as_bytes()
41 .to_vec())
42 }
43 ssh_key::private::KeypairData::Rsa(keypair) => Ok(convert_rsa_keypair(keypair)
44 .map_err(|_| SshKeyExportError::KeyConversion)?
45 .to_pkcs8_der()
46 .map_err(|_| SshKeyExportError::KeyConversion)?
47 .as_bytes()
48 .to_vec()),
49 _ => Err(SshKeyExportError::KeyConversion),
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56 use crate::import::{import_key, import_pkcs8_der_key};
57
58 #[test]
59 fn export_ed25519_openssh_unencrypted() {
60 let private_key = include_str!("../resources/import/ed25519_openssh_unencrypted");
61 let result = import_key(private_key.to_string(), Some("".to_string())).unwrap();
62
63 let exported_key = export_pkcs8_der_key(&result.private_key).unwrap();
64 let expected_pkcs8_der: Vec<u8> = vec![
65 48, 81, 2, 1, 1, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 139, 118, 81, 75, 32, 150,
66 196, 136, 90, 63, 127, 68, 78, 117, 115, 13, 100, 3, 199, 24, 243, 97, 189, 182, 223,
67 181, 163, 236, 81, 145, 35, 104, 129, 33, 0, 50, 66, 141, 182, 77, 117, 205, 170, 241,
68 126, 47, 200, 212, 73, 35, 94, 187, 197, 42, 174, 192, 227, 189, 255, 105, 192, 140, 3,
69 11, 211, 11, 234,
70 ];
71 assert_eq!(exported_key, expected_pkcs8_der);
72
73 let reimported_key = import_pkcs8_der_key(&exported_key).unwrap();
75 assert_eq!(
76 reimported_key.public_key,
77 result.public_key.strip_suffix(" testkey").unwrap()
78 );
79 }
80
81 #[test]
82 fn export_rsa_openssh_unencrypted() {
83 let private_key = include_str!("../resources/import/rsa_openssh_unencrypted");
84 let result = import_key(private_key.to_string(), Some("".to_string())).unwrap();
85
86 let exported_key = export_pkcs8_der_key(&result.private_key).unwrap();
87
88 let reimported_key = import_pkcs8_der_key(&exported_key).unwrap();
90 assert_eq!(
91 reimported_key.public_key,
92 result.public_key.strip_suffix(" testkey").unwrap()
93 );
94 }
95}