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