commit a9e74da11c8db7e19f69128fde0d15de426c7696
parent 7b3e1dafd42ce8548563b1acea55649be90b2e60
Author: ThomasV <thomasv@gitorious>
Date: Wed, 5 Aug 2015 20:49:45 +0200
check SSL certificate in config dialog
Diffstat:
2 files changed, 101 insertions(+), 76 deletions(-)
diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py
@@ -2529,6 +2529,7 @@ class ElectrumWindow(QMainWindow):
tx_widgets = []
id_widgets = []
+ # language
lang_help = _('Select which language is used in the GUI (after restart).')
lang_label = HelpLabel(_('Language') + ':', lang_help)
lang_combo = QComboBox()
@@ -2631,20 +2632,28 @@ class ElectrumWindow(QMainWindow):
alias_e.editingFinished.connect(on_alias_edit)
id_widgets.append((alias_label, alias_e))
- msg = _('Chain of SSL certificates, used to create BIP70 payment requests. ')\
- +_('Put your certificate at the top of the list, and the root CA at the end')
- SSL_cert_label = HelpLabel(_('SSL certificate') + ':', msg)
- SSL_cert = self.config.get('ssl_chain','')
- SSL_cert_e = QLineEdit(SSL_cert)
- SSL_cert_e.editingFinished.connect(lambda: self.config.set_key('ssl_chain', str(SSL_cert_e.text())))
- id_widgets.append((SSL_cert_label, SSL_cert_e))
-
- msg = _('Path to your SSL private key, used to sign BIP70 payment requests.')
- SSL_key_label = HelpLabel(_('SSL private key') + ':', msg)
- SSL_key = self.config.get('ssl_privkey','')
- SSL_key_e = QLineEdit(SSL_key)
- SSL_key_e.editingFinished.connect(lambda: self.config.set_key('ssl_privkey', str(SSL_key_e.text())))
- id_widgets.append((SSL_key_label, SSL_key_e))
+ # SSL certificate
+ msg = ' '.join([
+ _('SSL certificate used to sign payment requests.'),
+ _('Use setconfig to set ssl_chain and ssl_privkey.'),
+ ])
+ if self.config.get('ssl_privkey') or self.onfig.get('ssl_chain'):
+ try:
+ SSL_identity = paymentrequest.check_ssl_config(self.config)
+ SSL_error = None
+ except BaseException as e:
+ SSL_identity = "error"
+ SSL_error = str(e)
+ else:
+ SSL_identity = ""
+ SSL_error = None
+ SSL_id_label = HelpLabel(_('SSL certificate') + ':', msg)
+ SSL_id_e = QLineEdit(SSL_identity)
+ SSL_id_e.setStyleSheet(RED_BG if SSL_error else GREEN_BG if SSL_identity else '')
+ if SSL_error:
+ SSL_id_e.setToolTip(SSL_error)
+ SSL_id_e.setReadOnly(True)
+ id_widgets.append((SSL_id_label, SSL_id_e))
units = ['BTC', 'mBTC', 'bits']
msg = _('Base unit of your wallet.')\
diff --git a/lib/paymentrequest.py b/lib/paymentrequest.py
@@ -119,75 +119,22 @@ class PaymentRequest:
return False
def verify_x509(self, paymntreq):
- """ verify chain of certificates. The last certificate is the CA"""
if not ca_list:
self.error = "Trusted certificate authorities list not found"
return False
cert = pb2.X509Certificates()
cert.ParseFromString(paymntreq.pki_data)
- cert_num = len(cert.certificate)
- x509_chain = []
- for i in range(cert_num):
- x = x509.X509()
- x.parseBinary(bytearray(cert.certificate[i]))
- x509_chain.append(x)
- if i == 0:
- try:
- x.check_date()
- except Exception as e:
- self.error = str(e)
- return
- self.requestor = x.get_common_name()
- if self.requestor.startswith('*.'):
- self.requestor = self.requestor[2:]
- else:
- if not x.check_ca():
- self.error = "ERROR: Supplied CA Certificate Error"
- return
- if not cert_num > 1:
- self.error = "ERROR: CA Certificate Chain Not Provided by Payment Processor"
+ # verify the chain of certificates
+ try:
+ x, ca = verify_cert_chain(cert.certificate)
+ except BaseException as e:
+ self.error = str(e)
return False
- # if the root CA is not supplied, add it to the chain
- ca = x509_chain[cert_num-1]
- if ca.getFingerprint() not in ca_list:
- keyID = ca.get_issuer_keyID()
- f = ca_keyID.get(keyID)
- if f:
- root = ca_list[f]
- x509_chain.append(root)
- else:
- self.error = "Supplied CA Not Found in Trusted CA Store."
- return False
- # verify the chain of signatures
- cert_num = len(x509_chain)
- for i in range(1, cert_num):
- x = x509_chain[i]
- prev_x = x509_chain[i-1]
- algo, sig, data = prev_x.get_signature()
- sig = bytearray(sig)
-
- pubkey = rsakey.RSAKey(x.modulus, x.exponent)
-
- if algo == x509.ALGO_RSA_SHA1:
- verify = pubkey.hashAndVerify(sig, data)
- elif algo == x509.ALGO_RSA_SHA256:
- hashBytes = bytearray(hashlib.sha256(data).digest())
- verify = pubkey.verify(sig, x509.PREFIX_RSA_SHA256 + hashBytes)
- elif algo == x509.ALGO_RSA_SHA384:
- hashBytes = bytearray(hashlib.sha384(data).digest())
- verify = pubkey.verify(sig, x509.PREFIX_RSA_SHA384 + hashBytes)
- elif algo == x509.ALGO_RSA_SHA512:
- hashBytes = bytearray(hashlib.sha512(data).digest())
- verify = pubkey.verify(sig, x509.PREFIX_RSA_SHA512 + hashBytes)
- else:
- self.error = "Algorithm not supported"
- util.print_error(self.error, algo.getComponentByName('algorithm'))
- return False
- if not verify:
- self.error = "Certificate not Signed by Provided CA Certificate Chain"
- return False
+ # get requestor name
+ self.requestor = x.get_common_name()
+ if self.requestor.startswith('*.'):
+ self.requestor = self.requestor[2:]
# verify the BIP70 signature
- x = x509_chain[0]
pubkey0 = rsakey.RSAKey(x.modulus, x.exponent)
sig = paymntreq.signature
paymntreq.signature = ''
@@ -330,6 +277,75 @@ def sign_request_with_alias(pr, alias, alias_privkey):
+def verify_cert_chain(chain):
+ """ Verify a chain of certificates. The last certificate is the CA"""
+ # parse the chain
+ cert_num = len(chain)
+ x509_chain = []
+ for i in range(cert_num):
+ x = x509.X509()
+ x.parseBinary(bytearray(chain[i]))
+ x509_chain.append(x)
+ if i == 0:
+ x.check_date()
+ else:
+ if not x.check_ca():
+ raise BaseException("ERROR: Supplied CA Certificate Error")
+ if not cert_num > 1:
+ raise BaseException("ERROR: CA Certificate Chain Not Provided by Payment Processor")
+ # if the root CA is not supplied, add it to the chain
+ ca = x509_chain[cert_num-1]
+ if ca.getFingerprint() not in ca_list:
+ keyID = ca.get_issuer_keyID()
+ f = ca_keyID.get(keyID)
+ if f:
+ root = ca_list[f]
+ x509_chain.append(root)
+ else:
+ raise BaseException("Supplied CA Not Found in Trusted CA Store.")
+ # verify the chain of signatures
+ cert_num = len(x509_chain)
+ for i in range(1, cert_num):
+ x = x509_chain[i]
+ prev_x = x509_chain[i-1]
+ algo, sig, data = prev_x.get_signature()
+ sig = bytearray(sig)
+ pubkey = rsakey.RSAKey(x.modulus, x.exponent)
+ if algo == x509.ALGO_RSA_SHA1:
+ verify = pubkey.hashAndVerify(sig, data)
+ elif algo == x509.ALGO_RSA_SHA256:
+ hashBytes = bytearray(hashlib.sha256(data).digest())
+ verify = pubkey.verify(sig, x509.PREFIX_RSA_SHA256 + hashBytes)
+ elif algo == x509.ALGO_RSA_SHA384:
+ hashBytes = bytearray(hashlib.sha384(data).digest())
+ verify = pubkey.verify(sig, x509.PREFIX_RSA_SHA384 + hashBytes)
+ elif algo == x509.ALGO_RSA_SHA512:
+ hashBytes = bytearray(hashlib.sha512(data).digest())
+ verify = pubkey.verify(sig, x509.PREFIX_RSA_SHA512 + hashBytes)
+ else:
+ raise BaseException("Algorithm not supported")
+ util.print_error(self.error, algo.getComponentByName('algorithm'))
+ if not verify:
+ raise BaseException("Certificate not Signed by Provided CA Certificate Chain")
+
+ return x509_chain[0], ca
+
+
+def check_ssl_config(config):
+ import pem
+ key_path = config.get('ssl_privkey')
+ cert_path = config.get('ssl_chain')
+ with open(key_path, 'r') as f:
+ params = pem.parse_private_key(f.read())
+ privkey = rsakey.RSAKey(*params)
+ with open(cert_path, 'r') as f:
+ s = f.read()
+ bList = pem.dePemList(s, "CERTIFICATE")
+ # verify chain
+ x, ca = verify_cert_chain(bList)
+ # verify pubkey
+ return x.get_common_name()
+
def sign_request_with_x509(pr, key_path, cert_path):
import pem
with open(key_path, 'r') as f: