Skip to content

Commit 3a936ac

Browse files
petertoddposita
authored andcommitted
Fix OpenSSL related crashes on OSX and Arch
Credit goes to Casey Rodarmor for the fix, which is copied from a MIT-licensed QA tests pull-req for Bitcoin Core that was written by him: https://github.com/casey/bitcoin/blob/fullblocktest/qa/rpc-tests/test_framework/key.py
1 parent 873095a commit 3a936ac

File tree

1 file changed

+163
-27
lines changed

1 file changed

+163
-27
lines changed

bitcoin/core/key.py

Lines changed: 163 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -27,37 +27,173 @@
2727
if sys.version > '3':
2828
_bchr = lambda x: bytes([x])
2929
_bord = lambda x: x
30-
from io import BytesIO as BytesIO
31-
else:
32-
from cStringIO import StringIO as BytesIO
3330

3431
import bitcoin.core.script
3532

3633
_ssl = ctypes.cdll.LoadLibrary(ctypes.util.find_library('ssl') or 'libeay32')
3734

38-
# this specifies the curve used with ECDSA.
39-
_NID_secp256k1 = 714 # from openssl/obj_mac.h
35+
class OpenSSLException(EnvironmentError):
36+
pass
4037

41-
# test that openssl support secp256k1
42-
if _ssl.EC_KEY_new_by_curve_name(_NID_secp256k1) == 0:
43-
errno = _ssl.ERR_get_error()
44-
errmsg = ctypes.create_string_buffer(120)
45-
_ssl.ERR_error_string_n(errno, errmsg, 120)
46-
raise RuntimeError('openssl error: %s' % errmsg.value)
47-
48-
# Thx to Sam Devlin for the ctypes magic 64-bit fix.
49-
def _check_result (val, func, args):
38+
# Thx to Sam Devlin for the ctypes magic 64-bit fix (FIXME: should this
39+
# be applied to every OpenSSL call whose return type is a pointer?)
40+
def _check_res_void_p(val, func, args): # pylint: disable=unused-argument
5041
if val == 0:
51-
raise ValueError
52-
else:
53-
return ctypes.c_void_p(val)
42+
errno = _ssl.ERR_get_error()
43+
errmsg = ctypes.create_string_buffer(120)
44+
_ssl.ERR_error_string_n(errno, errmsg, 120)
45+
raise OpenSSLException(errno, str(errmsg.value))
46+
47+
return ctypes.c_void_p(val)
48+
49+
_ssl.BN_add.restype = ctypes.c_int
50+
_ssl.BN_add.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
51+
52+
_ssl.BN_bin2bn.restype = ctypes.c_void_p
53+
_ssl.BN_bin2bn.argtypes = [ctypes.c_char_p, ctypes.c_int, ctypes.c_void_p]
54+
55+
_ssl.BN_cmp.restype = ctypes.c_int
56+
_ssl.BN_cmp.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
57+
58+
_ssl.BN_copy.restype = ctypes.c_void_p
59+
_ssl.BN_copy.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
60+
61+
_ssl.BN_free.restype = None
62+
_ssl.BN_free.argtypes = [ctypes.c_void_p]
63+
64+
_ssl.BN_mod_inverse.restype = ctypes.c_void_p
65+
_ssl.BN_mod_inverse.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
66+
67+
_ssl.BN_mod_mul.restype = ctypes.c_int
68+
_ssl.BN_mod_mul.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
69+
70+
_ssl.BN_mod_sub.restype = ctypes.c_int
71+
_ssl.BN_mod_sub.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
72+
73+
_ssl.BN_mul_word.restype = ctypes.c_int
74+
_ssl.BN_mul_word.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
5475

76+
_ssl.BN_new.errcheck = _check_res_void_p
77+
_ssl.BN_new.restype = ctypes.c_void_p
78+
_ssl.BN_new.argtypes = []
79+
80+
_ssl.BN_rshift.restype = ctypes.c_int
81+
_ssl.BN_rshift.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int]
82+
83+
_ssl.BN_rshift1.restype = ctypes.c_int
84+
_ssl.BN_rshift1.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
85+
86+
_ssl.BN_sub.restype = ctypes.c_int
87+
_ssl.BN_sub.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
88+
89+
# _ssl.BN_zero.restype = ctypes.c_int
90+
# _ssl.BN_zero.argtypes = [ctypes.c_void_p]
91+
92+
_ssl.BN_CTX_free.restype = None
93+
_ssl.BN_CTX_free.argtypes = [ctypes.c_void_p]
94+
95+
_ssl.BN_CTX_get.restype = ctypes.c_void_p
96+
_ssl.BN_CTX_get.argtypes = [ctypes.c_void_p]
97+
98+
_ssl.BN_CTX_new.errcheck = _check_res_void_p
99+
_ssl.BN_CTX_new.restype = ctypes.c_void_p
100+
_ssl.BN_CTX_new.argtypes = []
101+
102+
_ssl.EC_GROUP_get_curve_GFp.restype = ctypes.c_int
103+
_ssl.EC_GROUP_get_curve_GFp.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
104+
105+
_ssl.EC_GROUP_get_degree.restype = ctypes.c_int
106+
_ssl.EC_GROUP_get_degree.argtypes = [ctypes.c_void_p]
107+
108+
_ssl.EC_GROUP_get_order.restype = ctypes.c_int
109+
_ssl.EC_GROUP_get_order.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
110+
111+
_ssl.EC_KEY_free.restype = None
112+
_ssl.EC_KEY_free.argtypes = [ctypes.c_void_p]
113+
114+
_ssl.EC_KEY_new_by_curve_name.errcheck = _check_res_void_p
55115
_ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p
56-
_ssl.EC_KEY_new_by_curve_name.errcheck = _check_result
116+
_ssl.EC_KEY_new_by_curve_name.argtypes = [ctypes.c_int]
117+
118+
_ssl.EC_KEY_get0_group.restype = ctypes.c_void_p
119+
_ssl.EC_KEY_get0_group.argtypes = [ctypes.c_void_p]
120+
121+
_ssl.EC_KEY_get0_public_key.restype = ctypes.c_void_p
122+
_ssl.EC_KEY_get0_public_key.argtypes = [ctypes.c_void_p]
123+
124+
_ssl.EC_KEY_set_conv_form.restype = None
125+
_ssl.EC_KEY_set_conv_form.argtypes = [ctypes.c_void_p, ctypes.c_int]
126+
127+
_ssl.EC_KEY_set_private_key.restype = ctypes.c_int
128+
_ssl.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
129+
130+
_ssl.EC_KEY_set_public_key.restype = ctypes.c_int
131+
_ssl.EC_KEY_set_public_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
132+
133+
_ssl.EC_POINT_free.restype = None
134+
_ssl.EC_POINT_free.argtypes = [ctypes.c_void_p]
135+
136+
_ssl.EC_POINT_is_at_infinity.restype = ctypes.c_int
137+
_ssl.EC_POINT_is_at_infinity.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
138+
139+
_ssl.EC_POINT_new.errcheck = _check_res_void_p
140+
_ssl.EC_POINT_new.restype = ctypes.c_void_p
141+
_ssl.EC_POINT_new.argtypes = [ctypes.c_void_p]
142+
143+
_ssl.EC_POINT_mul.restype = ctypes.c_int
144+
_ssl.EC_POINT_mul.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
145+
146+
_ssl.EC_POINT_set_compressed_coordinates_GFp.restype = ctypes.c_int
147+
_ssl.EC_POINT_set_compressed_coordinates_GFp.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p]
148+
149+
_ssl.ECDSA_sign.restype = ctypes.c_int
150+
_ssl.ECDSA_sign.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
151+
152+
_ssl.ECDSA_size.restype = ctypes.c_int
153+
_ssl.ECDSA_size.argtypes = [ctypes.c_void_p]
154+
155+
_ssl.ECDSA_verify.restype = ctypes.c_int
156+
_ssl.ECDSA_verify.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p]
157+
158+
_ssl.ECDSA_SIG_free.restype = None
159+
_ssl.ECDSA_SIG_free.argtypes = [ctypes.c_void_p]
160+
161+
_ssl.ECDH_compute_key.restype = ctypes.c_int
162+
_ssl.ECDH_compute_key.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p]
163+
164+
_ssl.ERR_error_string_n.restype = None
165+
_ssl.ERR_error_string_n.argtypes = [ctypes.c_ulong, ctypes.c_char_p, ctypes.c_size_t]
166+
167+
_ssl.ERR_get_error.restype = ctypes.c_ulong
168+
_ssl.ERR_get_error.argtypes = []
169+
170+
_ssl.d2i_ECDSA_SIG.restype = ctypes.c_void_p
171+
_ssl.d2i_ECDSA_SIG.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_long]
172+
173+
_ssl.d2i_ECPrivateKey.restype = ctypes.c_void_p
174+
_ssl.d2i_ECPrivateKey.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_long]
175+
176+
_ssl.i2d_ECDSA_SIG.restype = ctypes.c_int
177+
_ssl.i2d_ECDSA_SIG.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
178+
179+
_ssl.i2d_ECPrivateKey.restype = ctypes.c_int
180+
_ssl.i2d_ECPrivateKey.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
181+
182+
_ssl.i2o_ECPublicKey.restype = ctypes.c_void_p
183+
_ssl.i2o_ECPublicKey.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
184+
185+
_ssl.o2i_ECPublicKey.restype = ctypes.c_void_p
186+
_ssl.o2i_ECPublicKey.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_long]
187+
188+
# this specifies the curve used with ECDSA.
189+
_NID_secp256k1 = 714 # from openssl/obj_mac.h
190+
191+
# test that OpenSSL supports secp256k1
192+
_ssl.EC_KEY_new_by_curve_name(_NID_secp256k1)
57193

58194
# From openssl/ecdsa.h
59195
class ECDSA_SIG_st(ctypes.Structure):
60-
_fields_ = [("r", ctypes.c_void_p),
196+
_fields_ = [("r", ctypes.c_void_p),
61197
("s", ctypes.c_void_p)]
62198

63199
class CECKey:
@@ -122,7 +258,7 @@ def get_ecdh_key(self, other_pubkey, kdf=lambda k: hashlib.sha256(k).digest()):
122258
r = self.get_raw_ecdh_key(other_pubkey)
123259
return kdf(r)
124260

125-
def sign(self, hash):
261+
def sign(self, hash): # pylint: disable=redefined-builtin
126262
if not isinstance(hash, bytes):
127263
raise TypeError('Hash must be bytes instance; got %r' % hash.__class__)
128264
if len(hash) != 32:
@@ -138,7 +274,7 @@ def sign(self, hash):
138274
else:
139275
return self.signature_to_low_s(mb_sig.raw[:sig_size0.value])
140276

141-
def sign_compact(self, hash):
277+
def sign_compact(self, hash): # pylint: disable=redefined-builtin
142278
if not isinstance(hash, bytes):
143279
raise TypeError('Hash must be bytes instance; got %r' % hash.__class__)
144280
if len(hash) != 32:
@@ -214,10 +350,10 @@ def signature_to_low_s(self, sig):
214350

215351
return new_sig.raw
216352

217-
def verify(self, hash, sig):
353+
def verify(self, hash, sig): # pylint: disable=redefined-builtin
218354
"""Verify a DER signature"""
219355
if not sig:
220-
return false
356+
return False
221357

222358
# New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first.
223359
norm_sig = ctypes.c_void_p(0)
@@ -226,7 +362,7 @@ def verify(self, hash, sig):
226362
derlen = _ssl.i2d_ECDSA_SIG(norm_sig, 0)
227363
if derlen == 0:
228364
_ssl.ECDSA_SIG_free(norm_sig)
229-
return false
365+
return False
230366

231367
norm_der = ctypes.create_string_buffer(derlen)
232368
_ssl.i2d_ECDSA_SIG(norm_sig, ctypes.byref(ctypes.pointer(norm_der)))
@@ -362,11 +498,11 @@ def __new__(cls, buf, _cec_key=None):
362498
if _cec_key is None:
363499
_cec_key = CECKey()
364500
self._cec_key = _cec_key
365-
self.is_fullyvalid = _cec_key.set_pubkey(self) != 0
501+
self.is_fullyvalid = _cec_key.set_pubkey(self) is not None
366502
return self
367503

368504
@classmethod
369-
def recover_compact(cls, hash, sig):
505+
def recover_compact(cls, hash, sig): # pylint: disable=redefined-builtin
370506
"""Recover a public key from a compact signature."""
371507
if len(sig) != 65:
372508
raise ValueError("Signature should be 65 characters, not [%d]" % (len(sig), ))
@@ -397,7 +533,7 @@ def is_valid(self):
397533
def is_compressed(self):
398534
return len(self) == 33
399535

400-
def verify(self, hash, sig):
536+
def verify(self, hash, sig): # pylint: disable=redefined-builtin
401537
return self._cec_key.verify(hash, sig)
402538

403539
def __str__(self):

0 commit comments

Comments
 (0)