URI: 
       tadd root certificate to chain if missing. fixes #1137 - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 4fe32d2ad1115907cd62e9aea8d77c608b7643a1
   DIR parent 6f5241302c0278cee1eda873c975594254eaae67
  HTML Author: ThomasV <thomasv@gitorious>
       Date:   Fri, 10 Apr 2015 16:32:16 +0200
       
       add root certificate to chain if missing. fixes #1137
       
       Diffstat:
         M lib/paymentrequest.py               |      84 ++++++++++++++-----------------
         M lib/x509.py                         |      21 +++++++++++++++++++++
       
       2 files changed, 59 insertions(+), 46 deletions(-)
       ---
   DIR diff --git a/lib/paymentrequest.py b/lib/paymentrequest.py
       t@@ -106,23 +106,26 @@ class PaymentRequest:
                except:
                    self.error = "cannot parse payment request"
                    return
       +        self.details = pb2.PaymentDetails()
       +        self.details.ParseFromString(self.data.serialized_payment_details)
       +        for o in self.details.outputs:
       +            addr = transaction.get_address_from_output_script(o.script)[1]
       +            self.outputs.append(('address', addr, o.amount))
       +        self.memo = self.details.memo
       +        self.payment_url = self.details.payment_url
        
        
            def verify(self):
       -
                if not ca_list:
                    self.error = "Trusted certificate authorities list not found"
                    return False
       -
                paymntreq = self.data
                if not paymntreq.signature:
                    self.error = "No signature"
                    return
       -
                cert = pb2.X509Certificates()
                cert.ParseFromString(paymntreq.pki_data)
                cert_num = len(cert.certificate)
       -
                x509_chain = []
                for i in range(cert_num):
                    x = x509.X509()
       t@@ -140,15 +143,39 @@ class PaymentRequest:
                        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]
       +        supplied_CA_fingerprint = ca.getFingerprint()
       +        supplied_CA_names = ca.extract_names()
       +        CA_OU = supplied_CA_names['OU']
       +        x = ca_list.get(supplied_CA_fingerprint)
       +        if x:
       +            x.slow_parse()
       +            names = x.extract_names()
       +            assert names['CN'] == supplied_CA_names['CN']
       +        else:
       +            issuer = ca.get_issuer()
       +            for x in ca_list.values():
       +                try:
       +                    x.slow_parse()
       +                    names = x.extract_names()
       +                except Exception as e:
       +                    util.print_error("cannot parse cert:", e)
       +                    continue
       +                if names.get('CN') == issuer.get('CN'):
       +                    x509_chain.append(x)
       +                    break
       +            else:
       +                self.error = "Supplied CA Not Found in Trusted CA Store."
       +                return False
       +        # verify the chain of signatures
       +        cert_num = len(cert.certificate)
                for i in range(1, cert_num):
                    x = x509_chain[i]
                    prev_x = x509_chain[i-1]
       -
                    algo, sig, data = prev_x.extract_sig()
                    sig = bytearray(sig[5:])
                    pubkey = x.publicKey
       t@@ -166,35 +193,17 @@ class PaymentRequest:
                    else:
                        self.error = "Algorithm not supported"
                        util.print_error(self.error, algo.getComponentByName('algorithm'))
       -                return
       -
       +                return False
                    if not verify:
                        self.error = "Certificate not Signed by Provided CA Certificate Chain"
       -                return
       -
       -        ca = x509_chain[cert_num-1]
       -        supplied_CA_fingerprint = ca.getFingerprint()
       -        supplied_CA_names = ca.extract_names()
       -        CA_OU = supplied_CA_names['OU']
       -
       -        x = ca_list.get(supplied_CA_fingerprint)
       -        if x:
       -            x.slow_parse()
       -            names = x.extract_names()
       -            CA_match = True
       -            if names['CN'] != supplied_CA_names['CN']:
       -                print "ERROR: Trusted CA CN Mismatch; however CA has trusted fingerprint"
       -                print "Payment will continue with manual verification."
       -        else:
       -            CA_match = False
       -
       +                return False
       +        # verify the BIP70 signature
                pubkey0 = x509_chain[0].publicKey
                sig = paymntreq.signature
                paymntreq.signature = ''
                s = paymntreq.SerializeToString()
                sigBytes = bytearray(sig)
                msgBytes = bytearray(s)
       -
                if paymntreq.pki_type == "x509+sha256":
                    hashBytes = bytearray(hashlib.sha256(msgBytes).digest())
                    verify = pubkey0.verify(sigBytes, x509.PREFIX_RSA_SHA256 + hashBytes)
       t@@ -203,28 +212,11 @@ class PaymentRequest:
                else:
                    self.error = "ERROR: Unsupported PKI Type for Message Signature"
                    return False
       -
                if not verify:
                    self.error = "ERROR: Invalid Signature for Payment Request Data"
                    return False
       -
                ### SIG Verified
       -        self.details = pay_det = pb2.PaymentDetails()
       -        self.details.ParseFromString(paymntreq.serialized_payment_details)
       -
       -        for o in pay_det.outputs:
       -            addr = transaction.get_address_from_output_script(o.script)[1]
       -            self.outputs.append( ('address', addr, o.amount) )
       -
       -        self.memo = self.details.memo
       -
       -        if CA_match:
       -            self.status = 'Signed by Trusted CA:\n' + CA_OU
       -        else:
       -            self.status = "Supplied CA Not Found in Trusted CA Store."
       -
       -        self.payment_url = self.details.payment_url
       -
       +        self.status = 'Signed by Trusted CA:\n' + CA_OU
                return True
        
            def has_expired(self):
   DIR diff --git a/lib/x509.py b/lib/x509.py
       t@@ -75,6 +75,27 @@ class X509(tlslite.X509):
                self.subject = self.tbs.getComponentByName('subject')
                self.extensions = self.tbs.getComponentByName('extensions') or []
        
       +    def get_issuer(self):
       +        results = {'CN': None, 'OU': None,}
       +        issuer = self.tbs.getComponentByName('issuer')
       +        # Extract the CommonName(s) from the cert.
       +        for rdnss in issuer:
       +            for rdns in rdnss:
       +                for name in rdns:
       +                    oid = name.getComponentByName('type')
       +                    value = name.getComponentByName('value')
       +
       +                    if oid == COMMON_NAME:
       +                        value = decoder.decode(value, asn1Spec=DirectoryString())[0]
       +                        value = decode_str(value.getComponent())
       +                        results['CN'] = value
       +
       +                    elif oid == OU_NAME:
       +                        value = decoder.decode(value, asn1Spec=DirectoryString())[0]
       +                        value = decode_str(value.getComponent())
       +                        results['OU'] = value
       +        return results
       +
            def extract_names(self):
                results = {'CN': None,
                           'DNS': set(),