def revoke_creds_cmd(txid, cred_hash1, cred_hash2=None): bstring = (_create_header() + operators['op_revoke_creds'] + utils.hex_to_bytes(txid) + utils.ripemd160(cred_hash1)) if cred_hash2: bstring += utils.ripemd160(cred_hash2) return bstring
def validate_certificate(cert, issuer_identifier, testnet, blockchain_services): filename = os.path.basename(cert) tmp_filename = '__' + filename shutil.copy(cert, tmp_filename) issuer_address = get_issuer_address(tmp_filename) proof = get_and_remove_chainpoint_proof(tmp_filename) if proof == None: os.remove(tmp_filename) return False, "no chainpoint_proof in metadata" # get the hash after removing the metadata filehash = '' with open(tmp_filename, 'rb') as pdf_file: filehash = hashlib.sha256(pdf_file.read()).hexdigest() # instantiate chainpoint object cp = ChainPointV2() txid = cp.get_txid_from_receipt(proof) # make request to get txs regarding this address # issuance is the first element of data_before_issuance data_before_issuance, data_after_issuance = \ network_utils.get_all_op_return_hexes(issuer_address, txid, blockchain_services, testnet) # validate receipt valid, reason = cp.validate_receipt(proof, data_before_issuance[0], filehash, issuer_identifier, testnet) # display error except when the certificate expired; this is because we want # revoked certificate error to be displayed before cert expired error # TODO clean hard-coded reason if not valid and not reason.startswith("certificate expired"): return False, reason # set bitcoin network (required for addr->pkh in revoke address) if testnet: setup('testnet') else: setup('mainnet') # check if cert's issuance is after a revoke address cmd on that address # and if yes then the issuance is invalid (address was revoked) # we check before checking for cert revocations since if the issuance was # after an address revocation it should show that as an invalid reason # 0 index is the actual issuance -- ignore it for i in range(len(data_before_issuance))[1:]: cred_dict = cred_protocol.parse_op_return_hex(data_before_issuance[i]) if cred_dict: if cred_dict['cmd'] == cred_protocol.hex_op('op_revoke_address'): issuer_pkh = P2pkhAddress(issuer_address).to_hash160() if issuer_pkh == cred_dict['data']['pkh']: return False, "address was revoked" # check if cert or batch was revoked from oldest to newest for op_return in reversed(data_after_issuance): cred_dict = cred_protocol.parse_op_return_hex(op_return) if cred_dict: if cred_dict['cmd'] == cred_protocol.hex_op('op_revoke_batch'): if txid == cred_dict['data']['txid']: return False, "batch was revoked" elif cred_dict['cmd'] == cred_protocol.hex_op('op_revoke_creds'): if txid == cred_dict['data']['txid']: # compare the certificate hash bytes filehash_bytes = utils.hex_to_bytes(filehash) ripemd_filehash = utils.ripemd160(filehash_bytes) ripemd_hex = utils.bytes_to_hex(ripemd_filehash) if ripemd_hex == cred_dict['data']['hashes'][0]: return False, "cert hash was revoked" if len(cred_dict['data']['hashes']) > 1: if ripemd_hex == cred_dict['data']['hashes'][1]: return False, "cert hash was revoked" elif cred_dict['cmd'] == cred_protocol.hex_op('op_revoke_address'): # if address revocation is found stop looking since all other # revocations will be invalid issuer_pkh = P2pkhAddress(issuer_address).to_hash160() if issuer_pkh == cred_dict['data']['pkh']: break # if not revoked but not valid this means that it was expired; now that we # checked for revocations we can show the expiry error if not valid: return False, reason # now that the issuer (anchoring) was validated validate the certificate # with the owner's public key (vpdf v2) # get owner and owner_proof removing the latter owner, owner_proof = get_owner_and_remove_owner_proof(tmp_filename) if owner: # get public key pk = PublicKey.from_hex(owner['pk']) # get file hash sha256_hash = None with open(tmp_filename, 'rb') as pdf: sha256_hash = hashlib.sha256(pdf.read()).hexdigest() # cleanup now that we got original filehash os.remove(tmp_filename) # finally check if owner signature is valid #print(pk.get_address().to_string(), pk.to_hex(), sha256_hash, owner_proof) try: if (pk.verify(owner_proof, sha256_hash)): pass except Exception: #BadSignatureError: return False, 'owner signature could not be validated' # in a valid credential the reason could contain an expiry date return True, reason
def validate_certificate(cert, issuer_identifier, testnet): valid_certificate = False filename = os.path.basename(cert) tmp_filename = '__' + filename shutil.copy(cert, tmp_filename) proof = get_and_remove_chainpoint_proof(tmp_filename) if proof == None: os.remove(tmp_filename) return False # get the hash after removing the metadata filehash = '' with open(tmp_filename, 'rb') as pdf_file: filehash = hashlib.sha256(pdf_file.read()).hexdigest() # cleanup now that we got original filehash os.remove(tmp_filename) # validate receipt cp = ChainPointV2() if cp.validate_receipt(proof, filehash, issuer_identifier, testnet): valid_certificate = True else: return False # blockchain receipt is valid but we need to also check if the certificate # was revoked after issuing txid = proof['anchors'][0]['sourceId'] data_before_issuance, data_after_issuance = network_utils.get_all_op_return_hexes( txid, testnet) # check if cert or batch was revoked from oldest to newest; if a valid # revoke address is found further commands are ignored # (TODO: REVOKE ADDRESS CMD for op_return in reversed(data_after_issuance): cred_dict = cred_protocol.parse_op_return_hex(op_return) if cred_dict: if cred_dict['cmd'] == cred_protocol.hex_op('op_revoke_batch'): if txid == cred_dict['data']['txid']: return False # log: cert invalid - batch was revoked elif cred_dict['cmd'] == cred_protocol.hex_op('op_revoke_creds'): if txid == cred_dict['data']['txid']: # compare the certificate hash bytes filehash_bytes = utils.hex_to_bytes(filehash) ripemd_filehash = utils.ripemd160(filehash_bytes) ripemd_hex = utils.bytes_to_hex(ripemd_filehash) if ripemd_hex == cred_dict['data']['hashes'][0]: return False # log: cert invalid - cert was revoked if len(cred_dict['data']['hashes']) > 1: if ripemd_hex == cred_dict['data']['hashes'][1]: return False # log: cert invalid - cert was revoked elif cred_dict['cmd'] == cred_protocol.hex_op('op_revoke_address'): # if correct address and valid revoke then stop checking other # revokes and break loop (TODO: REVOKE ADDRESS CMD) print("TODO: revoke address not implemented yet!") # check if cert's issuance is after a revoke address cmd on that address # TODO: REVOKE ADDRESS CMD # check the data_before_issuance... and return False!! return True