diff --git a/ic-agent/src/identity/basic.rs b/ic-agent/src/identity/basic.rs index 58a63c0b..8cf2d6bd 100644 --- a/ic-agent/src/identity/basic.rs +++ b/ic-agent/src/identity/basic.rs @@ -39,14 +39,41 @@ impl BasicIdentity { /// Create a `BasicIdentity` from reading a PEM File from a Reader. #[cfg(feature = "pem")] pub fn from_pem(pem_reader: R) -> Result { - use der::{Decode, PemReader}; + use der::{asn1::OctetString, Decode, ErrorKind, SliceReader, Tag, TagNumber}; use pkcs8::PrivateKeyInfo; - let bytes: Vec = pem_reader - .bytes() - .collect::, std::io::Error>>()?; - let pki = PrivateKeyInfo::decode(&mut PemReader::new(&bytes)?)?; - let private_key = SigningKey::try_from(pki.private_key)?; + let bytes: Vec = pem_reader.bytes().collect::>()?; + let pem = pem::parse(bytes)?; + let pki_res = PrivateKeyInfo::decode(&mut SliceReader::new(pem.contents())?); + let mut truncated; + let pki = match pki_res { + Ok(pki) => pki, + Err(e) => { + if e.kind() + == (ErrorKind::Noncanonical { + tag: Tag::ContextSpecific { + constructed: true, + number: TagNumber::new(1), + }, + }) + { + // Very old versions of dfx generated nonconforming containers. They can only be imported if the extra data is removed. + truncated = pem.into_contents(); + if truncated[48..52] != *b"\xA1\x23\x03\x21" { + return Err(e.into()); + } + // hatchet surgery + truncated.truncate(48); + truncated[1] = 46; + truncated[4] = 0; + PrivateKeyInfo::decode(&mut SliceReader::new(&truncated)?).map_err(|_| e)? + } else { + return Err(e.into()); + } + } + }; + let decoded_key = OctetString::from_der(pki.private_key)?; // ed25519 uses an octet string within another octet string + let private_key = SigningKey::try_from(decoded_key.as_bytes())?; Ok(BasicIdentity::from_signing_key(private_key)) }