From 9d83bb2a897d289a52996c0e3a384188064ed4d1 Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Mon, 21 Aug 2023 22:40:07 -0600 Subject: [PATCH] sdk: enforce that `Keypair::from_bytes` bytes match secret-derived `Pubkey` (#32926) --- sdk/src/signer/keypair.rs | 16 ++++++++++++---- sdk/src/transaction/mod.rs | 26 +++++++++++++------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/sdk/src/signer/keypair.rs b/sdk/src/signer/keypair.rs index e9a9ce2f1..3183dac88 100644 --- a/sdk/src/signer/keypair.rs +++ b/sdk/src/signer/keypair.rs @@ -44,7 +44,16 @@ impl Keypair { /// Recovers a `Keypair` from a byte array pub fn from_bytes(bytes: &[u8]) -> Result { - ed25519_dalek::Keypair::from_bytes(bytes).map(Self) + let secret = + ed25519_dalek::SecretKey::from_bytes(&bytes[..ed25519_dalek::SECRET_KEY_LENGTH])?; + let public = + ed25519_dalek::PublicKey::from_bytes(&bytes[ed25519_dalek::SECRET_KEY_LENGTH..])?; + let expected_public = ed25519_dalek::PublicKey::from(&secret); + (public == expected_public) + .then_some(Self(ed25519_dalek::Keypair { secret, public })) + .ok_or(ed25519_dalek::SignatureError::from_source(String::from( + "keypair bytes do not specify same pubkey as derived from their secret key", + ))) } /// Returns this `Keypair` as a byte array @@ -161,9 +170,8 @@ impl EncodableKeypair for Keypair { /// Reads a JSON-encoded `Keypair` from a `Reader` implementor pub fn read_keypair(reader: &mut R) -> Result> { let bytes: Vec = serde_json::from_reader(reader)?; - let dalek_keypair = ed25519_dalek::Keypair::from_bytes(&bytes) - .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?; - Ok(Keypair(dalek_keypair)) + Keypair::from_bytes(&bytes) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()).into()) } /// Reads a `Keypair` from a file diff --git a/sdk/src/transaction/mod.rs b/sdk/src/transaction/mod.rs index f1c7e2ed5..9ae74405a 100644 --- a/sdk/src/transaction/mod.rs +++ b/sdk/src/transaction/mod.rs @@ -1265,9 +1265,9 @@ mod tests { fn create_sample_transaction() -> Transaction { let keypair = Keypair::from_bytes(&[ 48, 83, 2, 1, 1, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 255, 101, 36, 24, 124, 23, - 167, 21, 132, 204, 155, 5, 185, 58, 121, 75, 156, 227, 116, 193, 215, 38, 142, 22, 8, - 14, 229, 239, 119, 93, 5, 218, 161, 35, 3, 33, 0, 36, 100, 158, 252, 33, 161, 97, 185, - 62, 89, 99, + 167, 21, 132, 204, 155, 5, 185, 58, 121, 75, 124, 76, 154, 235, 9, 194, 237, 253, 194, + 191, 157, 234, 156, 225, 50, 195, 2, 9, 247, 111, 43, 33, 218, 128, 149, 245, 216, 35, + 86, 157, 94, 186, ]) .unwrap(); let to = Pubkey::from([ @@ -1354,16 +1354,16 @@ mod tests { assert_eq!( serialize(&create_sample_transaction()).unwrap(), vec![ - 1, 71, 59, 9, 187, 190, 129, 150, 165, 21, 33, 158, 72, 87, 110, 144, 120, 79, 238, - 132, 134, 105, 39, 102, 116, 209, 29, 229, 154, 36, 105, 44, 172, 118, 131, 22, - 124, 131, 179, 142, 176, 27, 117, 160, 89, 102, 224, 204, 1, 252, 141, 2, 136, 0, - 37, 218, 225, 129, 92, 154, 250, 59, 97, 178, 10, 1, 0, 1, 3, 156, 227, 116, 193, - 215, 38, 142, 22, 8, 14, 229, 239, 119, 93, 5, 218, 161, 35, 3, 33, 0, 36, 100, - 158, 252, 33, 161, 97, 185, 62, 89, 99, 1, 1, 1, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 7, 6, 5, 4, 1, 1, 1, 2, 2, 2, 4, 5, 6, 7, 8, 9, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 8, 7, 6, 5, 4, 2, 2, 2, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, - 2, 0, 1, 3, 1, 2, 3 + 1, 51, 31, 4, 198, 124, 166, 17, 196, 133, 226, 233, 135, 194, 189, 76, 152, 81, + 42, 25, 196, 226, 163, 89, 189, 104, 151, 117, 71, 73, 70, 105, 83, 9, 27, 16, 141, + 105, 150, 216, 41, 16, 37, 228, 71, 4, 39, 44, 168, 89, 182, 131, 41, 227, 47, 141, + 12, 246, 100, 222, 208, 60, 105, 225, 2, 1, 0, 1, 3, 124, 76, 154, 235, 9, 194, + 237, 253, 194, 191, 157, 234, 156, 225, 50, 195, 2, 9, 247, 111, 43, 33, 218, 128, + 149, 245, 216, 35, 86, 157, 94, 186, 1, 1, 1, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 7, 6, 5, 4, 1, 1, 1, 2, 2, 2, 4, 5, 6, 7, 8, 9, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 8, 7, 6, 5, 4, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, + 0, 1, 3, 1, 2, 3 ] ); }