@@ -39,14 +39,41 @@ impl BasicIdentity {
3939 /// Create a `BasicIdentity` from reading a PEM File from a Reader.
4040 #[ cfg( feature = "pem" ) ]
4141 pub fn from_pem < R : std:: io:: Read > ( pem_reader : R ) -> Result < Self , PemError > {
42- use der:: { Decode , PemReader } ;
42+ use der:: { asn1 :: OctetString , Decode , ErrorKind , SliceReader , Tag , TagNumber } ;
4343 use pkcs8:: PrivateKeyInfo ;
4444
45- let bytes: Vec < u8 > = pem_reader
46- . bytes ( )
47- . collect :: < Result < Vec < u8 > , std:: io:: Error > > ( ) ?;
48- let pki = PrivateKeyInfo :: decode ( & mut PemReader :: new ( & bytes) ?) ?;
49- let private_key = SigningKey :: try_from ( pki. private_key ) ?;
45+ let bytes: Vec < u8 > = pem_reader. bytes ( ) . collect :: < Result < _ , _ > > ( ) ?;
46+ let pem = pem:: parse ( bytes) ?;
47+ let pki_res = PrivateKeyInfo :: decode ( & mut SliceReader :: new ( pem. contents ( ) ) ?) ;
48+ let mut truncated;
49+ let pki = match pki_res {
50+ Ok ( pki) => pki,
51+ Err ( e) => {
52+ if e. kind ( )
53+ == ( ErrorKind :: Noncanonical {
54+ tag : Tag :: ContextSpecific {
55+ constructed : true ,
56+ number : TagNumber :: new ( 1 ) ,
57+ } ,
58+ } )
59+ {
60+ // Very old versions of dfx generated nonconforming containers. They can only be imported if the extra data is removed.
61+ truncated = pem. into_contents ( ) ;
62+ if truncated[ 48 ..52 ] != * b"\xA1 \x23 \x03 \x21 " {
63+ return Err ( e. into ( ) ) ;
64+ }
65+ // hatchet surgery
66+ truncated. truncate ( 48 ) ;
67+ truncated[ 1 ] = 46 ;
68+ truncated[ 4 ] = 0 ;
69+ PrivateKeyInfo :: decode ( & mut SliceReader :: new ( & truncated) ?) . map_err ( |_| e) ?
70+ } else {
71+ return Err ( e. into ( ) ) ;
72+ }
73+ }
74+ } ;
75+ let decoded_key = OctetString :: from_der ( pki. private_key ) ?; // ed25519 uses an octet string within another octet string
76+ let private_key = SigningKey :: try_from ( decoded_key. as_bytes ( ) ) ?;
5077 Ok ( BasicIdentity :: from_signing_key ( private_key) )
5178 }
5279
0 commit comments