Browse Source

check SSL certificate in config dialog

283
ThomasV 10 years ago
parent
commit
a9e74da11c
  1. 37
      gui/qt/main_window.py
  2. 140
      lib/paymentrequest.py

37
gui/qt/main_window.py

@ -2529,6 +2529,7 @@ class ElectrumWindow(QMainWindow):
tx_widgets = [] tx_widgets = []
id_widgets = [] id_widgets = []
# language
lang_help = _('Select which language is used in the GUI (after restart).') lang_help = _('Select which language is used in the GUI (after restart).')
lang_label = HelpLabel(_('Language') + ':', lang_help) lang_label = HelpLabel(_('Language') + ':', lang_help)
lang_combo = QComboBox() lang_combo = QComboBox()
@ -2631,20 +2632,28 @@ class ElectrumWindow(QMainWindow):
alias_e.editingFinished.connect(on_alias_edit) alias_e.editingFinished.connect(on_alias_edit)
id_widgets.append((alias_label, alias_e)) id_widgets.append((alias_label, alias_e))
msg = _('Chain of SSL certificates, used to create BIP70 payment requests. ')\ # SSL certificate
+_('Put your certificate at the top of the list, and the root CA at the end') msg = ' '.join([
SSL_cert_label = HelpLabel(_('SSL certificate') + ':', msg) _('SSL certificate used to sign payment requests.'),
SSL_cert = self.config.get('ssl_chain','') _('Use setconfig to set ssl_chain and ssl_privkey.'),
SSL_cert_e = QLineEdit(SSL_cert) ])
SSL_cert_e.editingFinished.connect(lambda: self.config.set_key('ssl_chain', str(SSL_cert_e.text()))) if self.config.get('ssl_privkey') or self.onfig.get('ssl_chain'):
id_widgets.append((SSL_cert_label, SSL_cert_e)) try:
SSL_identity = paymentrequest.check_ssl_config(self.config)
msg = _('Path to your SSL private key, used to sign BIP70 payment requests.') SSL_error = None
SSL_key_label = HelpLabel(_('SSL private key') + ':', msg) except BaseException as e:
SSL_key = self.config.get('ssl_privkey','') SSL_identity = "error"
SSL_key_e = QLineEdit(SSL_key) SSL_error = str(e)
SSL_key_e.editingFinished.connect(lambda: self.config.set_key('ssl_privkey', str(SSL_key_e.text()))) else:
id_widgets.append((SSL_key_label, SSL_key_e)) 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'] units = ['BTC', 'mBTC', 'bits']
msg = _('Base unit of your wallet.')\ msg = _('Base unit of your wallet.')\

140
lib/paymentrequest.py

@ -119,75 +119,22 @@ class PaymentRequest:
return False return False
def verify_x509(self, paymntreq): def verify_x509(self, paymntreq):
""" verify chain of certificates. The last certificate is the CA"""
if not ca_list: if not ca_list:
self.error = "Trusted certificate authorities list not found" self.error = "Trusted certificate authorities list not found"
return False return False
cert = pb2.X509Certificates() cert = pb2.X509Certificates()
cert.ParseFromString(paymntreq.pki_data) cert.ParseFromString(paymntreq.pki_data)
cert_num = len(cert.certificate) # verify the chain of certificates
x509_chain = [] try:
for i in range(cert_num): x, ca = verify_cert_chain(cert.certificate)
x = x509.X509() except BaseException as e:
x.parseBinary(bytearray(cert.certificate[i])) self.error = str(e)
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"
return False return False
# if the root CA is not supplied, add it to the chain # get requestor name
ca = x509_chain[cert_num-1] self.requestor = x.get_common_name()
if ca.getFingerprint() not in ca_list: if self.requestor.startswith('*.'):
keyID = ca.get_issuer_keyID() self.requestor = self.requestor[2:]
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
# verify the BIP70 signature # verify the BIP70 signature
x = x509_chain[0]
pubkey0 = rsakey.RSAKey(x.modulus, x.exponent) pubkey0 = rsakey.RSAKey(x.modulus, x.exponent)
sig = paymntreq.signature sig = paymntreq.signature
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): def sign_request_with_x509(pr, key_path, cert_path):
import pem import pem
with open(key_path, 'r') as f: with open(key_path, 'r') as f:

Loading…
Cancel
Save