Skip to content

Commit f18c6d8

Browse files
authored
Merge pull request #289 from tlsfuzzer/invalid-curve-params
better handling for malformed curve parameters
2 parents 915094a + 6c61180 commit f18c6d8

File tree

3 files changed

+39
-8
lines changed

3 files changed

+39
-8
lines changed

src/ecdsa/ellipticcurve.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ def _from_compressed(data, curve):
260260
alpha = (pow(x, 3, p) + (curve.a() * x) + curve.b()) % p
261261
try:
262262
beta = numbertheory.square_root_mod_prime(alpha, p)
263-
except numbertheory.SquareRootError as e:
263+
except numbertheory.Error as e:
264264
raise MalformedPointError(
265265
"Encoding does not correspond to a point on curve", e
266266
)
@@ -315,7 +315,7 @@ def _from_edwards(cls, curve, data):
315315

316316
try:
317317
x = numbertheory.square_root_mod_prime(x2, p)
318-
except numbertheory.SquareRootError as e:
318+
except numbertheory.Error as e:
319319
raise MalformedPointError(
320320
"Encoding does not correspond to a point on curve", e
321321
)

src/ecdsa/numbertheory.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ class Error(Exception):
4343
pass
4444

4545

46+
class JacobiError(Error):
47+
pass
48+
49+
4650
class SquareRootError(Error):
4751
pass
4852

@@ -154,8 +158,10 @@ def jacobi(a, n):
154158
# table printed in HAC, and by extensive use in calculating
155159
# modular square roots.
156160

157-
assert n >= 3
158-
assert n % 2 == 1
161+
if not n >= 3:
162+
raise JacobiError("n must be larger than 2")
163+
if not n % 2 == 1:
164+
raise JacobiError("n must be odd")
159165
a = a % n
160166
if a == 0:
161167
return 0
@@ -202,9 +208,8 @@ def square_root_mod_prime(a, p):
202208
d = pow(a, (p - 1) // 4, p)
203209
if d == 1:
204210
return pow(a, (p + 3) // 8, p)
205-
if d == p - 1:
206-
return (2 * a * pow(4 * a, (p - 5) // 8, p)) % p
207-
raise RuntimeError("Shouldn't get here.")
211+
assert d == p - 1
212+
return (2 * a * pow(4 * a, (p - 5) // 8, p)) % p
208213

209214
if PY2:
210215
# xrange on python2 can take integers representable as C long only
@@ -215,7 +220,8 @@ def square_root_mod_prime(a, p):
215220
if jacobi(b * b - 4 * a, p) == -1:
216221
f = (a, -b, 1)
217222
ff = polynomial_exp_mod((0, 1), (p + 1) // 2, f, p)
218-
assert ff[1] == 0
223+
if ff[1]:
224+
raise SquareRootError("p is not prime")
219225
return ff[0]
220226
raise RuntimeError("No b found.")
221227

src/ecdsa/test_numbertheory.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
HC_PRESENT = False
1818
from .numbertheory import (
1919
SquareRootError,
20+
JacobiError,
2021
factorization,
2122
gcd,
2223
lcm,
@@ -108,6 +109,30 @@ def test_square_root_mod_prime_for_p_congruent_5_large_d():
108109
assert root * root % p == 4
109110

110111

112+
class TestSquareRootModPrime(unittest.TestCase):
113+
def test_power_of_2_p(self):
114+
with self.assertRaises(JacobiError):
115+
square_root_mod_prime(12, 32)
116+
117+
def test_no_square(self):
118+
with self.assertRaises(SquareRootError) as e:
119+
square_root_mod_prime(12, 31)
120+
121+
self.assertIn("no square root", str(e.exception))
122+
123+
def test_non_prime(self):
124+
with self.assertRaises(SquareRootError) as e:
125+
square_root_mod_prime(12, 33)
126+
127+
self.assertIn("p is not prime", str(e.exception))
128+
129+
def test_non_prime_with_negative(self):
130+
with self.assertRaises(SquareRootError) as e:
131+
square_root_mod_prime(697 - 1, 697)
132+
133+
self.assertIn("p is not prime", str(e.exception))
134+
135+
111136
@st.composite
112137
def st_two_nums_rel_prime(draw):
113138
# 521-bit is the biggest curve we operate on, use 1024 for a bit

0 commit comments

Comments
 (0)