# Copyright (c) Microsoft Corporation. All rights reserved.# Licensed under the Apache 2.0 License.importbase64fromhashlibimportsha256fromtypingimportListfromcryptography.x509importCertificatefromcryptography.hazmat.primitivesimporthashesfromcryptography.hazmat.primitives.asymmetricimportec,utils
[docs]defroot(leaf:str,proof:List[dict]):""" Recompute root of Merkle tree from a leaf and a proof of the form: [{"left": digest}, {"right": digest}, ...] """current=bytes.fromhex(leaf)forninproof:if"left"inn:current=sha256(bytes.fromhex(n["left"])+current).digest()else:current=sha256(current+bytes.fromhex(n["right"])).digest()returncurrent.hex()
[docs]defverify(root:str,signature:str,cert:Certificate):""" Verify signature over root of Merkle Tree """sig=base64.b64decode(signature)pk=cert.public_key()assertisinstance(pk,ec.EllipticCurvePublicKey)pk.verify(sig,bytes.fromhex(root),ec.ECDSA(utils.Prehashed(hashes.SHA256())),)
[docs]defcheck_endorsement(endorsee:Certificate,endorser:Certificate):""" Check endorser has endorsed endorsee """digest_algo=endorsee.signature_hash_algorithmassertdigest_algodigester=hashes.Hash(digest_algo)digester.update(endorsee.tbs_certificate_bytes)digest=digester.finalize()endorser_pk=endorser.public_key()assertisinstance(endorser_pk,ec.EllipticCurvePublicKey)endorser_pk.verify(endorsee.signature,digest,ec.ECDSA(utils.Prehashed(digest_algo)))
[docs]defcheck_endorsements(node_cert:Certificate,service_cert:Certificate,endorsements:List[Certificate]):""" Check a node certificate is endorsed by a service certificate, transitively through a list of endorsements. """cert_i=node_certforendorsementinendorsements:check_endorsement(cert_i,endorsement)cert_i=endorsementcheck_endorsement(cert_i,service_cert)