def verify_x509(self, paymntreq): if not ca_list: self.error = "Trusted certificate authorities list not found" return False cert = pb2.X509Certificates() cert.ParseFromString(paymntreq.pki_data) # verify the chain of certificates try: x, ca = verify_cert_chain(cert.certificate) except BaseException as e: traceback.print_exc(file=sys.stderr) self.error = str(e) return False # get requestor name self.requestor = x.get_common_name() if self.requestor.startswith('*.'): self.requestor = self.requestor[2:] # verify the BIP70 signature pubkey0 = rsakey.RSAKey(x.modulus, x.exponent) 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) elif paymntreq.pki_type == "x509+sha1": verify = pubkey0.hashAndVerify(sigBytes, msgBytes) if not verify: self.error = "ERROR: Invalid Signature for Payment Request Data" return False ### SIG Verified self.error = 'Signed by Trusted CA: ' + ca.get_common_name() return True
def make_payment_request(outputs, memo, time, expires, key_path, cert_path): pd = pb2.PaymentDetails() for script, amount in outputs: pd.outputs.add(amount=amount, script=script) pd.time = time pd.expires = expires pd.memo = memo pr = pb2.PaymentRequest() pr.serialized_payment_details = pd.SerializeToString() pr.signature = '' pr = pb2.PaymentRequest() pr.serialized_payment_details = pd.SerializeToString() pr.signature = '' if key_path and cert_path: import tlslite with open(key_path, 'r') as f: rsakey = tlslite.utils.python_rsakey.Python_RSAKey.parsePEM( f.read()) with open(cert_path, 'r') as f: chain = tlslite.X509CertChain() chain.parsePemList(f.read()) certificates = pb2.X509Certificates() certificates.certificate.extend( map(lambda x: str(x.bytes), chain.x509List)) pr.pki_type = 'x509+sha256' pr.pki_data = certificates.SerializeToString() msgBytes = bytearray(pr.SerializeToString()) hashBytes = bytearray(hashlib.sha256(msgBytes).digest()) sig = rsakey.sign(x509.PREFIX_RSA_SHA256 + hashBytes) pr.signature = bytes(sig) return pr.SerializeToString()
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
def sign_request_with_x509(pr, key_path, cert_path): import tlslite with open(key_path, 'r') as f: rsakey = tlslite.utils.python_rsakey.Python_RSAKey.parsePEM(f.read()) with open(cert_path, 'r') as f: chain = tlslite.X509CertChain() chain.parsePemList(f.read()) certificates = pb2.X509Certificates() certificates.certificate.extend(map(lambda x: str(x.bytes), chain.x509List)) pr.pki_type = 'x509+sha256' pr.pki_data = certificates.SerializeToString() msgBytes = bytearray(pr.SerializeToString()) hashBytes = bytearray(hashlib.sha256(msgBytes).digest()) sig = rsakey.sign(x509.PREFIX_RSA_SHA256 + hashBytes) pr.signature = bytes(sig)
def sign_request_with_x509(pr, key_path, cert_path): import pem 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") certificates = pb2.X509Certificates() certificates.certificate.extend(map(str, bList)) pr.pki_type = 'x509+sha256' pr.pki_data = certificates.SerializeToString() msgBytes = bytearray(pr.SerializeToString()) hashBytes = bytearray(hashlib.sha256(msgBytes).digest()) sig = privkey.sign(x509.PREFIX_RSA_SHA256 + hashBytes) pr.signature = bytes(sig)
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
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 = pb2.PaymentRequest() paymntreq.ParseFromString(self.raw) 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() 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" 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 = x.publicKey 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 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) 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.error = 'Signed by Trusted CA: ' + ca.get_common_name() return True