check SSL certificate in config dialog
This commit is contained in:
parent
7b3e1dafd4
commit
a9e74da11c
|
@ -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.')\
|
||||||
|
|
|
@ -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 = []
|
|
||||||
for i in range(cert_num):
|
|
||||||
x = x509.X509()
|
|
||||||
x.parseBinary(bytearray(cert.certificate[i]))
|
|
||||||
x509_chain.append(x)
|
|
||||||
if i == 0:
|
|
||||||
try:
|
try:
|
||||||
x.check_date()
|
x, ca = verify_cert_chain(cert.certificate)
|
||||||
except Exception as e:
|
except BaseException as e:
|
||||||
self.error = str(e)
|
self.error = str(e)
|
||||||
return
|
return False
|
||||||
|
# get requestor name
|
||||||
self.requestor = x.get_common_name()
|
self.requestor = x.get_common_name()
|
||||||
if self.requestor.startswith('*.'):
|
if self.requestor.startswith('*.'):
|
||||||
self.requestor = self.requestor[2:]
|
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
|
|
||||||
# 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
|
|
||||||
# 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…
Reference in New Issue