Пример #1
0
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