99#[ cfg( feature = "ecdsa" ) ]
1010mod ecdsa;
1111mod ed25519;
12- mod openssh;
1312#[ cfg( feature = "alloc" ) ]
1413mod rsa;
1514
@@ -27,10 +26,14 @@ use crate::{
2726 public, Algorithm , CipherAlg , Error , KdfAlg , KdfOptions , Result ,
2827} ;
2928use core:: str:: FromStr ;
29+ use pem_rfc7468:: { self as pem, PemLabel } ;
3030
3131#[ cfg( feature = "alloc" ) ]
3232use alloc:: string:: String ;
3333
34+ /// Line width used by the PEM encoding of OpenSSH private keys
35+ const PEM_LINE_WIDTH : usize = 70 ;
36+
3437/// SSH private key.
3538#[ derive( Clone , Debug ) ]
3639pub struct PrivateKey {
@@ -64,23 +67,25 @@ impl PrivateKey {
6467 /// -----BEGIN OPENSSH PRIVATE KEY-----
6568 /// ```
6669 pub fn from_openssh ( input : impl AsRef < [ u8 ] > ) -> Result < Self > {
67- let encapsulation = openssh:: Encapsulation :: decode ( input. as_ref ( ) ) ?;
68- let mut decoder = base64:: Decoder :: new_wrapped (
69- encapsulation. base64_data ,
70- openssh:: Encapsulation :: LINE_WIDTH ,
71- ) ?;
70+ let pem_decoder = pem:: Decoder :: new_wrapped ( input. as_ref ( ) , PEM_LINE_WIDTH ) ?;
71+
72+ if pem_decoder. type_label ( ) != Self :: TYPE_LABEL {
73+ return Err ( Error :: Pem ) ;
74+ }
75+
76+ let mut base64_decoder = base64:: Decoder :: from ( pem_decoder. into_base64_decoder ( ) ) ;
7277
7378 let mut auth_magic = [ 0u8 ; Self :: AUTH_MAGIC . len ( ) ] ;
74- decoder . decode_into ( & mut auth_magic) ?;
79+ base64_decoder . decode_into ( & mut auth_magic) ?;
7580
7681 if auth_magic != Self :: AUTH_MAGIC {
7782 return Err ( Error :: FormatEncoding ) ;
7883 }
7984
80- let cipher_alg = CipherAlg :: decode ( & mut decoder ) ?;
81- let kdf_alg = KdfAlg :: decode ( & mut decoder ) ?;
82- let kdf_options = KdfOptions :: decode ( & mut decoder ) ?;
83- let nkeys = decoder . decode_u32 ( ) ? as usize ;
85+ let cipher_alg = CipherAlg :: decode ( & mut base64_decoder ) ?;
86+ let kdf_alg = KdfAlg :: decode ( & mut base64_decoder ) ?;
87+ let kdf_options = KdfOptions :: decode ( & mut base64_decoder ) ?;
88+ let nkeys = base64_decoder . decode_u32 ( ) ? as usize ;
8489
8590 // TODO(tarcieri): support more than one key?
8691 if nkeys != 1 {
@@ -89,26 +94,26 @@ impl PrivateKey {
8994
9095 for _ in 0 ..nkeys {
9196 // TODO(tarcieri): validate decoded length
92- let _len = decoder . decode_u32 ( ) ? as usize ;
93- let _pubkey = public:: KeyData :: decode ( & mut decoder ) ?;
97+ let _len = base64_decoder . decode_u32 ( ) ? as usize ;
98+ let _pubkey = public:: KeyData :: decode ( & mut base64_decoder ) ?;
9499 }
95100
96101 // Begin decoding unencrypted list of N private keys
97102 // See OpenSSH PROTOCOL.key § 3
98103 // TODO(tarcieri): validate decoded length
99- let _len = decoder . decode_u32 ( ) ? as usize ;
100- let checkint1 = decoder . decode_u32 ( ) ?;
101- let checkint2 = decoder . decode_u32 ( ) ?;
104+ let _len = base64_decoder . decode_u32 ( ) ? as usize ;
105+ let checkint1 = base64_decoder . decode_u32 ( ) ?;
106+ let checkint2 = base64_decoder . decode_u32 ( ) ?;
102107
103108 if checkint1 != checkint2 {
104109 // TODO(tarcieri): treat this as a cryptographic error?
105110 return Err ( Error :: FormatEncoding ) ;
106111 }
107112
108- let key_data = KeypairData :: decode ( & mut decoder ) ?;
113+ let key_data = KeypairData :: decode ( & mut base64_decoder ) ?;
109114
110115 #[ cfg( feature = "alloc" ) ]
111- let comment = decoder . decode_string ( ) ?;
116+ let comment = base64_decoder . decode_string ( ) ?;
112117
113118 // TODO(tarcieri): parse/validate padding bytes?
114119 Ok ( Self {
@@ -135,6 +140,10 @@ impl FromStr for PrivateKey {
135140 }
136141}
137142
143+ impl PemLabel for PrivateKey {
144+ const TYPE_LABEL : & ' static str = "OPENSSH PRIVATE KEY" ;
145+ }
146+
138147/// Private key data.
139148#[ derive( Clone , Debug ) ]
140149#[ non_exhaustive]
0 commit comments