Skip to content

Commit 507c1fb

Browse files
committed
test(crypto): CRP-928 Add tests of ECDSA invalid public keys
1 parent 30a213d commit 507c1fb

File tree

4 files changed

+124
-0
lines changed

4 files changed

+124
-0
lines changed

rs/crypto/ecdsa_secp256k1/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,8 @@ impl PublicKey {
334334
///
335335
/// This is just the encoding of the point. Both compressed and uncompressed
336336
/// points are accepted
337+
///
338+
/// See SEC1 <https://www.secg.org/sec1-v2.pdf> section 2.3.3 for details of the format
337339
pub fn deserialize_sec1(bytes: &[u8]) -> Result<Self, KeyDecodingError> {
338340
let key = k256::ecdsa::VerifyingKey::from_sec1_bytes(bytes)
339341
.map_err(|e| KeyDecodingError::InvalidKeyEncoding(format!("{:?}", e)))?;
@@ -362,6 +364,8 @@ impl PublicKey {
362364
/// Serialize a public key in SEC1 format
363365
///
364366
/// The point can optionally be compressed
367+
///
368+
/// See SEC1 <https://www.secg.org/sec1-v2.pdf> section 2.3.3 for details
365369
pub fn serialize_sec1(&self, compressed: bool) -> Vec<u8> {
366370
self.key.to_encoded_point(compressed).as_bytes().to_vec()
367371
}

rs/crypto/ecdsa_secp256k1/tests/tests.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,64 @@ fn should_reject_high_s_in_signature_unless_malleable() -> Result<(), KeyDecodin
126126
Ok(())
127127
}
128128

129+
#[test]
130+
fn should_reject_invalid_public_keys() {
131+
struct InvalidKey {
132+
reason: &'static str,
133+
key: Vec<u8>,
134+
}
135+
136+
impl InvalidKey {
137+
fn new(reason: &'static str, key_hex: &'static str) -> Self {
138+
let key = hex::decode(key_hex).expect("Invalid key_hex param");
139+
Self { reason, key }
140+
}
141+
}
142+
143+
let invalid_keys = [
144+
InvalidKey::new("empty", ""),
145+
InvalidKey::new("too short", "02"),
146+
InvalidKey::new(
147+
"valid compressed point with uncompressed header",
148+
"04F599CDA3A05987498A716E820651AC96A4EEAA3AD9B7D6F244A83CC3381CABC4",
149+
),
150+
InvalidKey::new(
151+
"invalid x, header 02",
152+
"02F599CDA3A05987498A716E820651AC96A4EEAA3AD9B7D6F244A83CC3381CABC3",
153+
),
154+
InvalidKey::new(
155+
"invalid x, header 03",
156+
"03F599CDA3A05987498A716E820651AC96A4EEAA3AD9B7D6F244A83CC3381CABC3",
157+
),
158+
InvalidKey::new(
159+
"valid uncompressed point with header 02",
160+
"02F599CDA3A05987498A716E820651AC96A4EEAA3AD9B7D6F244A83CC3381CABC4C300A1369821A5A86D4D9BA74FF68817C4CAEA4BAC737A7B00A48C4835F28DB4"
161+
),
162+
InvalidKey::new(
163+
"valid uncompressed point with header 03",
164+
"03F599CDA3A05987498A716E820651AC96A4EEAA3AD9B7D6F244A83CC3381CABC4C300A1369821A5A86D4D9BA74FF68817C4CAEA4BAC737A7B00A48C4835F28DB4"
165+
),
166+
InvalidKey::new(
167+
"invalid uncompressed point (y off by one)",
168+
"04F599CDA3A05987498A716E820651AC96A4EEAA3AD9B7D6F244A83CC3381CABC4C300A1369821A5A86D4D9BA74FF68817C4CAEA4BAC737A7B00A48C4835F28DB5"
169+
),
170+
InvalidKey::new(
171+
"valid P256 point",
172+
"04EB2D21CD969E68C767B091E91900863E7699826C3466F15B956BBB6CBAEDB09A5A16ED621975EC1BCB81A41EE5DCF719021B12A95CC858A735A266135EFD2E4E"
173+
),
174+
];
175+
176+
for invalid_key in &invalid_keys {
177+
let result = PublicKey::deserialize_sec1(&invalid_key.key);
178+
179+
assert!(
180+
result.is_err(),
181+
"Accepted invalid key ({})",
182+
invalid_key.reason
183+
);
184+
}
185+
}
186+
129187
#[test]
130188
fn should_serialization_and_deserialization_round_trip_for_private_keys(
131189
) -> Result<(), KeyDecodingError> {

rs/crypto/ecdsa_secp256r1/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,8 @@ impl PublicKey {
318318
///
319319
/// This is just the encoding of the point. Both compressed and uncompressed
320320
/// points are accepted
321+
///
322+
/// See SEC1 <https://www.secg.org/sec1-v2.pdf> section 2.3.3 for details of the format
321323
pub fn deserialize_sec1(bytes: &[u8]) -> Result<Self, KeyDecodingError> {
322324
let key = p256::ecdsa::VerifyingKey::from_sec1_bytes(bytes)
323325
.map_err(|e| KeyDecodingError::InvalidKeyEncoding(format!("{:?}", e)))?;
@@ -346,6 +348,8 @@ impl PublicKey {
346348
/// Serialize a public key in SEC1 format
347349
///
348350
/// The point can optionally be compressed
351+
///
352+
/// See SEC1 <https://www.secg.org/sec1-v2.pdf> section 2.3.3 for details of the format
349353
pub fn serialize_sec1(&self, compressed: bool) -> Vec<u8> {
350354
self.key.to_encoded_point(compressed).to_bytes().to_vec()
351355
}

rs/crypto/ecdsa_secp256r1/tests/tests.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,64 @@ fn should_serialization_and_deserialization_round_trip_for_public_keys(
161161
Ok(())
162162
}
163163

164+
#[test]
165+
fn should_reject_invalid_public_keys() {
166+
struct InvalidKey {
167+
reason: &'static str,
168+
key: Vec<u8>,
169+
}
170+
171+
impl InvalidKey {
172+
fn new(reason: &'static str, key_hex: &'static str) -> Self {
173+
let key = hex::decode(key_hex).expect("Invalid key_hex param");
174+
Self { reason, key }
175+
}
176+
}
177+
178+
let invalid_keys = [
179+
InvalidKey::new("empty", ""),
180+
InvalidKey::new("too short", "02"),
181+
InvalidKey::new(
182+
"valid compressed point with uncompressed header",
183+
"04EB2D21CD969E68C767B091E91900863E7699826C3466F15B956BBB6CBAEDB09A",
184+
),
185+
InvalidKey::new(
186+
"invalid x, header 02",
187+
"02EB2D21CD969E68C767B091E91900863E7699826C3466F15B956BBB6CBAEDB09C",
188+
),
189+
InvalidKey::new(
190+
"invalid x, header 03",
191+
"03EB2D21CD969E68C767B091E91900863E7699826C3466F15B956BBB6CBAEDB09C",
192+
),
193+
InvalidKey::new(
194+
"valid uncompressed point with header 02",
195+
"02EB2D21CD969E68C767B091E91900863E7699826C3466F15B956BBB6CBAEDB09A5A16ED621975EC1BCB81A41EE5DCF719021B12A95CC858A735A266135EFD2E4E"
196+
),
197+
InvalidKey::new(
198+
"valid uncompressed point with header 03",
199+
"03EB2D21CD969E68C767B091E91900863E7699826C3466F15B956BBB6CBAEDB09A5A16ED621975EC1BCB81A41EE5DCF719021B12A95CC858A735A266135EFD2E4E"
200+
),
201+
InvalidKey::new(
202+
"invalid uncompressed point (y off by one)",
203+
"04EB2D21CD969E68C767B091E91900863E7699826C3466F15B956BBB6CBAEDB09A5A16ED621975EC1BCB81A41EE5DCF719021B12A95CC858A735A266135EFD2E4F",
204+
),
205+
InvalidKey::new(
206+
"valid secp256k1 point",
207+
"04F599CDA3A05987498A716E820651AC96A4EEAA3AD9B7D6F244A83CC3381CABC4C300A1369821A5A86D4D9BA74FF68817C4CAEA4BAC737A7B00A48C4835F28DB4"
208+
),
209+
];
210+
211+
for invalid_key in &invalid_keys {
212+
let result = PublicKey::deserialize_sec1(&invalid_key.key);
213+
214+
assert!(
215+
result.is_err(),
216+
"Accepted invalid key ({})",
217+
invalid_key.reason
218+
);
219+
}
220+
}
221+
164222
#[test]
165223
fn should_insecure_keygen_for_testing_be_deterministic() {
166224
assert_eq!(

0 commit comments

Comments
 (0)