x509 fixes and plugins

This commit is contained in:
Dmitry Sorokin 2017-02-05 13:38:44 +03:00 committed by ThomasV
parent 0693403358
commit 362ca96f38
18 changed files with 111 additions and 115 deletions

View File

@ -189,7 +189,7 @@ class BaseWizard(object):
except:
devmgr.print_error("error", name)
continue
devices += map(lambda x: (name, x), u)
devices += list(map(lambda x: (name, x), u))
if not devices:
msg = ''.join([
_('No hardware device detected.') + '\n',
@ -235,7 +235,7 @@ class BaseWizard(object):
self.line_dialog(run_next=f, title=_('Derivation'), message=message, default=default, test=bitcoin.is_bip32_derivation)
def on_hw_derivation(self, name, device_info, derivation):
from keystore import hardware_keystore
from .keystore import hardware_keystore
xpub = self.plugin.get_xpub(device_info.device.id_, derivation, self)
if xpub is None:
self.show_error('Cannot read xpub from device')
@ -286,7 +286,7 @@ class BaseWizard(object):
self.load_2fa()
self.run('on_restore_seed', seed, is_ext)
else:
raise BaseException('Unknown seed type', seed_type)
raise BaseException('Unknown seed type', self.seed_type)
def on_restore_bip39(self, seed, passphrase):
f = lambda x: self.run('on_bip44', seed, passphrase, str(x))
@ -334,7 +334,8 @@ class BaseWizard(object):
k.update_password(None, password)
if self.wallet_type == 'standard':
self.storage.put('seed_type', self.seed_type)
self.storage.put('keystore', k.dump())
keys = self.keystores[0].dump()
self.storage.put('keystore', keys)
self.wallet = Standard_Wallet(self.storage)
self.run('create_addresses')
elif self.wallet_type == 'multisig':
@ -355,7 +356,7 @@ class BaseWizard(object):
self.on_keystore(k)
def create_seed(self):
import mnemonic
from . import mnemonic
self.seed_type = 'segwit' if bitcoin.TESTNET and self.config.get('segwit') else 'standard'
seed = mnemonic.Mnemonic('en').make_seed(self.seed_type)
self.opt_bip39 = False

View File

@ -29,7 +29,7 @@ import re
import hmac
import os
from lib.util import bfh, bh2u
from lib.util import bfh, bh2u, to_string
from . import version
from .util import print_error, InvalidPassword, assert_bytes, to_bytes
@ -150,7 +150,7 @@ def DecodeAES(secret, e):
def pw_encode(s, password):
if password:
secret = Hash(password)
return EncodeAES(secret, s.encode("utf8"))
return EncodeAES(secret, to_bytes(s, "utf8"))
else:
return s
@ -158,7 +158,7 @@ def pw_decode(s, password):
if password is not None:
secret = Hash(password)
try:
d = DecodeAES(secret, s).decode("utf8")
d = to_string(DecodeAES(secret, s), "utf8")
except Exception:
raise InvalidPassword()
return d
@ -213,7 +213,7 @@ def Hash(x):
hash_encode = lambda x: bh2u(x[::-1])
hash_decode = lambda x: bfh(x)[::-1]
hmac_sha_512 = lambda x, y: _bytes(hmac.new(x, y, hashlib.sha512).digest())
hmac_sha_512 = lambda x, y: hmac.new(x, y, hashlib.sha512).digest()
def is_new_seed(x, prefix=version.SEED_PREFIX):

View File

@ -34,8 +34,8 @@ import sys
import time
# from jsonrpc import JSONRPCResponseManager
import jsonrpclib
from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer, SimpleJSONRPCRequestHandler
# import jsonrpclib
# from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer, SimpleJSONRPCRequestHandler
from .version import ELECTRUM_VERSION
from .network import Network
@ -96,17 +96,17 @@ def get_server(config):
time.sleep(1.0)
class RequestHandler(SimpleJSONRPCRequestHandler):
def do_OPTIONS(self):
self.send_response(200)
self.end_headers()
def end_headers(self):
self.send_header("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept")
self.send_header("Access-Control-Allow-Origin", "*")
SimpleJSONRPCRequestHandler.end_headers(self)
# class RequestHandler(SimpleJSONRPCRequestHandler):
#
# def do_OPTIONS(self):
# self.send_response(200)
# self.end_headers()
#
# def end_headers(self):
# self.send_header("Access-Control-Allow-Headers",
# "Origin, X-Requested-With, Content-Type, Accept")
# self.send_header("Access-Control-Allow-Origin", "*")
# SimpleJSONRPCRequestHandler.end_headers(self)
class Daemon(DaemonThread):
@ -132,24 +132,24 @@ class Daemon(DaemonThread):
def init_server(self, config, fd):
host = config.get('rpchost', '127.0.0.1')
port = config.get('rpcport', 0)
try:
server = SimpleJSONRPCServer((host, port), logRequests=False,
requestHandler=RequestHandler)
except Exception as e:
self.print_error('Warning: cannot initialize RPC server on host', host, e)
self.server = None
os.close(fd)
return
os.write(fd, bytes(repr((server.socket.getsockname(), time.time())), 'utf8'))
os.close(fd)
server.timeout = 0.1
for cmdname in known_commands:
server.register_function(getattr(self.cmd_runner, cmdname), cmdname)
server.register_function(self.run_cmdline, 'run_cmdline')
server.register_function(self.ping, 'ping')
server.register_function(self.run_daemon, 'daemon')
server.register_function(self.run_gui, 'gui')
self.server = server
# try:
# server = SimpleJSONRPCServer((host, port), logRequests=False, requestHandler=RequestHandler)
# except Exception as e:
# self.print_error('Warning: cannot initialize RPC server on host', host, e)
# self.server = None
# os.close(fd)
# return
# os.write(fd, bytes(repr((server.socket.getsockname(), time.time())), 'utf8'))
# os.close(fd)
# server.timeout = 0.1
# for cmdname in known_commands:
# server.register_function(getattr(self.cmd_runner, cmdname), cmdname)
# server.register_function(self.run_cmdline, 'run_cmdline')
# server.register_function(self.ping, 'ping')
# server.register_function(self.run_daemon, 'daemon')
# server.register_function(self.run_gui, 'gui')
# self.server = server
self.server = None
def ping(self):
return True
@ -260,9 +260,9 @@ class Daemon(DaemonThread):
# arguments passed to function
args = map(lambda x: config.get(x), cmd.params)
# decode json arguments
args = map(json_decode, args)
args = [json_decode(i) for i in args]
# options
args += map(lambda x: (config_options.get(x) if x in ['password', 'new_password'] else config.get(x)), cmd.options)
args += list(map(lambda x: (config_options.get(x) if x in ['password', 'new_password'] else config.get(x)), cmd.options))
cmd_runner = Commands(config, wallet, self.network)
func = getattr(cmd_runner, cmd.name)
result = func(*args)

View File

@ -149,7 +149,7 @@ class Imported_KeyStore(Software_KeyStore):
except Exception:
raise BaseException('Invalid private key')
# allow overwrite
self.keypairs[pubkey] = pw_encode(sec, password)
self.keypairs[pubkey] = pw_encode(sec, password).decode('ascii')
return pubkey
def delete_imported_key(self, key):
@ -179,7 +179,7 @@ class Imported_KeyStore(Software_KeyStore):
new_password = None
for k, v in self.keypairs.items():
b = pw_decode(v, old_password)
c = pw_encode(b, new_password)
c = pw_encode(b, new_password).decode('ascii')
self.keypairs[k] = c
@ -309,13 +309,13 @@ class BIP32_KeyStore(Deterministic_KeyStore, Xpub):
new_password = None
if self.has_seed():
decoded = self.get_seed(old_password)
self.seed = pw_encode(decoded, new_password)
self.seed = pw_encode(decoded, new_password).decode('ascii')
if self.passphrase:
decoded = self.get_passphrase(old_password)
self.passphrase = pw_encode(decoded, new_password)
self.passphrase = pw_encode(decoded, new_password).decode('ascii')
if self.xprv is not None:
b = pw_decode(self.xprv, old_password)
self.xprv = pw_encode(b, new_password)
self.xprv = pw_encode(b, new_password).decode('ascii')
def is_watching_only(self):
return self.xprv is None
@ -478,7 +478,7 @@ class Old_KeyStore(Deterministic_KeyStore):
new_password = None
if self.has_seed():
decoded = self.get_hex_seed(old_password)
self.seed = pw_encode(decoded, new_password)
self.seed = pw_encode(decoded, new_password).decode('ascii')
class Hardware_KeyStore(KeyStore, Xpub):

View File

@ -173,7 +173,7 @@ class Mnemonic(object):
return i % custom_entropy == 0
def make_seed(self, seed_type='standard', num_bits=132, custom_entropy=1):
import version
from . import version
prefix = version.seed_prefix(seed_type)
# increase num_bits in order to obtain a uniform distibution for the last word
bpw = math.log(len(self.wordlist), 2)

View File

@ -345,7 +345,6 @@ def sign_request_with_alias(pr, alias, alias_privkey):
pr.signature = ec_key.sign_message(message, compressed, address)
def verify_cert_chain(chain):
""" Verify a chain of certificates. The last certificate is the CA"""
load_ca_list()

View File

@ -127,12 +127,12 @@ def pem(b, name):
-----END CERTIFICATE-----
"""
s1 = b2a_base64(b)[:-1] # remove terminating \n
s2 = ""
s2 = b""
while s1:
s2 += s1[:64] + "\n"
s2 += s1[:64] + b"\n"
s1 = s1[64:]
s = ("-----BEGIN %s-----\n" % name) + s2 + \
("-----END %s-----\n" % name)
s = ("-----BEGIN %s-----\n" % name).encode('ascii') + s2 + \
("-----END %s-----\n" % name).encode('ascii')
return s
def pemSniff(inStr, name):
@ -152,8 +152,8 @@ def parse_private_key(s):
raise SyntaxError("Not a PEM private key file")
def _parsePKCS8(bytes):
s = ASN1_Node(str(bytes))
def _parsePKCS8(_bytes):
s = ASN1_Node(_bytes)
root = s.root()
version_node = s.first_child(root)
version = bytestr_to_int(s.get_value_of_type(version_node, 'INTEGER'))
@ -192,5 +192,5 @@ def _parseASN1PrivateKey(s):
dP = s.next_node(q)
dQ = s.next_node(dP)
qInv = s.next_node(dQ)
return map(lambda x: bytesToNumber(s.get_value_of_type(x, 'INTEGER')), [n, e, d, p, q, dP, dQ, qInv])
return list(map(lambda x: bytesToNumber(s.get_value_of_type(x, 'INTEGER')), [n, e, d, p, q, dP, dQ, qInv]))

View File

@ -22,12 +22,6 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
from collections import namedtuple
import traceback
import sys
@ -192,7 +186,7 @@ class Plugins(DaemonThread):
def hook(func):
hook_names.add(func.func_name)
hook_names.add(func.__name__)
return func
def run_hook(name, *args):

View File

@ -22,12 +22,6 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import os
import ast
import threading

View File

@ -586,7 +586,8 @@ def parse_URI(uri, on_pr=None):
request = pr.PaymentRequest(s)
else:
request = pr.get_payment_request(r)
on_pr(request)
if on_pr:
on_pr(request)
t = threading.Thread(target=get_payment_request_thread)
t.setDaemon(True)
t.start()
@ -698,7 +699,6 @@ class SocketPipe:
self._send(out)
def send_all(self, requests):
print(requests)
out = b''.join(map(lambda x: (json.dumps(x) + '\n').encode('utf8'), requests))
self._send(out)

View File

@ -1537,8 +1537,6 @@ class Deterministic_Wallet(Abstract_Wallet):
return self.get_master_public_key()
class Simple_Wallet(Abstract_Wallet):
""" Wallet with a single pubkey per address """

View File

@ -63,6 +63,7 @@ ASN1_TYPES = {
'PrintableString' : 0x13,
'IA5String' : 0x16,
'UTCTime' : 0x17,
'GeneralizedTime' : 0x18,
'ENUMERATED' : 0x0A,
'UTF8String' : 0x0C,
}
@ -75,7 +76,7 @@ class CertificateError(Exception):
# helper functions
def bitstr_to_bytestr(s):
if s[0] != 0x00:
raise BaseException('no padding')
raise TypeError('no padding')
return s[1:]
@ -117,7 +118,7 @@ class ASN1_Node(bytes):
def get_node(self, ix):
# return index of first byte, first content byte and last byte.
first = self[ix + 1]
if (self[ix + 1] & 0x80) == 0:
if (first & 0x80) == 0:
length = first
ixf = ix + 2
ixl = ixf + length - 1
@ -138,7 +139,7 @@ class ASN1_Node(bytes):
def first_child(self, node):
ixs, ixf, ixl = node
if self[ixs] & 0x20 != 0x20:
raise BaseException('Can only open constructed types.', hex(self[ixs]))
raise TypeError('Can only open constructed types.', hex(self[ixs]))
return self.get_node(ixf)
def is_child_of(node1, node2):
@ -155,7 +156,7 @@ class ASN1_Node(bytes):
# verify type byte and return content
ixs, ixf, ixl = node
if ASN1_TYPES[asn1_type] != self[ixs]:
raise BaseException('Wrong type:', hex(self[ixs]), hex(ASN1_TYPES[asn1_type]))
raise TypeError('Wrong type:', hex(self[ixs]), hex(ASN1_TYPES[asn1_type]))
return self[ixf:ixl + 1]
def get_value(self, node):
@ -217,9 +218,15 @@ class X509(object):
# validity
validity = der.next_node(issuer)
ii = der.first_child(validity)
self.notBefore = der.get_value_of_type(ii, 'UTCTime')
try:
self.notBefore = der.get_value_of_type(ii, 'UTCTime')
except TypeError:
self.notBefore = der.get_value_of_type(ii, 'GeneralizedTime')[2:] # strip year
ii = der.next_node(ii)
self.notAfter = der.get_value_of_type(ii, 'UTCTime')
try:
self.notAfter = der.get_value_of_type(ii, 'UTCTime')
except TypeError:
self.notAfter = der.get_value_of_type(ii, 'GeneralizedTime')[2:] # strip year
# subject
subject = der.next_node(validity)
@ -229,17 +236,22 @@ class X509(object):
ii = der.first_child(public_key_algo)
self.public_key_algo = decode_OID(der.get_value_of_type(ii, 'OBJECT IDENTIFIER'))
# pubkey modulus and exponent
subject_public_key = der.next_node(public_key_algo)
spk = der.get_value_of_type(subject_public_key, 'BIT STRING')
spk = ASN1_Node(bitstr_to_bytestr(spk))
r = spk.root()
modulus = spk.first_child(r)
exponent = spk.next_node(modulus)
rsa_n = spk.get_value_of_type(modulus, 'INTEGER')
rsa_e = spk.get_value_of_type(exponent, 'INTEGER')
self.modulus = ecdsa.util.string_to_number(rsa_n)
self.exponent = ecdsa.util.string_to_number(rsa_e)
if self.public_key_algo != '1.2.840.10045.2.1': # for non EC public key
# pubkey modulus and exponent
subject_public_key = der.next_node(public_key_algo)
spk = der.get_value_of_type(subject_public_key, 'BIT STRING')
spk = ASN1_Node(bitstr_to_bytestr(spk))
r = spk.root()
modulus = spk.first_child(r)
exponent = spk.next_node(modulus)
rsa_n = spk.get_value_of_type(modulus, 'INTEGER')
rsa_e = spk.get_value_of_type(exponent, 'INTEGER')
self.modulus = ecdsa.util.string_to_number(rsa_n)
self.exponent = ecdsa.util.string_to_number(rsa_e)
else:
subject_public_key = der.next_node(public_key_algo)
spk = der.get_value_of_type(subject_public_key, 'BIT STRING')
self.ec_public_key = spk
# extensions
self.CA = False
@ -308,14 +320,17 @@ def load_certificates(ca_path):
from . import pem
ca_list = {}
ca_keyID = {}
with open(ca_path, 'rb') as f:
s = f.read().decode('ascii')
# ca_path = '/tmp/tmp.txt'
with open(ca_path, 'r') as f:
s = f.read()
bList = pem.dePemList(s, "CERTIFICATE")
for b in bList:
try:
x = X509(b)
x.check_date()
except BaseException as e:
# with open('/tmp/tmp.txt', 'w') as f:
# f.write(pem.pem(b, 'CERTIFICATE').decode('ascii'))
util.print_error("cert error:", e)
continue

View File

@ -26,7 +26,7 @@
import socket
import threading
import time
import xmlrpclib
from xmlrpc.client import ServerProxy
from PyQt4.QtGui import *
from PyQt4.QtCore import *
@ -45,7 +45,7 @@ import traceback
PORT = 12344
HOST = 'cosigner.electrum.org'
server = xmlrpclib.ServerProxy('http://%s:%d'%(HOST,PORT), allow_none=True)
server = ServerProxy('http://%s:%d'%(HOST,PORT), allow_none=True)
class Listener(util.DaemonThread):

View File

@ -23,8 +23,6 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from __future__ import absolute_import
import time
import threading
import base64
@ -33,9 +31,9 @@ from functools import partial
import smtplib
import imaplib
import email
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email import Encoders
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.encoders import encode_base64
from PyQt4.QtGui import *
from PyQt4.QtCore import *
@ -49,7 +47,6 @@ from electrum_gui.qt.util import EnterButton, Buttons, CloseButton
from electrum_gui.qt.util import OkButton, WindowModalDialog
class Processor(threading.Thread):
polling_interval = 5*60
@ -96,7 +93,7 @@ class Processor(threading.Thread):
msg['From'] = self.username
part = MIMEBase('application', "bitcoin-paymentrequest")
part.set_payload(payment_request)
Encoders.encode_base64(part)
encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="payreq.btc"')
msg.attach(part)
s = smtplib.SMTP_SSL(self.imap_server, timeout=2)

View File

@ -1 +1 @@
from plugin import HW_PluginBase
from .plugin import HW_PluginBase

View File

@ -12,8 +12,6 @@ from electrum.plugins import BasePlugin, hook
from electrum.i18n import _
class LabelsPlugin(BasePlugin):
def __init__(self, parent, config, name):
@ -83,7 +81,7 @@ class LabelsPlugin(BasePlugin):
bundle = {"labels": [],
"walletId": wallet_id,
"walletNonce": self.get_nonce(wallet)}
for key, value in wallet.labels.iteritems():
for key, value in wallet.labels.items():
try:
encoded_key = self.encode(wallet, key)
encoded_value = self.encode(wallet, value)
@ -135,12 +133,12 @@ class LabelsPlugin(BasePlugin):
def start_wallet(self, wallet):
nonce = self.get_nonce(wallet)
self.print_error("wallet", wallet.basename(), "nonce is", nonce)
mpk = wallet.get_fingerprint()
mpk = wallet.get_fingerprint().encode('ascii')
if not mpk:
return
password = hashlib.sha1(mpk).digest().encode('hex')[:32]
password = hashlib.sha1(mpk).hexdigest()[:32].encode('ascii')
iv = hashlib.sha256(password).digest()[:16]
wallet_id = hashlib.sha256(mpk).digest().encode('hex')
wallet_id = hashlib.sha256(mpk).hexdigest()
self.wallets[wallet] = (password, iv, wallet_id)
# If there is an auth token we can try to actually start syncing
t = threading.Thread(target=self.pull_thread, args=(wallet, False))

View File

@ -9,7 +9,7 @@ from electrum_gui.qt import EnterButton
from electrum_gui.qt.util import ThreadedButton, Buttons
from electrum_gui.qt.util import WindowModalDialog, OkButton
from labels import LabelsPlugin
from .labels import LabelsPlugin
class Plugin(LabelsPlugin):

View File

@ -3,8 +3,8 @@ from electrum.plugins import BasePlugin, hook
from electrum.i18n import _
import random
class Plugin(BasePlugin):
class Plugin(BasePlugin):
vkb = None
vkb_index = 0
@ -25,7 +25,7 @@ class Plugin(BasePlugin):
self.vkb_index += 1
def virtual_keyboard(self, i, pw):
i = i%3
i = i % 3
if i == 0:
chars = 'abcdefghijklmnopqrstuvwxyz '
elif i == 1:
@ -35,9 +35,9 @@ class Plugin(BasePlugin):
n = len(chars)
s = []
for i in xrange(n):
for i in range(n):
while True:
k = random.randint(0,n-1)
k = random.randint(0, n - 1)
if k not in s:
s.append(k)
break
@ -53,7 +53,7 @@ class Plugin(BasePlugin):
l_button.setFixedWidth(25)
l_button.setFixedHeight(25)
l_button.clicked.connect(add_target(chars[s[i]]))
grid.addWidget(l_button, i/6, i%6)
grid.addWidget(l_button, i // 6, i % 6)
vbox.addLayout(grid)