def test_check_invalid_digit(self):
        priv_chars = list(KEY1_PRIV_HEX)
        priv_chars[3] = 'i'
        with self.assertRaises(ParseError):
            Secp256k1PrivateKey.from_hex(''.join(priv_chars))

        pub_chars = list(KEY1_PUB_HEX)
        pub_chars[3] = 'i'
        with self.assertRaises(ParseError):
            Secp256k1PublicKey.from_hex(''.join(pub_chars))
 def test_key_signature_validation(self):
     signature, message, pubkey = self.test_key_signing()
     public_key = Secp256k1PublicKey.from_hex(pubkey)
     context = sawtooth_signing.create_context("secp256k1")
     self.assertTrue(context.verify(signature, bytes(message, "utf8"), public_key))
     self.assertFalse(
         context.verify(signature, bytes(message + "foo", "utf8"), public_key)
     )
     other = Secp256k1PublicKey.from_hex(Key().public_key)
     self.assertFalse(context.verify(signature, bytes(message, "utf8"), other))
def is_valid_batch(batch):
    # validate batch signature
    header = BatchHeader()
    header.ParseFromString(batch.header)

    context = create_context('secp256k1')
    public_key = Secp256k1PublicKey.from_hex(header.signer_public_key)
    if not context.verify(batch.header_signature,
                          batch.header,
                          public_key):
        LOGGER.debug("batch failed signature validation: %s",
                     batch.header_signature)
        return False

    # validate all transactions in batch
    for txn in batch.transactions:
        if not is_valid_transaction(txn):
            return False

        txn_header = TransactionHeader()
        txn_header.ParseFromString(txn.header)
        if txn_header.batcher_public_key != header.signer_public_key:
            LOGGER.debug("txn batcher public_key does not match signer"
                         "public_key for batch: %s txn: %s",
                         batch.header_signature,
                         txn.header_signature)
            return False

    return True
Beispiel #4
0
 def verify(self, signature, message, public_key=None):
     """Verifies a message was signed by this Key"""
     if public_key is None:
         public_key = self._public_key
     elif isinstance(public_key, str):
         public_key = Secp256k1PublicKey.from_hex(public_key)
     return self._context.verify(signature, message, public_key)
Beispiel #5
0
def verify_nonce(nonce, checksum, message, hex_public_key):
    ##message is hex encoded
    message = binascii.unhexlify(message)
    public_key = Secp256k1PublicKey.from_hex(hex_public_key)
    unserialized = public_key.secp256k1_public_key.ecdsa_deserialize(message)
    result = public_key.secp256k1_public_key.ecdsa_verify(str(nonce).encode(), unserialized)
    return result
Beispiel #6
0
def is_valid_batch(batch):
    # validate batch signature
    header = BatchHeader()
    header.ParseFromString(batch.header)

    context = create_context('secp256k1')
    public_key = Secp256k1PublicKey.from_hex(header.signer_public_key)
    if not context.verify(batch.header_signature, batch.header, public_key):
        LOGGER.debug("batch failed signature validation: %s",
                     batch.header_signature)
        return False

    # validate all transactions in batch
    for txn in batch.transactions:
        if not is_valid_transaction(txn):
            return False

        txn_header = TransactionHeader()
        txn_header.ParseFromString(txn.header)
        if txn_header.batcher_public_key != header.signer_public_key:
            LOGGER.debug(
                "txn batcher public_key does not match signer"
                "public_key for batch: %s txn: %s", batch.header_signature,
                txn.header_signature)
            return False

    return True
Beispiel #7
0
 def assertIsPublicKeyBytes(self, key):
     """Sanity checks a public key in bytes"""
     self.assertIsInstance(key, bytes)
     self.assertEqual(len(key), PUBLIC_KEY_LENGTH)
     key = Secp256k1PublicKey.from_hex(str(binascii.hexlify(key), "ascii"))
     self.assertIsPublicKeySecp256k1(key)
     return key
Beispiel #8
0
 def assertIsPublicKeyHex(self, key):
     """Sanity checks a hexidecimal string public key"""
     self.assertIsInstance(key, str)
     self.assertTrue(PUBLIC_KEY_PATTERN.match(key))
     key = Secp256k1PublicKey.from_hex(key)
     self.assertIsPublicKeySecp256k1(key)
     return key
def do_test_verification():
    context = create_context("secp256k1")
    factory = CryptoFactory(context)
    pub_key1 = Secp256k1PublicKey.from_hex(KEY1_PUB_HEX)
    context.verify(signature=MSG1_KEY1_SIG,
                   message=MSG1.encode(),
                   public_key=pub_key1)
Beispiel #10
0
def verify_signature(message, signature, public_key):
    try:
        context = create_context("secp256k1")
        pubkey = Secp256k1PublicKey.from_hex(public_key)
        result = context.verify(signature,message.encode(),pubkey)
        return result 
    except Exception:
        return False
    def test_hex_key(self):
        priv_key = Secp256k1PrivateKey.from_hex(KEY1_PRIV_HEX)
        self.assertEqual(priv_key.get_algorithm_name(), "secp256k1")
        self.assertEqual(priv_key.as_hex(), KEY1_PRIV_HEX)

        pub_key = Secp256k1PublicKey.from_hex(KEY1_PUB_HEX)
        self.assertEqual(pub_key.get_algorithm_name(), "secp256k1")
        self.assertEqual(pub_key.as_hex(), KEY1_PUB_HEX)
    def test_verification(self):
        context = create_context("secp256k1")
        self.assertEqual(context.get_algorithm_name(), "secp256k1")

        pub_key1 = Secp256k1PublicKey.from_hex(KEY1_PUB_HEX)
        self.assertEqual(pub_key1.get_algorithm_name(), "secp256k1")
        self.assertEqual(pub_key1.as_hex(), KEY1_PUB_HEX)

        result = context.verify(MSG1_KEY1_SIG, MSG1.encode(), pub_key1)
        self.assertEqual(result, True)
    def test_verification_error(self):
        context = create_context("secp256k1")
        self.assertEqual(context.get_algorithm_name(), "secp256k1")

        pub_key1 = Secp256k1PublicKey.from_hex(KEY1_PUB_HEX)
        self.assertEqual(pub_key1.get_algorithm_name(), "secp256k1")
        self.assertEqual(pub_key1.as_hex(), KEY1_PUB_HEX)

        # This signature doesn't match for MSG1/KEY1
        result = context.verify(MSG2_KEY2_SIG, MSG1.encode(), pub_key1)
        self.assertEqual(result, False)
    def verify_wait_certificate(cls, certificate, poet_public_key):
        # Since the signing module uses a hex-encoded string as the canonical
        # format for public keys and we should be handed a public key that was
        # part of signup information created by us, don't bother decoding
        # the public key.
        try:
            poet_public_key = Secp256k1PublicKey.from_hex(poet_public_key)
        except ParseError:
            raise \
                ValueError(
                    'Invalid signup data. Badly formatted poet key(s).')

        if not \
            cls._context.verify(
                certificate.signature,
                certificate.serialize().encode(),
                poet_public_key):
            raise ValueError('Wait certificate signature does not match')
    def verify_wait_certificate(cls, certificate, poet_public_key):
        # Since the signing module uses a hex-encoded string as the canonical
        # format for public keys and we should be handed a public key that was
        # part of signup information created by us, don't bother decoding
        # the public key.
        try:
            poet_public_key = Secp256k1PublicKey.from_hex(poet_public_key)
        except ParseError:
            raise \
                ValueError(
                    'Invalid signup data. Badly formatted poet key(s).')

        if not \
            cls._context.verify(
                certificate.signature,
                certificate.serialize().encode(),
                poet_public_key):
            raise ValueError('Wait certificate signature does not match')
Beispiel #16
0
    def __init__(self, private_key=None, public_key=None):
        """
        Key() -- generates a new key
        Key(private_key:str) -- Uses the private key passed
        """
        self._context = create_context(ELLIPTIC_CURVE_ALGORITHM)

        if private_key is None and public_key is None:
            private_key = Secp256k1PrivateKey.new_random()
        if isinstance(private_key, str):
            private_key = Secp256k1PrivateKey.from_hex(private_key)
        if isinstance(public_key, str):
            public_key = Secp256k1PublicKey.from_hex(public_key)
        if public_key is None and private_key is not None:
            public_key = self._context.get_public_key(private_key)

        self._public_key = public_key
        self._private_key = private_key
Beispiel #17
0
def is_valid_block(block):
    # validate block signature
    header = BlockHeader()
    header.ParseFromString(block.header)

    context = create_context('secp256k1')
    public_key = Secp256k1PublicKey.from_hex(header.signer_public_key)
    if not context.verify(block.header_signature, block.header, public_key):
        LOGGER.debug("block failed signature validation: %s",
                     block.header_signature)
        return False

    # validate all batches in block. These are not all batches in the
    # batch_ids stored in the block header, only those sent with the block.
    if not all(map(is_valid_batch, block.batches)):
        return False

    return True
def is_valid_block(block):
    # validate block signature
    header = BlockHeader()
    header.ParseFromString(block.header)

    context = create_context('secp256k1')
    public_key = Secp256k1PublicKey.from_hex(header.signer_public_key)
    if not context.verify(block.header_signature,
                          block.header,
                          public_key):
        LOGGER.debug("block failed signature validation: %s",
                     block.header_signature)
        return False

    # validate all batches in block. These are not all batches in the
    # batch_ids stored in the block header, only those sent with the block.
    if not all(map(is_valid_batch, block.batches)):
        return False

    return True
def ecdsa_signature_verify(public_key, signature, raw_message):
    secp_public = Secp256k1PublicKey.from_hex(public_key)
    #unhexlify signature

    try:
        signature = binascii.unhexlify(signature)
    except Exception as e:
        logging.error("Signatures are not in valid hex format")
        raise ApiInternalError(e)

    unserialized = secp_public.secp256k1_public_key.ecdsa_deserialize(signature)


    if isinstance(raw_message, int):
        raw_message = str(raw_message)

    if isinstance(raw_message, str):
        raw_message = raw_message.encode()

    return secp_public.secp256k1_public_key.ecdsa_verify(raw_message, unserialized)
Beispiel #20
0
def is_valid_transaction(txn):
    # validate transactions signature
    header = TransactionHeader()
    header.ParseFromString(txn.header)

    context = create_context('secp256k1')
    public_key = Secp256k1PublicKey.from_hex(header.signer_public_key)
    if not context.verify(txn.header_signature, txn.header, public_key):
        LOGGER.debug("transaction signature invalid for txn: %s",
                     txn.header_signature)
        return False

    # verify the payload field matches the header
    txn_payload_sha512 = hashlib.sha512(txn.payload).hexdigest()
    if txn_payload_sha512 != header.payload_sha512:
        LOGGER.debug(
            "payload doesn't match payload_sha512 of the header"
            "for txn: %s", txn.header_signature)
        return False

    return True
def is_valid_transaction(txn):
    # validate transactions signature
    header = TransactionHeader()
    header.ParseFromString(txn.header)

    context = create_context('secp256k1')
    public_key = Secp256k1PublicKey.from_hex(header.signer_public_key)
    if not context.verify(txn.header_signature,
                          txn.header,
                          public_key):
        LOGGER.debug("transaction signature invalid for txn: %s",
                     txn.header_signature)
        return False

    # verify the payload field matches the header
    txn_payload_sha512 = hashlib.sha512(txn.payload).hexdigest()
    if txn_payload_sha512 != header.payload_sha512:
        LOGGER.debug("payload doesn't match payload_sha512 of the header"
                     "for txn: %s", txn.header_signature)
        return False

    return True
    def _store_certificate(self, context, signer_pubkey, transaction_payload):
        address = self.make_address_from_data(transaction_payload.certificate_raw)
        data = get_data(context, CertificateStorage, address)
        if data:
            raise InvalidTransaction('This certificate is already registered.')

        certificate = x509.load_der_x509_certificate(bytes.fromhex(transaction_payload.certificate_raw),
                                                     default_backend())

        if transaction_payload.cert_signer_public_key:
            cert_signer_pubkey = load_pem_public_key(transaction_payload.cert_signer_public_key.encode('utf-8'),
                                                     backend=default_backend())
        else:
            cert_signer_pubkey = certificate.public_key()

        try:
            cert_signer_pubkey.verify(bytes.fromhex(transaction_payload.signature_crt),
                                      bytes.fromhex(transaction_payload.signature_rem),
                                      padding.PSS(mgf=padding.MGF1(hashes.SHA256()),
                                                  salt_length=padding.PSS.MAX_LENGTH),
                                      hashes.SHA256())
        except InvalidSignature:
            raise InvalidTransaction('signature_crt mismatch')

        crt_hash = hashlib.sha512(transaction_payload.certificate_raw.encode('utf-8')).hexdigest().encode('utf-8')
        sawtooth_signing_ctx = Secp256k1Context()
        sawtooth_signing_pubkey = Secp256k1PublicKey.from_hex(signer_pubkey)
        sawtooth_signing_check_res = \
            sawtooth_signing_ctx.verify(transaction_payload.signature_rem,
                                        crt_hash,
                                        sawtooth_signing_pubkey)
        if not sawtooth_signing_check_res:
            raise InvalidTransaction('signature_rem mismatch with signer key {}'.format(signer_pubkey))

        subject = certificate.subject
        issuer = certificate.issuer

        organization = issuer.get_attributes_for_oid(NameOID.ORGANIZATION_NAME)[0].value
        uid = issuer.get_attributes_for_oid(NameOID.USER_ID)[0].value
        valid_from = certificate.not_valid_before
        valid_until = certificate.not_valid_after

        if organization != CERT_ORGANIZATION:
            raise InvalidTransaction('The organization name should be set to REMME. The actual name is {}'
                                     .format(organization))
        if uid != signer_pubkey:
            raise InvalidTransaction('The certificate should be sent by its signer. Certificate signed by {}. '
                                     'Transaction sent by {}.'.format(uid, signer_pubkey))

        if valid_until - valid_from > CERT_MAX_VALIDITY:
            raise InvalidTransaction('The certificate validity exceeds the maximum value.')

        fingerprint = certificate.fingerprint(hashes.SHA512()).hex()[:64]
        data = CertificateStorage()
        data.hash = fingerprint
        data.owner = signer_pubkey
        data.revoked = False

        account_address, account = TokenHandler.get_account_by_pub_key(context, signer_pubkey)
        if account.balance < CERT_STORE_PRICE:
            raise InvalidTransaction('Not enough tokens to register a new certificate. Current balance: {}'
                                     .format(account.balance))
        account.balance -= CERT_STORE_PRICE

        LOGGER.info('Registered a new certificate on address {}. Fingerprint: {}'.format(address, fingerprint))

        return {address: data,
                account_address: account}
Beispiel #23
0
    def handle(self, connection_id, message_content):
        """
        When the validator receives an AuthorizationChallengeSubmit message, it
        will verify the public key against the signature. If the public key is
        verified, the requested roles will be checked against the stored roles
        to see if the public key is included in the policy. If the node’s
        response is accepted, the node’s public key will be stored and the
        requester may start sending messages for the approved roles.

        If the requester wanted a role that is either not available on the
        endpoint, the requester does not have access to one of the roles
        requested, or the previous message was not an
        AuthorizationChallengeRequest, the challenge will be rejected and the
        connection will be closed.
        """
        if self._network.get_connection_status(connection_id) != \
                ConnectionStatus.AUTH_CHALLENGE_REQUEST:
            LOGGER.debug(
                "Connection's previous message was not a"
                " AuthorizationChallengeRequest, Remove connection to"
                "%s", connection_id)
            return AuthorizationChallengeSubmitHandler \
                ._network_violation_result()

        auth_challenge_submit = AuthorizationChallengeSubmit()
        auth_challenge_submit.ParseFromString(message_content)

        try:
            payload = self._challenge_payload_cache[connection_id]
        except KeyError:
            LOGGER.debug(
                "Connection's challenge payload expired before a"
                "response was received. %s", connection_id)
            return AuthorizationChallengeSubmitHandler \
                ._network_violation_result()

        context = create_context('secp256k1')
        try:
            public_key = Secp256k1PublicKey.from_hex(
                auth_challenge_submit.public_key)
        except ParseError:
            LOGGER.warning(
                'Authorization Challenge Request cannot be '
                'verified. Invalid public key %s',
                auth_challenge_submit.public_key)
            return AuthorizationChallengeSubmitHandler \
                ._network_violation_result()

        if not context.verify(auth_challenge_submit.signature, payload,
                              public_key):
            LOGGER.warning(
                "Signature was not able to be verifed. Remove "
                "connection to %s", connection_id)
            return AuthorizationChallengeSubmitHandler \
                ._network_violation_result()

        roles = self._network.roles
        for role in auth_challenge_submit.roles:
            if role == RoleType.Value("NETWORK") or role == \
                    RoleType.Value("ALL"):
                permitted = False
                if "network" in roles:
                    permitted = self._permission_verifier.check_network_role(
                        auth_challenge_submit.public_key)
                if not permitted:
                    return AuthorizationChallengeSubmitHandler \
                            ._network_violation_result()

        self._network.update_connection_public_key(
            connection_id, auth_challenge_submit.public_key)

        if RoleType.Value("NETWORK") in auth_challenge_submit.roles:
            # Need to send ConnectionRequest to authorize ourself with the
            # connection if they initialized the connection
            try:
                is_outbound_connection = self._network.is_outbound_connection(
                    connection_id)
            except KeyError:
                # Connection has gone away, drop message
                return HandlerResult(HandlerStatus.DROP)

            if not is_outbound_connection:
                self._network.send_connect_request(connection_id)
            else:
                # If this is an outbound connection, authorization is complete
                # for both connections and peering/topology build out can
                # begin.
                self._gossip.connect_success(connection_id)

        auth_challenge_result = AuthorizationChallengeResult(
            roles=[RoleType.Value("NETWORK")])

        LOGGER.debug("Connection: %s is approved", connection_id)
        self._network.update_connection_status(connection_id,
                                               ConnectionStatus.CONNECTED)
        return HandlerResult(
            HandlerStatus.RETURN,
            message_out=auth_challenge_result,
            message_type=validator_pb2.Message.AUTHORIZATION_CHALLENGE_RESULT)
Beispiel #24
0
def _check_signature(obj, signature, sender_key_str):
    publicKey = Secp256k1PublicKey.from_hex(sender_key_str)
    token_serialized = str(cbor.dumps(obj, sort_keys=True)).encode('utf-8')
    if not create_context('secp256k1').verify(signature, token_serialized,
                                              publicKey):
        raise InvalidTransaction('Invalid signature.')
Beispiel #25
0
    def _store_public_key_for_other(self, context, signer_pubkey, transaction_payload):
        """
        Store public key for other account.

        The transaction for account which want to pay for other account public keys storing.

        A first account -> send payload -> A second account -> send transaction with first account's public key,
        but sign and pay for storing on own -> Remme-core.

        So Remme core charges tokens from a second account, but store a first account's public key.
        Public key owner here is a first account.

        Arguments:
            context (sawtooth_sdk.processor.context): context to store updated state (blockchain data).
            signer_pubkey: transaction sender public key.
            transaction_payload (pub_key_pb2.NewPubKeyStoreAndPayPayload): payload for storing public key for other.
        """
        new_public_key_payload = transaction_payload.pub_key_payload

        owner_public_key_as_bytes = transaction_payload.owner_public_key
        owner_public_key_as_hex = owner_public_key_as_bytes.hex()

        owner_secp256k1_public_key = Secp256k1PublicKey.from_hex(owner_public_key_as_hex)

        is_owner_public_key_payload_signature_valid = Secp256k1Context().verify(
            signature=transaction_payload.signature_by_owner.hex(),
            message=new_public_key_payload.SerializeToString(),
            public_key=owner_secp256k1_public_key,
        )
        if not is_owner_public_key_payload_signature_valid:
            raise InvalidTransaction('Public key owner\'s signature is invalid.')

        processor = self._get_public_key_processor(transaction_payload=transaction_payload.pub_key_payload)

        if not processor.verify():
            raise InvalidTransaction('Payed public key has invalid signature.')

        public_key = processor.get_public_key()
        public_key_to_store_address = self.make_address_from_data(public_key)

        public_key_to_store_owner_address = AccountHandler().make_address_from_data(owner_public_key_as_hex)
        payer_for_storing_address = AccountHandler().make_address_from_data(signer_pubkey)

        public_key_information, public_key_to_store_owner_account, payer_for_storing_account = get_multiple_data(context, [
            (public_key_to_store_address, PubKeyStorage),
            (public_key_to_store_owner_address, Account),
            (payer_for_storing_address, Account),
        ])

        if public_key_information:
            raise InvalidTransaction('This public key is already registered.')

        if public_key_to_store_owner_account is None:
            public_key_to_store_owner_account = Account()

        if payer_for_storing_account is None:
            payer_for_storing_account = Account()

        if not self._is_public_key_validity_exceeded(
            valid_from=new_public_key_payload.valid_from,
            valid_to=new_public_key_payload.valid_to,
        ):
            raise InvalidTransaction('The public key validity exceeds the maximum value.')

        public_key_information = PubKeyStorage()
        public_key_information.owner = owner_public_key_as_hex
        public_key_information.payload.CopyFrom(new_public_key_payload)
        public_key_information.is_revoked = False

        state = {
            public_key_to_store_owner_address: public_key_to_store_owner_account,
            payer_for_storing_address: payer_for_storing_account,
            public_key_to_store_address: public_key_information,
        }

        charging_state = self._charge_for_storing(context=context, address_from=payer_for_storing_address)
        if charging_state is not None:
            state.update(charging_state)

        public_key_to_store_owner_account = self._store_public_key_to_account(
            public_key_to_store_address=public_key_to_store_address,
            public_key_to_store_owner_account=public_key_to_store_owner_account,
        )

        state.update({
            public_key_to_store_owner_address: public_key_to_store_owner_account,
        })

        return state
Beispiel #26
0
 def get_public_hex_secp256k1(public_hex_string):
     """Return and instance of a sawtooth public key"""
     return Secp256k1PublicKey.from_hex(public_hex_string)
    def create_wait_certificate(cls,
                                sealed_signup_data,
                                wait_timer,
                                block_hash):
        with cls._lock:
            # Extract keys from the 'sealed' signup data
            if sealed_signup_data is None:
                raise ValueError('Sealed Signup Data is None')
            signup_data = \
                json2dict(
                    base64.b64decode(sealed_signup_data.encode()).decode())
            poet_private_key = signup_data['poet_private_key']
            poet_public_key = signup_data['poet_public_key']

            if poet_private_key is None or poet_public_key is None:
                raise \
                    ValueError(
                        'Invalid signup data. No poet key(s).')

            try:
                poet_public_key = Secp256k1PublicKey.from_hex(poet_public_key)
                poet_private_key = Secp256k1PrivateKey.from_hex(
                    poet_private_key)
            except ParseError:
                raise \
                    ValueError(
                        'Invalid signup data. Badly formatted poet key(s).')

            # Several criteria need to be met before we can create a wait
            # certificate:
            # 1. This signup data was used to sign this timer.
            #    i.e. the key sealed / unsealed by the TEE signed this
            #    wait timer.
            # 2. This timer has expired
            # 3. This timer has not timed out
            #
            # In a TEE implementation we would check HW counter agreement.
            # We can't usefully simulate a HW counter though.
            # i.e. wait_timer.counter_value == signup_data.counter.value

            #
            # Note - we make a concession for the genesis block (i.e., a wait
            # timer for which the previous certificate ID is the Null
            # identifier) in that we don't require the timer to have expired
            # and we don't worry about the timer having timed out.

            if wait_timer is None or \
                    not cls._context.verify(
                        wait_timer.signature,
                        wait_timer.serialize().encode(),
                        poet_public_key):
                raise \
                    ValueError(
                        'Validator is not using the current wait timer')

            is_not_genesis_block = \
                (wait_timer.previous_certificate_id != NULL_BLOCK_IDENTIFIER)

            now = time.time()
            expire_time = \
                wait_timer.request_time + \
                wait_timer.duration

            if is_not_genesis_block and now < expire_time:
                raise \
                    ValueError(
                        'Cannot create wait certificate because timer has '
                        'not expired')

            time_out_time = \
                wait_timer.request_time + \
                wait_timer.duration + \
                TIMER_TIMEOUT_PERIOD

            if is_not_genesis_block and time_out_time < now:
                raise \
                    ValueError(
                        'Cannot create wait certificate because timer '
                        'has timed out')

            # Create a random nonce for the certificate.  For our "random"
            # nonce we will take the timer signature, concat that with the
            # current time, JSON-ize it and create a SHA-256 hash over it.
            # Probably not considered random by security professional
            # standards, but it is good enough for the simulator.
            random_string = \
                dict2json({
                    'wait_timer_signature': wait_timer.signature,
                    'now': datetime.datetime.utcnow().isoformat()
                })
            nonce = hashlib.sha256(random_string.encode()).hexdigest()

            # First create a new enclave wait certificate using the data
            # provided and then sign the certificate with the PoET private key
            wait_certificate = \
                EnclaveWaitCertificate.wait_certificate_with_wait_timer(
                    wait_timer=wait_timer,
                    nonce=nonce,
                    block_hash=block_hash)
            wait_certificate.signature = \
                cls._context.sign(
                    wait_certificate.serialize().encode(),
                    poet_private_key)

            # In a TEE implementation we would increment the HW counter here
            # to prevent replay.
            # We can't usefully simulate a HW counter though.

            return wait_certificate
    def validate_from_dict(self,token):

        _check_format(token,"access token",VALIDATION_FORMAT)

        # state retrival
        device = token['DE']
        result = self._send_request(
            "state?address={}".format(
                self._get_address(device)))

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            data_list =  [
                cbor.loads(base64.b64decode(entry["data"]))
                for entry in encoded_entries
            ]

            state = {x:y[x] for y in data_list for x in y}

        except BaseException:
            return None

        LOGGER.info('checking authorization')
        # check authorization
        capability = token['IC']

        if capability not in state:
            return False

        LOGGER.info('checking delegation chain')
        # delegation chain check
        now = int(time.time())
        resource = token['RE']
        action = token['AC']

        current_token = state[capability]
        parent = current_token['IC']
        while parent != None:
            if parent not in state:
                raise BaseException
            parent_token = state[parent]

            # check time interval
            if now >= int(parent_token['NA']):
                return False
            if now < int(parent_token['NB']):
                return False

            # check access rights
            if resource not in parent_token["AR"]:
                return False
            if action not in parent_token["AR"][resource]:
                return False

            # next
            current_token = parent_token
            parent = current_token['IC']

        LOGGER.info('checking signature')
        # check signature
        signature = token.pop('SI')
        if not create_context('secp256k1').verify(
            signature,
            str(cbor.dumps(token,sort_keys=True)).encode('utf-8'),
            Secp256k1PublicKey.from_hex(state[capability]['SU'])
            ):
            return False

        return True
Beispiel #29
0
def test_verification(benchmark):
    context = create_context("secp256k1")
    factory = CryptoFactory(context)
    pub_key1 = Secp256k1PublicKey.from_hex(KEY1_PUB_HEX)
    result = benchmark(context.verify, MSG1_KEY1_SIG, MSG1.encode(), pub_key1)
    assert result == True
    def create_wait_certificate(cls,
                                sealed_signup_data,
                                wait_timer,
                                block_hash):
        with cls._lock:
            # Extract keys from the 'sealed' signup data
            if sealed_signup_data is None:
                raise ValueError('Sealed Signup Data is None')
            signup_data = \
                json2dict(
                    base64.b64decode(sealed_signup_data.encode()).decode())
            poet_private_key = signup_data['poet_private_key']
            poet_public_key = signup_data['poet_public_key']

            if poet_private_key is None or poet_public_key is None:
                raise \
                    ValueError(
                        'Invalid signup data. No poet key(s).')

            try:
                poet_public_key = Secp256k1PublicKey.from_hex(poet_public_key)
                poet_private_key = Secp256k1PrivateKey.from_hex(
                    poet_private_key)
            except ParseError:
                raise \
                    ValueError(
                        'Invalid signup data. Badly formatted poet key(s).')

            # Several criteria need to be met before we can create a wait
            # certificate:
            # 1. This signup data was used to sign this timer.
            #    i.e. the key sealed / unsealed by the TEE signed this
            #    wait timer.
            # 2. This timer has expired
            # 3. This timer has not timed out
            #
            # In a TEE implementation we would check HW counter agreement.
            # We can't usefully simulate a HW counter though.
            # i.e. wait_timer.counter_value == signup_data.counter.value

            #
            # Note - we make a concession for the genesis block (i.e., a wait
            # timer for which the previous certificate ID is the Null
            # identifier) in that we don't require the timer to have expired
            # and we don't worry about the timer having timed out.

            if wait_timer is None or \
                    not cls._context.verify(
                        wait_timer.signature,
                        wait_timer.serialize().encode(),
                        poet_public_key):
                raise \
                    ValueError(
                        'Validator is not using the current wait timer')

            is_not_genesis_block = \
                (wait_timer.previous_certificate_id !=
                 NULL_BLOCK_IDENTIFIER)

            now = time.time()
            expire_time = \
                wait_timer.request_time + \
                wait_timer.duration

            if is_not_genesis_block and now < expire_time:
                raise \
                    ValueError(
                        'Cannot create wait certificate because timer has '
                        'not expired')

            time_out_time = \
                wait_timer.request_time + \
                wait_timer.duration + \
                TIMER_TIMEOUT_PERIOD

            if is_not_genesis_block and time_out_time < now:
                raise \
                    ValueError(
                        'Cannot create wait certificate because timer '
                        'has timed out')

            # Create a random nonce for the certificate.  For our "random"
            # nonce we will take the timer signature, concat that with the
            # current time, JSON-ize it and create a SHA-256 hash over it.
            # Probably not considered random by security professional
            # standards, but it is good enough for the simulator.
            random_string = \
                dict2json({
                    'wait_timer_signature': wait_timer.signature,
                    'now': datetime.datetime.utcnow().isoformat()
                })
            nonce = hashlib.sha256(random_string.encode()).hexdigest()

            # First create a new enclave wait certificate using the data
            # provided and then sign the certificate with the PoET private key
            wait_certificate = \
                EnclaveWaitCertificate.wait_certificate_with_wait_timer(
                    wait_timer=wait_timer,
                    nonce=nonce,
                    block_hash=block_hash)
            wait_certificate.signature = \
                cls._context.sign(
                    wait_certificate.serialize().encode(),
                    poet_private_key)

            # In a TEE implementation we would increment the HW counter here
            # to prevent replay.
            # We can't usefully simulate a HW counter though.

            return wait_certificate
Beispiel #31
0
    def handle(self, connection_id, message_content):
        """
        When the validator receives an AuthorizationChallengeSubmit message, it
        will verify the public key against the signature. If the public key is
        verified, the requested roles will be checked against the stored roles
        to see if the public key is included in the policy. If the node’s
        response is accepted, the node’s public key will be stored and the
        requester may start sending messages for the approved roles.

        If the requester wanted a role that is either not available on the
        endpoint, the requester does not have access to one of the roles
        requested, or the previous message was not an
        AuthorizationChallengeRequest, the challenge will be rejected and the
        connection will be closed.
        """
        if self._network.get_connection_status(connection_id) != \
                ConnectionStatus.AUTH_CHALLENGE_REQUEST:
            LOGGER.debug("Connection's previous message was not a"
                         " AuthorizationChallengeRequest, Remove connection to"
                         "%s",
                         connection_id)
            return AuthorizationChallengeSubmitHandler \
                ._network_violation_result()

        auth_challenge_submit = AuthorizationChallengeSubmit()
        auth_challenge_submit.ParseFromString(message_content)

        try:
            payload = self._challenge_payload_cache[connection_id]
        except KeyError:
            LOGGER.warning("Connection's challenge payload expired before a"
                           "response was received. %s", connection_id)
            return AuthorizationChallengeSubmitHandler \
                ._network_violation_result()

        context = create_context('secp256k1')
        try:
            public_key = Secp256k1PublicKey.from_hex(
                auth_challenge_submit.public_key)
        except ParseError:
            LOGGER.warning('Authorization Challenge Request cannot be '
                           'verified. Invalid public key %s',
                           auth_challenge_submit.public_key)
            return AuthorizationChallengeSubmitHandler \
                ._network_violation_result()

        if not context.verify(auth_challenge_submit.signature,
                              payload,
                              public_key):
            LOGGER.warning("Signature was not able to be verified. Remove "
                           "connection to %s", connection_id)
            return AuthorizationChallengeSubmitHandler \
                ._network_violation_result()

        roles = self._network.roles
        for role in auth_challenge_submit.roles:
            if role == RoleType.Value("NETWORK") or role == \
                    RoleType.Value("ALL"):
                permitted = False
                if "network" in roles:
                    permitted = self._permission_verifier.check_network_role(
                        auth_challenge_submit.public_key)
                if not permitted:
                    return AuthorizationChallengeSubmitHandler \
                        ._network_violation_result()

        self._network.update_connection_public_key(
            connection_id,
            auth_challenge_submit.public_key)

        if RoleType.Value("NETWORK") in auth_challenge_submit.roles:
            # Need to send ConnectionRequest to authorize ourself with the
            # connection if they initialized the connection
            try:
                is_outbound_connection = self._network.is_outbound_connection(
                    connection_id)
            except KeyError:
                # Connection has gone away, drop message
                return HandlerResult(HandlerStatus.DROP)

            if not is_outbound_connection:
                self._network.send_connect_request(connection_id)
            else:
                # If this is an outbound connection, authorization is complete
                # for both connections and peering/topology build out can
                # begin.
                self._gossip.connect_success(connection_id)

        auth_challenge_result = AuthorizationChallengeResult(
            roles=[RoleType.Value("NETWORK")])

        LOGGER.debug("Connection: %s is approved", connection_id)
        self._network.update_connection_status(
            connection_id,
            ConnectionStatus.CONNECTED)
        return HandlerResult(
            HandlerStatus.RETURN,
            message_out=auth_challenge_result,
            message_type=validator_pb2.Message.AUTHORIZATION_CHALLENGE_RESULT)