def parse(self, r): try: self.data = pb2.PaymentRequest() self.data.ParseFromString(r) 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 parse(self, r): self.id = bitcoin.sha256(r)[0:16].encode('hex') try: self.data = pb2.PaymentRequest() self.data.ParseFromString(r) except: self.error = "cannot parse payment request" return self.details = pb2.PaymentDetails() self.details.ParseFromString(self.data.serialized_payment_details) self.outputs = [] for o in self.details.outputs: addr = transaction.get_address_from_output_script(o.script)[1] self.outputs.append((TYPE_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 = paymentrequest_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])) x.slow_parse() x509_chain.append(x) if i == 0: try: x.check_date() x.check_name(self.domain) except Exception as e: self.error = str(e) return 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 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 if algo.getComponentByName("algorithm") == x509.ALGO_RSA_SHA1: verify = pubkey.hashAndVerify(sig, data) elif algo.getComponentByName("algorithm") == x509.ALGO_RSA_SHA256: hashBytes = bytearray(hashlib.sha256(data).digest()) prefixBytes = bytearray( [ 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20, ] ) verify = pubkey.verify(sig, prefixBytes + hashBytes) else: self.error = "Algorithm not supported" util.print_error(self.error, algo.getComponentByName("algorithm")) return 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 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()) prefixBytes = bytearray( [ 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20, ] ) verify = pubkey0.verify(sigBytes, prefixBytes + hashBytes) elif paymntreq.pki_type == "x509+sha1": verify = pubkey0.hashAndVerify(sigBytes, msgBytes) 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 = paymentrequest_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 return True
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 = paymentrequest_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])) x.slow_parse() x509_chain.append(x) if i == 0: try: x.check_date() x.check_name(self.domain) except Exception as e: self.error = str(e) return 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 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 if algo.getComponentByName('algorithm') == x509.ALGO_RSA_SHA1: verify = pubkey.hashAndVerify(sig, data) elif algo.getComponentByName('algorithm') == x509.ALGO_RSA_SHA256: hashBytes = bytearray(hashlib.sha256(data).digest()) prefixBytes = bytearray([ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 ]) verify = pubkey.verify(sig, prefixBytes + hashBytes) else: self.error = "Algorithm not supported" util.print_error(self.error, algo.getComponentByName('algorithm')) return 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 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()) prefixBytes = bytearray([ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 ]) verify = pubkey0.verify(sigBytes, prefixBytes + hashBytes) elif paymntreq.pki_type == "x509+sha1": verify = pubkey0.hashAndVerify(sigBytes, msgBytes) 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 = paymentrequest_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 return True
class PaymentRequest: def __init__(self, url): self.url = url self.outputs = [] self.error = "" def get_amount(self): return sum(map(lambda x: x[1], self.outputs)) def verify(self): u = urlparse.urlparse(self.url) self.domain = u.netloc try: connection = httplib.HTTPConnection( u.netloc) if u.scheme == 'http' else httplib.HTTPSConnection( u.netloc) connection.request("GET", u.geturl(), headers=REQUEST_HEADERS) resp = connection.getresponse() except: self.error = "cannot read url" return paymntreq = paymentrequest_pb2.PaymentRequest() try: r = resp.read() paymntreq.ParseFromString(r) except: self.error = "cannot parse payment request" return sig = paymntreq.signature if not sig: self.error = "No signature" return cert = paymentrequest_pb2.X509Certificates() cert.ParseFromString(paymntreq.pki_data) cert_num = len(cert.certificate) x509_1 = X509.load_cert_der_string(cert.certificate[0]) if self.domain != x509_1.get_subject().CN: validcert = False try: SANs = x509_1.get_ext("subjectAltName").get_value().split(",") for s in SANs: s = s.strip() if s.startswith("DNS:") and s[4:] == self.domain: validcert = True print "Match SAN DNS" elif s.startswith("IP:") and s[3:] == self.domain: validcert = True print "Match SAN IP" elif s.startswith("email:") and s[6:] == self.domain: validcert = True print "Match SAN email" except Exception, e: print "ERROR: No SAN data" if not validcert: ###TODO: check for wildcards self.error = "ERROR: Certificate Subject Domain Mismatch and SAN Mismatch" return x509 = [] CA_OU = '' if cert_num > 1: for i in range(cert_num - 1): x509.append(X509.load_cert_der_string(cert.certificate[i + 1])) if x509[i].check_ca() == 0: self.error = "ERROR: Supplied CA Certificate Error" return for i in range(cert_num - 1): if i == 0: if x509_1.verify(x509[i].get_pubkey()) != 1: self.error = "ERROR: Certificate not Signed by Provided CA Certificate Chain" return else: if x509[i - 1].verify(x509[i].get_pubkey()) != 1: self.error = "ERROR: CA Certificate not Signed by Provided CA Certificate Chain" return supplied_CA_fingerprint = x509[cert_num - 2].get_fingerprint() supplied_CA_CN = x509[cert_num - 2].get_subject().CN CA_match = False x = ca_list.get(supplied_CA_fingerprint) if x: CA_OU = x.get_subject().OU CA_match = True if x.get_subject().CN != supplied_CA_CN: print "ERROR: Trusted CA CN Mismatch; however CA has trusted fingerprint" print "Payment will continue with manual verification." else: print "ERROR: Supplied CA Not Found in Trusted CA Store." print "Payment will continue with manual verification." else: self.error = "ERROR: CA Certificate Chain Not Provided by Payment Processor" return False paymntreq.signature = '' s = paymntreq.SerializeToString() pubkey_1 = x509_1.get_pubkey() if paymntreq.pki_type == "x509+sha256": pubkey_1.reset_context(md="sha256") elif paymntreq.pki_type == "x509+sha1": pubkey_1.reset_context(md="sha1") else: self.error = "ERROR: Unsupported PKI Type for Message Signature" return False pubkey_1.verify_init() pubkey_1.verify_update(s) if pubkey_1.verify_final(sig) != 1: self.error = "ERROR: Invalid Signature for Payment Request Data" return False ### SIG Verified self.payment_details = pay_det = paymentrequest_pb2.PaymentDetails() pay_det.ParseFromString(paymntreq.serialized_payment_details) if pay_det.expires and pay_det.expires < int(time.time()): self.error = "ERROR: Payment Request has Expired." return False for o in pay_det.outputs: addr = transaction.get_address_from_output_script(o.script)[1] self.outputs.append((addr, o.amount)) self.memo = pay_det.memo if CA_match: print 'Signed By Trusted CA: ', CA_OU print "payment url", pay_det.payment_url return True
class PaymentRequest: def __init__(self, config): self.config = config self.outputs = [] self.error = "" self.dir_path = os.path.join(self.config.path, 'requests') if not os.path.exists(self.dir_path): os.mkdir(self.dir_path) def read(self, url): self.url = url u = urlparse.urlparse(url) self.domain = u.netloc try: connection = httplib.HTTPConnection( u.netloc) if u.scheme == 'http' else httplib.HTTPSConnection( u.netloc) connection.request("GET", u.geturl(), headers=REQUEST_HEADERS) response = connection.getresponse() except: self.error = "cannot read url" return try: r = response.read() except: self.error = "cannot read" return self.id = bitcoin.sha256(r)[0:16].encode('hex') filename = os.path.join(self.dir_path, self.id) with open(filename, 'w') as f: f.write(r) return self.parse(r) def get_status(self): if self.error: return self.error else: return self.status def read_file(self, key): filename = os.path.join(self.dir_path, key) with open(filename, 'r') as f: r = f.read() self.parse(r) def parse(self, r): try: self.data = paymentrequest_pb2.PaymentRequest() self.data.ParseFromString(r) except: self.error = "cannot parse payment request" return def verify(self): try: from M2Crypto import X509 except: self.error = "cannot import M2Crypto" return False if not ca_list: self.error = "Trusted certificate authorities list not found" return False paymntreq = self.data sig = paymntreq.signature if not sig: self.error = "No signature" return cert = paymentrequest_pb2.X509Certificates() cert.ParseFromString(paymntreq.pki_data) cert_num = len(cert.certificate) x509_1 = X509.load_cert_der_string(cert.certificate[0]) if self.domain != x509_1.get_subject().CN: validcert = False try: SANs = x509_1.get_ext("subjectAltName").get_value().split(",") for s in SANs: s = s.strip() if s.startswith("DNS:") and s[4:] == self.domain: validcert = True print "Match SAN DNS" elif s.startswith("IP:") and s[3:] == self.domain: validcert = True print "Match SAN IP" elif s.startswith("email:") and s[6:] == self.domain: validcert = True print "Match SAN email" except Exception, e: print "ERROR: No SAN data" if not validcert: ###TODO: check for wildcards self.error = "ERROR: Certificate Subject Domain Mismatch and SAN Mismatch" return x509 = [] CA_OU = '' if cert_num > 1: for i in range(cert_num - 1): x509.append(X509.load_cert_der_string(cert.certificate[i + 1])) if x509[i].check_ca() == 0: self.error = "ERROR: Supplied CA Certificate Error" return for i in range(cert_num - 1): if i == 0: if x509_1.verify(x509[i].get_pubkey()) != 1: self.error = "ERROR: Certificate not Signed by Provided CA Certificate Chain" return else: if x509[i - 1].verify(x509[i].get_pubkey()) != 1: self.error = "ERROR: CA Certificate not Signed by Provided CA Certificate Chain" return supplied_CA_fingerprint = x509[cert_num - 2].get_fingerprint() supplied_CA_CN = x509[cert_num - 2].get_subject().CN CA_match = False x = ca_list.get(supplied_CA_fingerprint) if x: CA_OU = x.get_subject().OU CA_match = True if x.get_subject().CN != supplied_CA_CN: print "ERROR: Trusted CA CN Mismatch; however CA has trusted fingerprint" print "Payment will continue with manual verification." else: print "ERROR: Supplied CA Not Found in Trusted CA Store." print "Payment will continue with manual verification." else: self.error = "ERROR: CA Certificate Chain Not Provided by Payment Processor" return False paymntreq.signature = '' s = paymntreq.SerializeToString() pubkey_1 = x509_1.get_pubkey() if paymntreq.pki_type == "x509+sha256": pubkey_1.reset_context(md="sha256") elif paymntreq.pki_type == "x509+sha1": pubkey_1.reset_context(md="sha1") else: self.error = "ERROR: Unsupported PKI Type for Message Signature" return False pubkey_1.verify_init() pubkey_1.verify_update(s) if pubkey_1.verify_final(sig) != 1: self.error = "ERROR: Invalid Signature for Payment Request Data" return False ### SIG Verified self.details = pay_det = paymentrequest_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((addr, o.amount)) self.memo = self.details.memo if CA_match: self.status = 'Signed by Trusted CA:\n' + CA_OU self.payment_url = self.details.payment_url if self.has_expired(): self.error = "ERROR: Payment Request has Expired." return False return True