def wait_timer_from_serialized(cls, serialized_timer, signature):
        """
        Takes wait timer that has been serialized to JSON and reconstitutes
        into an EnclaveWaitTimer object.

        Args:
            serialized_timer (str): JSON serialized wait timer
            signature (str): Signature over serialized timer

        Returns:
            An EnclaveWaitTimer object
        """
        deserialized_timer = json2dict(serialized_timer)

        timer = \
            EnclaveWaitTimer(
                duration=float(deserialized_timer.get(
                    'duration')),
                previous_certificate_id=str(deserialized_timer.get(
                    'previous_certificate_id')),
                local_mean=float(deserialized_timer.get(
                    'local_mean')),
                signature=signature,
                serialized_timer=serialized_timer)

        timer.request_time = float(deserialized_timer.get('request_time'))

        return timer
    def wait_timer_from_serialized(cls, serialized_timer, signature):
        """
        Takes wait timer that has been serialized to JSON and reconstitutes
        into an EnclaveWaitTimer object.

        Args:
            serialized_timer (str): JSON serialized wait timer
            signature (str): Signature over serialized timer

        Returns:
            An EnclaveWaitTimer object
        """
        deserialized_timer = json2dict(serialized_timer)

        timer = \
            EnclaveWaitTimer(
                validator_address=str(deserialized_timer.get(
                    'validator_address')),
                duration=float(deserialized_timer.get(
                    'duration')),
                previous_certificate_id=str(deserialized_timer.get(
                    'previous_certificate_id')),
                local_mean=float(deserialized_timer.get(
                    'local_mean')),
                signature=signature,
                serialized_timer=serialized_timer)

        timer.request_time = float(deserialized_timer.get('request_time'))

        return timer
    def wait_certificate_from_serialized(cls, serialized_certificate,
                                         signature):
        """
        Takes wait certificate that has been serialized to JSON and
        reconstitutes into an EnclaveWaitCertificate object.

        Args:
            serialized_certificate (str): JSON serialized wait certificate
            signature (str): Signature over serialized certificate

        Returns:
            An EnclaveWaitCertificate object
        """
        deserialized_certificate = json2dict(serialized_certificate)

        certificate = \
            EnclaveWaitCertificate(
                duration=float(deserialized_certificate.get('duration')),
                previous_certificate_id=str(
                    deserialized_certificate.get('previous_certificate_id')),
                local_mean=float(deserialized_certificate.get('local_mean')),
                request_time=float(
                    deserialized_certificate.get('request_time')),
                nonce=str(deserialized_certificate.get('nonce')),
                block_digest=str(deserialized_certificate.get(
                    'block_digest')),
                signature=signature,
                serialized_certificate=serialized_certificate)

        return certificate
Esempio n. 4
0
    def signup_info_from_serialized(cls, serialized_signup_info):
        """
        Takes signup information that has been serialized to JSON and
        reconstitutes into an EnclaveSignupInfo object.

        Args:
            serialized_signup_info: JSON serialized signup info

        Returns:
            An EnclaveSignupInfo object with sealed signup info data
            stripped out as serialized signup info doesn't contain it.
        """
        deserialized_signup_info = json2dict(serialized_signup_info)

        # Note - serialized signup info shouldn't have sealed signup
        # data.
        signup_info = \
            EnclaveSignupInfo(
                poet_public_key=deserialized_signup_info.get(
                    'poet_public_key'),
                proof_data=deserialized_signup_info.get(
                    'proof_data'),
                anti_sybil_id=deserialized_signup_info.get(
                    'anti_sybil_id'),
                serialized_signup_info=serialized_signup_info)

        return signup_info
    def wait_certificate_from_serialized(cls,
                                         serialized_certificate,
                                         signature):
        """
        Takes wait certificate that has been serialized to JSON and
        reconstitutes into an EnclaveWaitCertificate object.

        Args:
            serialized_certificate (str): JSON serialized wait certificate
            signature (str): Signature over serialized certificate

        Returns:
            An EnclaveWaitCertificate object
        """
        deserialized_certificate = json2dict(serialized_certificate)

        certificate = \
            EnclaveWaitCertificate(
                duration=float(deserialized_certificate.get('duration')),
                previous_certificate_id=str(
                    deserialized_certificate.get('previous_certificate_id')),
                local_mean=float(deserialized_certificate.get('local_mean')),
                request_time=float(
                    deserialized_certificate.get('request_time')),
                nonce=str(deserialized_certificate.get('nonce')),
                block_digest=str(deserialized_certificate.get(
                    'block_digest')))

        certificate.signature = signature

        return certificate
    def unseal_signup_data(cls, sealed_signup_data):
        """

        Args:
            sealed_signup_data: Sealed signup data that was returned
                previously in a EnclaveSignupInfo object from a call to
                create_signup_info

        Returns:
            A string The hex encoded PoET public key that was extracted from
            the sealed data
        """

        # Reverse the process we used in creating "sealed" signup info.
        # Specifically, we will do a base 32 decode, which gives us json
        # we can convert back to a dictionary we can use to get the
        # data we need
        signup_data = \
            json2dict(pybitcointools.base64.b32decode(sealed_signup_data))

        with cls._lock:
            cls._poet_public_key = \
                pybitcointools.decode_pubkey(
                    signup_data.get('poet_public_key'),
                    'hex')
            cls._poet_private_key = \
                pybitcointools.decode_privkey(
                    signup_data.get('poet_public_key'),
                    'hex')
            cls._active_wait_timer = None

            return signup_data.get('poet_public_key')
Esempio n. 7
0
    def unseal_signup_data(cls, sealed_signup_data):
        """

        Args:
            sealed_signup_data: Sealed signup data that was returned
                previously in a EnclaveSignupInfo object from a call to
                create_signup_info

        Returns:
            A string The hex encoded PoET public key that was extracted from
            the sealed data
        """

        # Reverse the process we used in creating "sealed" signup info.
        # Specifically, we will do a base 32 decode, which gives us json
        # we can convert back to a dictionary we can use to get the
        # data we need
        signup_data = \
            json2dict(base64.b64decode(sealed_signup_data))

        with cls._lock:
            cls._poet_public_key = \
                signing.decode_pubkey(
                    signup_data.get('poet_public_key'),
                    'hex')
            cls._poet_private_key = \
                signing.decode_privkey(
                    signup_data.get('poet_private_key'),
                    'hex')
            cls._active_wait_timer = None

            return signup_data.get('poet_public_key')
Esempio n. 8
0
    def signup_info_from_serialized(cls, serialized):
        deserialized = json2dict(serialized)

        return \
            SignupInfo(
                anti_sybil_id=deserialized.get('anti_sybil_id'),
                poet_public_key=deserialized.get('poet_public_key'),
                proof_data=deserialized.get('proof_data'))
Esempio n. 9
0
    def _parse(self, lines):
        cpattern = re.compile('##.*$')

        text = ""
        for line in lines:
            text += re.sub(cpattern, '', line) + ' '

        json_dict = json2dict(text)

        self.update(json_dict)
    def verify_signup_info(cls, signup_info, originator_public_key_hash,
                           most_recent_wait_certificate_id):
        # Verify the attestation verification report signature
        proof_data = json2dict(signup_info.proof_data)
        verification_report = proof_data.get('verification_report')
        if verification_report is None:
            raise \
                SignupInfoError(
                    'Verification report is missing from proof data')

        if not pybitcointools.ecdsa_verify(verification_report,
                                           proof_data.get('signature'),
                                           cls._report_public_key):
            raise \
                SignupInfoError('Verification report signature is invalid')

        # Verify that the report data field in the report contains the SHA256
        # digest of the originator's public key SHA 256 digest and the PoET
        # public key.
        verification_report_dict = json2dict(verification_report)

        enclave_quote = verification_report_dict.get('enclave_quote')
        if enclave_quote is None:
            raise \
                SignupInfoError(
                    'Verification report does not contain an enclave quote')

        report = json2dict(pybitcointools.base64.b64decode(enclave_quote))
        report_data = report.get('report_data')
        if report_data is None:
            raise \
                SignupInfoError('Enclave quote does not contain report data')

        target_report_data = {
            'originator_public_key_hash': originator_public_key_hash.upper(),
            'poet_public_key': signup_info.poet_public_key.upper()
        }
        target_report_data_digest = \
            pybitcointools.sha256(dict2json(target_report_data))

        if report_data != target_report_data_digest:
            raise SignupInfoError('Enclave quote report data is invalid')
    def postmsg(self, msgtype, info):
        """
        Post a transaction message to the validator, parse the returning CBOR
        and return the corresponding dictionary.
        """

        logger.debug(dict2json(info))

        data = dict2cbor(info)
        datalen = len(data)
        url = self.BaseURL + msgtype

        logger.debug(
            'post transaction to %s with DATALEN=%d, '
            'base64(DATA)=<%s>', url, datalen, base64.b64encode(data))

        try:
            request = urllib2.Request(url, data, {
                'Content-Type': 'application/cbor',
                'Content-Length': datalen
            })
            opener = urllib2.build_opener(self.ProxyHandler)
            response = opener.open(request, timeout=10)

        except urllib2.HTTPError as err:
            logger.warn('operation failed with response: %s', err.code)
            raise MessageException(
                'operation failed with response: {0}'.format(err.code))

        except urllib2.URLError as err:
            logger.warn('operation failed: %s', err.reason)
            raise MessageException('operation failed: {0}'.format(err.reason))

        except:
            logger.warn('no response from server')
            raise MessageException('no response from server')

        content = response.read()
        headers = response.info()
        response.close()

        encoding = headers.get('Content-Type')

        if encoding == 'application/json':
            value = json2dict(content)
        elif encoding == 'application/cbor':
            value = cbor2dict(content)
        else:
            logger.info('server responds with message %s of type %s', content,
                        encoding)
            return None

        logger.debug(pretty_print_dict(value))
        return value
Esempio n. 12
0
def parse_configuration_file(filename):
    cpattern = re.compile('##.*$')

    with open(filename) as fp:
        lines = fp.readlines()

    text = ""
    for line in lines:
        text += re.sub(cpattern, '', line) + ' '

    return json2dict(text)
Esempio n. 13
0
def parse_configuration_file(filename):
    cpattern = re.compile('##.*$')

    with open(filename) as fp:
        lines = fp.readlines()

    text = ""
    for line in lines:
        text += re.sub(cpattern, '', line) + ' '

    return json2dict(text)
Esempio n. 14
0
    def postmsg(self, msgtype, info):
        """
        Post a transaction message to the validator, parse the returning CBOR
        and return the corresponding dictionary.
        """

        logger.debug(dict2json(info))

        data = dict2cbor(info)
        datalen = len(data)
        url = self.BaseURL + msgtype

        logger.debug('post transaction to %s with DATALEN=%d, '
                     'base64(DATA)=<%s>', url, datalen, base64.b64encode(data))

        try:
            request = urllib2.Request(url, data,
                                      {'Content-Type': 'application/cbor',
                                       'Content-Length': datalen})
            opener = urllib2.build_opener(self.ProxyHandler)
            response = opener.open(request, timeout=10)

        except urllib2.HTTPError as err:
            logger.warn('operation failed with response: %s', err.code)
            raise MessageException(
                'operation failed with response: {0}'.format(err.code))

        except urllib2.URLError as err:
            logger.warn('operation failed: %s', err.reason)
            raise MessageException('operation failed: {0}'.format(err.reason))

        except:
            logger.warn('no response from server')
            raise MessageException('no response from server')

        content = response.read()
        headers = response.info()
        response.close()

        encoding = headers.get('Content-Type')

        if encoding == 'application/json':
            value = json2dict(content)
        elif encoding == 'application/cbor':
            value = cbor2dict(content)
        else:
            logger.info('server responds with message %s of type %s', content,
                        encoding)
            return None

        logger.debug(pretty_print_dict(value))
        return value
    def render_post(self, request, components, msg):
        """
        Process validator control commands
        """
        encoding = request.getHeader('Content-Type')
        data = request.content.getvalue()

        try:
            if encoding == 'application/json':
                minfo = json2dict(data)
            else:
                raise Error(
                    "", 'unknown message'
                    ' encoding: {0}'.format(encoding))
        except Error as e:
            LOGGER.info('exception while decoding http request %s; %s',
                        request.path, traceback.format_exc(20))
            raise Error(http.BAD_REQUEST,
                        'unable to decode incoming request {0}'.format(str(e)))

        # process /command
        try:
            if minfo['action'] == 'start':
                if self.Validator.delaystart is True:
                    self.Validator.delaystart = False
                    LOGGER.info("command received : %s", minfo['action'])
                    minfo['action'] = 'started'
                else:
                    LOGGER.warn("validator startup not delayed")
                    minfo['action'] = 'running'
            else:
                LOGGER.warn("unknown command received")
                minfo['action'] = 'startup failed'

            request.responseHeaders.addRawHeader("content-type", encoding)
            result = dict2json(minfo)
            return result
        except Error as e:
            raise Error(
                int(e.status), 'exception while processing'
                ' request {0}; {1}'.format(request.path, str(e)))

        except:
            LOGGER.info('exception while processing http request %s; %s',
                        request.path, traceback.format_exc(20))
            raise Error(
                http.BAD_REQUEST, 'error processing http request'
                ' {0}'.format(request.path))

        return msg
Esempio n. 16
0
    def getmsg(self, path):
        """
        Send an HTTP get request to the validator. If the resulting content
        is in JSON form, parse it & return the corresponding dictionary.
        """

        url = "{0}/{1}".format(self.BaseURL, path.strip('/'))

        logger.debug('get content from url <%s>', url)

        try:
            request = urllib2.Request(url, headers=self.GET_HEADER)
            opener = urllib2.build_opener(self.ProxyHandler)

            if path == '/prevalidation':
                if self._cookie:
                    request.add_header('cookie', self._cookie)
            response = opener.open(request, timeout=10)

        except urllib2.HTTPError as err:
            logger.warn('operation failed with response: %s', err.code)
            self._print_error_information_from_server(err)
            raise MessageException(
                'operation failed with response: {0}'.format(err.code))

        except urllib2.URLError as err:
            logger.warn('operation failed: %s', err.reason)
            raise MessageException('operation failed: {0}'.format(err.reason))

        except:
            logger.warn('no response from server')
            raise MessageException('no response from server')

        content = response.read()
        headers = response.info()
        response.close()

        encoding = headers.get('Content-Type')

        if encoding == 'application/json':
            value = json2dict(content)
        elif encoding == 'application/cbor':
            value = cbor2dict(content)
        else:
            logger.debug('get content <%s> from url <%s>', content, url)
            return content

        logger.debug(pretty_print_dict(value))
        return value
    def getmsg(self, path):
        """
        Send an HTTP get request to the validator. If the resulting content
        is in JSON form, parse it & return the corresponding dictionary.
        """

        url = "{0}/{1}".format(self.BaseURL, path.strip('/'))

        logger.debug('get content from url <%s>', url)

        try:
            request = urllib2.Request(url, headers=self.GET_HEADER)
            opener = urllib2.build_opener(self.ProxyHandler)

            if path == '/prevalidation':
                if self._cookie:
                    request.add_header('cookie', self._cookie)
            response = opener.open(request, timeout=10)

        except urllib2.HTTPError as err:
            logger.warn('operation failed with response: %s', err.code)
            self._print_error_information_from_server(err)
            raise MessageException(
                'operation failed with response: {0}'.format(err.code))

        except urllib2.URLError as err:
            logger.warn('operation failed: %s', err.reason)
            raise MessageException('operation failed: {0}'.format(err.reason))

        except:
            logger.warn('no response from server')
            raise MessageException('no response from server')

        content = response.read()
        headers = response.info()
        response.close()

        encoding = headers.get('Content-Type')

        if encoding == 'application/json':
            value = json2dict(content)
        elif encoding == 'application/cbor':
            value = cbor2dict(content)
        else:
            logger.debug('get content <%s> from url <%s>', content, url)
            return content

        logger.debug(pretty_print_dict(value))
        return value
    def render_post(self, request, components, msg):
        """
        Process validator control commands
        """
        encoding = request.getHeader('Content-Type')
        data = request.content.getvalue()

        try:
            if encoding == 'application/json':
                minfo = json2dict(data)
            else:
                raise Error("", 'unknown message'
                            ' encoding: {0}'.format(encoding))
        except Error as e:
            LOGGER.info('exception while decoding http request %s; %s',
                        request.path, traceback.format_exc(20))
            raise Error(http.BAD_REQUEST,
                        'unable to decode incoming request {0}'.format(str(e)))

        # process /command
        try:
            if minfo['action'] == 'start':
                if self.Validator.delaystart is True:
                    self.Validator.delaystart = False
                    LOGGER.info("command received : %s", minfo['action'])
                    minfo['action'] = 'started'
                else:
                    LOGGER.warn("validator startup not delayed")
                    minfo['action'] = 'running'
            else:
                LOGGER.warn("unknown command received")
                minfo['action'] = 'startup failed'

            request.responseHeaders.addRawHeader("content-type", encoding)
            result = dict2json(minfo)
            return result
        except Error as e:
            raise Error(int(e.status),
                        'exception while processing'
                        ' request {0}; {1}'.format(request.path, str(e)))

        except:
            LOGGER.info('exception while processing http request %s; %s',
                        request.path, traceback.format_exc(20))
            raise Error(http.BAD_REQUEST,
                        'error processing http request'
                        ' {0}'.format(request.path))

        return msg
Esempio n. 19
0
    def _geturl(self, url, verbose=True, timeout=30):
        """
        Send an HTTP get request to the validator. If the resulting content is
        in JSON or CBOR form, parse it & return the corresponding dictionary.
        """

        if verbose:
            LOGGER.debug('get content from url <%s>', url)

        try:
            request = urllib2.Request(url, headers=self.GET_HEADER)
            opener = urllib2.build_opener(self.proxy_handler)
            response = opener.open(request, timeout=timeout)

        except urllib2.HTTPError as err:
            if verbose:
                LOGGER.error(
                    'peer operation on url %s failed '
                    'with response: %d', url, err.code)
            raise MessageException('operation failed '
                                   'with response: {0}'.format(err.code))

        except urllib2.URLError as err:
            if verbose:
                LOGGER.error('peer operation on url %s failed: %s', url,
                             err.reason)
            raise MessageException('operation failed: {0}'.format(err.reason))

        except:
            if verbose:
                LOGGER.error('no response from peer server for url %s; %s',
                             url,
                             sys.exc_info()[0])
            raise MessageException('no response from server')

        content = response.read()
        headers = response.info()
        response.close()

        encoding = headers.get('Content-Type')

        if encoding == 'application/json':
            return json2dict(content)
        elif encoding == 'application/cbor':
            return cbor2dict(content)
        else:
            return content
Esempio n. 20
0
    def _geturl(self, url, verbose=True, timeout=30):
        """
        Send an HTTP get request to the validator. If the resulting content is
        in JSON or CBOR form, parse it & return the corresponding dictionary.
        """

        if verbose:
            LOGGER.debug('get content from url <%s>', url)

        try:
            request = urllib2.Request(url, headers=self.GET_HEADER)
            opener = urllib2.build_opener(self.proxy_handler)
            response = opener.open(request, timeout=timeout)

        except urllib2.HTTPError as err:
            if verbose:
                LOGGER.error('peer operation on url %s failed '
                             'with response: %d', url, err.code)
            raise MessageException('operation failed '
                                   'with response: {0}'.format(err.code))

        except urllib2.URLError as err:
            if verbose:
                LOGGER.error('peer operation on url %s failed: %s',
                             url, err.reason)
            raise MessageException('operation failed: {0}'.format(err.reason))

        except:
            if verbose:
                LOGGER.error('no response from peer server for url %s; %s',
                             url, sys.exc_info()[0])
            raise MessageException('no response from server')

        content = response.read()
        headers = response.info()
        response.close()

        encoding = headers.get('Content-Type')

        if encoding == 'application/json':
            return json2dict(content)
        elif encoding == 'application/cbor':
            return cbor2dict(content)
        else:
            return content
Esempio n. 21
0
    def _get_message(self, request):
        encoding = request.getHeader('Content-Type')
        data = request.content.getvalue()
        if encoding == 'application/json':
            minfo = json2dict(data)

        elif encoding == 'application/cbor':
            minfo = cbor2dict(data)
        else:
            return self._encode_error_response(
                request, http.BAD_REQUEST, 'unknown message'
                ' encoding: {0}'.format(encoding))
        typename = minfo.get('__TYPE__', '**UNSPECIFIED**')
        if typename not in self.Ledger.gossip.MessageHandlerMap:
            return self._encode_error_response(
                request, http.NOT_FOUND, 'received request for unknown message'
                ' type, {0}'.format(typename))
        return self.Ledger.gossip.MessageHandlerMap[typename][0](minfo)
Esempio n. 22
0
    def getmsg(self, path, timeout=10):
        """
        Send an HTTP get request to the validator. If the resulting content
        is in JSON form, parse it & return the corresponding dictionary.
        """

        url = urlparse.urljoin(self._base_url, path)

        LOGGER.debug('get content from url <%s>', url)

        try:
            request = urllib2.Request(url)
            opener = urllib2.build_opener(self._proxy_handler)
            response = opener.open(request, timeout=timeout)

        except urllib2.HTTPError as err:
            LOGGER.warn('operation failed with response: %s', err.code)
            self._print_error_information_from_server(err)
            raise MessageException(
                'operation failed with response: {0}'.format(err.code))

        except urllib2.URLError as err:
            LOGGER.warn('operation failed: %s', err.reason)
            raise MessageException('operation failed: {0}'.format(err.reason))

        except:
            LOGGER.warn('no response from server')
            raise MessageException('no response from server')

        content = response.read()
        headers = response.info()
        response.close()

        encoding = headers.get('Content-Type')

        if encoding == 'application/json':
            return json2dict(content)
        elif encoding == 'application/cbor':
            return cbor2dict(content)
        else:
            return content
Esempio n. 23
0
    def getmsg(self, path, timeout=10):
        """
        Send an HTTP get request to the validator. If the resulting content
        is in JSON form, parse it & return the corresponding dictionary.
        """

        url = urlparse.urljoin(self._base_url, path)

        LOGGER.debug('get content from url <%s>', url)

        try:
            request = urllib2.Request(url)
            opener = urllib2.build_opener(self._proxy_handler)
            response = opener.open(request, timeout=timeout)

        except urllib2.HTTPError as err:
            LOGGER.warn('operation failed with response: %s', err.code)
            self._print_error_information_from_server(err)
            raise MessageException(
                'operation failed with response: {0}'.format(err.code))

        except urllib2.URLError as err:
            LOGGER.warn('operation failed: %s', err.reason)
            raise MessageException('operation failed: {0}'.format(err.reason))

        except:
            LOGGER.warn('no response from server')
            raise MessageException('no response from server')

        content = response.read()
        headers = response.info()
        response.close()

        encoding = headers.get('Content-Type')

        if encoding == 'application/json':
            return json2dict(content)
        elif encoding == 'application/cbor':
            return cbor2dict(content)
        else:
            return content
Esempio n. 24
0
def ParseConfigurationFile(filename, variable_map):
    """
    Parse a configuration file expanding variable references
    using the Python Template library (variables are $var format)

  :param string filename: name of the configuration file
  :param dict variable_map: dictionary of expansions to use
  :returns dict: dictionary of configuration information
    """
    cpattern = re.compile('##.*$')

    with open(filename) as fp:
        lines = fp.readlines()

    text = ""
    for line in lines:
        text += re.sub(cpattern, '', line) + ' '

    if variable_map:
        text = Template(text).substitute(variable_map)

    return json2dict(text)
Esempio n. 25
0
    def _get_message(self, request):
        encoding = request.getHeader('Content-Type')
        data = request.content.getvalue()
        if encoding == 'application/json':
            minfo = json2dict(data)

        elif encoding == 'application/cbor':
            minfo = cbor2dict(data)
        else:
            return self._encode_error_response(
                request,
                http.BAD_REQUEST,
                'unknown message'
                ' encoding: {0}'.format(encoding))
        typename = minfo.get('__TYPE__', '**UNSPECIFIED**')
        if not self.validator.gossip.dispatcher.has_message_handler(typename):
            return self._encode_error_response(
                request,
                http.NOT_FOUND,
                'received request for unknown message'
                ' type, {0}'.format(typename))
        return self.validator.gossip.dispatcher.unpack_message(typename, minfo)
Esempio n. 26
0
    def _get_message(self, request):
        encoding = request.getHeader('Content-Type')
        data = request.content.getvalue()
        if encoding == 'application/json':
            minfo = json2dict(data)

        elif encoding == 'application/cbor':
            minfo = cbor2dict(data)
        else:
            return self._encode_error_response(
                request,
                http.BAD_REQUEST,
                'unknown message'
                ' encoding: {0}'.format(encoding))
        typename = minfo.get('__TYPE__', '**UNSPECIFIED**')
        if typename not in self.Ledger.MessageHandlerMap:
            return self._encode_error_response(
                request,
                http.NOT_FOUND,
                'received request for unknown message'
                ' type, {0}'.format(typename))
        return self.Ledger.MessageHandlerMap[typename][0](minfo)
Esempio n. 27
0
    def signup_info_from_serialized(cls, serialized_signup_info):
        """
        Takes signup information that has been serialized to JSON and
        reconstitutes into an EnclaveSignupInfo object.

        Args:
            serialized_signup_info: JSON serialized signup info

        Returns:
            An EnclaveSignupInfo object
        """
        deserialized_signup_info = json2dict(serialized_signup_info)

        return \
            EnclaveSignupInfo(
                anti_sybil_id=deserialized_signup_info.get(
                    'anti_sybil_id'),
                poet_public_key=deserialized_signup_info.get(
                    'poet_public_key'),
                proof_data=deserialized_signup_info.get(
                    'proof_data'),
                sealed_signup_data=deserialized_signup_info.get(
                    'sealed_signup_data'))
Esempio n. 28
0
    def _posturl(self, url, info, encoding='application/cbor'):
        """
        Post a transaction message to the validator, parse the returning CBOR
        and return the corresponding dictionary.
        """

        if encoding == 'application/json':
            data = dict2json(info)
        elif encoding == 'application/cbor':
            data = dict2cbor(info)
        else:
            LOGGER.error('unknown request encoding %s', encoding)
            return None

        datalen = len(data)

        LOGGER.debug('post transaction to %s with DATALEN=%d, DATA=<%s>', url,
                     datalen, data)

        try:
            request = urllib2.Request(url, data, {
                'Content-Type': 'application/cbor',
                'Content-Length': datalen
            })
            opener = urllib2.build_opener(self.proxy_handler)
            response = opener.open(request, timeout=10)

        except urllib2.HTTPError as err:
            LOGGER.error('peer operation on url %s failed with response: %d',
                         url, err.code)
            raise MessageException(
                'operation failed with response: {0}'.format(err.code))

        except urllib2.URLError as err:
            LOGGER.error('peer operation on url %s failed: %s', url,
                         err.reason)
            raise MessageException('operation failed: {0}'.format(err.reason))

        except NameError as err:
            LOGGER.error('name error %s', err)
            raise MessageException('operation failed: {0}'.format(url))

        except:
            LOGGER.error('no response from peer server for url %s; %s', url,
                         sys.exc_info()[0])
            raise MessageException('no response from server')

        content = response.read()
        headers = response.info()
        response.close()

        encoding = headers.get('Content-Type')

        if encoding == 'application/json':
            value = json2dict(content)
        elif encoding == 'application/cbor':
            value = cbor2dict(content)
        else:
            LOGGER.info('server responds with message %s of unknown type %s',
                        content, encoding)
            value = OrderedDict()

        return value
Esempio n. 29
0
    def _posturl(self, url, info, encoding='application/cbor'):
        """
        Post a transaction message to the validator, parse the returning CBOR
        and return the corresponding dictionary.
        """

        if encoding == 'application/json':
            data = dict2json(info)
        elif encoding == 'application/cbor':
            data = dict2cbor(info)
        else:
            LOGGER.error('unknown request encoding %s', encoding)
            return None

        datalen = len(data)

        LOGGER.debug('post transaction to %s with DATALEN=%d, DATA=<%s>', url,
                     datalen, data)

        try:
            request = urllib2.Request(url, data,
                                      {'Content-Type': 'application/cbor',
                                       'Content-Length': datalen})
            opener = urllib2.build_opener(self.proxy_handler)
            response = opener.open(request, timeout=10)

        except urllib2.HTTPError as err:
            LOGGER.error('peer operation on url %s failed with response: %d',
                         url, err.code)
            raise MessageException('operation failed with resonse: {0}'.format(
                err.code))

        except urllib2.URLError as err:
            LOGGER.error('peer operation on url %s failed: %s', url,
                         err.reason)
            raise MessageException('operation failed: {0}'.format(err.reason))

        except NameError as err:
            LOGGER.error('name error %s', err)
            raise MessageException('operation failed: {0}'.format(url))

        except:
            LOGGER.error('no response from peer server for url %s; %s', url,
                         sys.exc_info()[0])
            raise MessageException('no response from server')

        content = response.read()
        headers = response.info()
        response.close()

        encoding = headers.get('Content-Type')

        if encoding == 'application/json':
            value = json2dict(content)
        elif encoding == 'application/cbor':
            value = cbor2dict(content)
        else:
            LOGGER.info('server responds with message %s of unknown type %s',
                        content, encoding)
            value = OrderedDict()

        return value
Esempio n. 30
0
    def render_POST(self, request):
        """
        Handle a POST request on the HTTP interface. All message on the POST
        interface are gossip messages that should be relayed into the gossip
        network as is.
        """
        # pylint: disable=invalid-name

        # break the path into its component parts
        components = request.path.split('/')
        while components and components[0] == '':
            components.pop(0)

        prefix = components.pop(0) if components else 'error'
        if prefix not in self.PostPageMap:
            prefix = 'default'

        # process the message encoding
        encoding = request.getHeader('Content-Type')
        data = request.content.getvalue()

        try:
            if encoding == 'application/json':
                minfo = json2dict(data)
            elif encoding == 'application/cbor':
                minfo = cbor2dict(data)
            else:
                return self.error_response(request, http.BAD_REQUEST,
                                           'unknown message encoding, {0}',
                                           encoding)

            typename = minfo.get('__TYPE__', '**UNSPECIFIED**')
            if typename not in self.Ledger.MessageHandlerMap:
                return self.error_response(
                    request, http.BAD_REQUEST,
                    'received request for unknown message type, {0}', typename)

            msg = self.Ledger.MessageHandlerMap[typename][0](minfo)

        except:
            logger.info('exception while decoding http request %s; %s',
                        request.path, traceback.format_exc(20))
            return self.error_response(
                request, http.BAD_REQUEST,
                'unabled to decode incoming request {0}',
                data)

        # and finally execute the associated method and send back the results
        try:
            response = self.PostPageMap[prefix](request, components, msg)

            request.responseHeaders.addRawHeader("content-type", encoding)
            if encoding == 'application/json':
                result = dict2json(response.dump())
            else:
                result = dict2cbor(response.dump())

            return result

        except Error as e:
            return self.error_response(
                request, int(e.status),
                'exception while processing request {0}; {1}', request.path,
                str(e))

        except:
            logger.info('exception while processing http request %s; %s',
                        request.path, traceback.format_exc(20))
            return self.error_response(request, http.BAD_REQUEST,
                                       'error processing http request {0}',
                                       request.path)
Esempio n. 31
0
    def postmsg(self, msgtype, info):
        """
        Post a transaction message to the validator, parse the returning CBOR
        and return the corresponding dictionary.
        """

        data = dict2cbor(info)
        datalen = len(data)
        url = urlparse.urljoin(self._base_url, msgtype)

        LOGGER.debug('post transaction to %s with DATALEN=%d, DATA=<%s>', url,
                     datalen, data)

        try:
            request = urllib2.Request(url, data,
                                      {'Content-Type': 'application/cbor',
                                       'Content-Length': datalen})

            if self._cookie:
                request.add_header('cookie', self._cookie)

            opener = urllib2.build_opener(self._proxy_handler)
            response = opener.open(request, timeout=10)
            if not self._cookie:
                self._cookie = response.headers.get('Set-Cookie')
        except urllib2.HTTPError as err:
            content = err.read()
            if content is not None:
                headers = err.info()
                encoding = headers.get('Content-Type')

                if encoding == 'application/json':
                    value = json2dict(content)
                elif encoding == 'application/cbor':
                    value = cbor2dict(content)
                else:
                    LOGGER.warn('operation failed with response: %s', err.code)
                    raise MessageException(
                        'operation failed with response: {0}'.format(err.code))
                LOGGER.warn('operation failed with response: %s %s',
                            err.code, str(value))
                if "errorType" in value:
                    if value['errorType'] == "InvalidTransactionError":
                        raise InvalidTransactionError(
                            value['error'] if 'error' in value else value)
                    else:
                        raise MessageException(str(value))
            else:
                raise MessageException(
                    'operation failed with response: {0}'.format(err.code))
        except urllib2.URLError as err:
            LOGGER.warn('operation failed: %s', err.reason)
            raise MessageException('operation failed: {0}'.format(err.reason))

        except:
            LOGGER.warn('no response from server')
            raise MessageException('no response from server')

        content = response.read()
        headers = response.info()
        response.close()

        encoding = headers.get('Content-Type')

        if encoding == 'application/json':
            value = json2dict(content)
        elif encoding == 'application/cbor':
            value = cbor2dict(content)
        else:
            LOGGER.info('server responds with message %s of type %s', content,
                        encoding)
            return None

        LOGGER.debug(pretty_print_dict(value))
        return value
    def render_post(self, request, components, msg):
        """
        Forward a signed message through the gossip network.
        """
        encoding = request.getHeader('Content-Type')
        data = request.content.getvalue()
        try:
            if encoding == 'application/json':
                minfo = json2dict(data)

            elif encoding == 'application/cbor':
                minfo = cbor2dict(data)
            else:
                raise Error("", 'unknown message'
                            ' encoding: {0}'.format(encoding))
            typename = minfo.get('__TYPE__', '**UNSPECIFIED**')
            if typename not in self.Ledger.MessageHandlerMap:
                raise Error("",
                            'received request for unknown message'
                            ' type, {0}'.format(typename))
            msg = self.Ledger.MessageHandlerMap[typename][0](minfo)
        except Error as e:
            LOGGER.info('exception while decoding http request %s; %s',
                        request.path, traceback.format_exc(20))
            raise Error(http.BAD_REQUEST,
                        'unable to decode incoming request: {0}'.format(e))

        if self.Validator.Config.get("LocalValidation", True):
            # determine if the message contains a valid transaction before
            # we send the message to the network

            # we need to start with a copy of the message due to cases
            # where side effects of the validity check may impact objects
            # related to msg
            mymsg = copy.deepcopy(msg)

            if hasattr(mymsg, 'Transaction') and mymsg.Transaction is not None:
                mytxn = mymsg.Transaction
                LOGGER.info('starting local validation '
                            'for txn id: %s type: %s',
                            mytxn.Identifier,
                            mytxn.TransactionTypeName)
                block_id = self.Ledger.MostRecentCommittedBlockID

                real_store_map = self.Ledger.GlobalStoreMap.get_block_store(
                    block_id)
                temp_store_map = \
                    global_store_manager.BlockStore(real_store_map)
                if not temp_store_map:
                    LOGGER.info('no store map for block %s', block_id)
                    raise Error(http.BAD_REQUEST,
                                'unable to validate enclosed'
                                ' transaction {0}'.format(data))

                transaction_type = mytxn.TransactionTypeName
                if transaction_type not in temp_store_map.TransactionStores:
                    LOGGER.info('transaction type %s not in global store map',
                                transaction_type)
                    raise Error(http.BAD_REQUEST,
                                'unable to validate enclosed'
                                ' transaction {0}'.format(data))

                # clone a copy of the ledger's message queue so we can
                # temporarily play forward all locally submitted yet
                # uncommitted transactions
                my_queue = copy.deepcopy(self.Ledger.MessageQueue)

                # apply any enqueued messages
                while len(my_queue) > 0:
                    qmsg = my_queue.pop()
                    if qmsg and \
                            qmsg.MessageType in self.Ledger.MessageHandlerMap:
                        if (hasattr(qmsg, 'Transaction') and
                                qmsg.Transaction is not None):
                            my_store = temp_store_map.get_transaction_store(
                                qmsg.Transaction.TransactionTypeName)
                            if qmsg.Transaction.is_valid(my_store):
                                myqtxn = copy.copy(qmsg.Transaction)
                                myqtxn.apply(my_store)

                # apply any local pending transactions
                for txn_id in self.Ledger.PendingTransactions.iterkeys():
                    pend_txn = self.Ledger.TransactionStore[txn_id]
                    my_store = temp_store_map.get_transaction_store(
                        pend_txn.TransactionTypeName)
                    if pend_txn and pend_txn.is_valid(my_store):
                        my_pend_txn = copy.copy(pend_txn)
                        my_pend_txn.apply(my_store)

                # determine validity of the POSTed transaction against our
                # new temporary state
                my_store = temp_store_map.get_transaction_store(
                    mytxn.TransactionTypeName)
                try:
                    mytxn.check_valid(my_store)
                except InvalidTransactionError as e:
                    LOGGER.info('submitted transaction fails transaction '
                                'family validation check: %s; %s',
                                request.path, mymsg.dump())
                    raise Error(http.BAD_REQUEST,
                                "enclosed transaction failed transaction "
                                "family validation check: {}".format(str(e)))
                except:
                    LOGGER.info('submitted transaction is '
                                'not valid %s; %s; %s',
                                request.path, mymsg.dump(),
                                traceback.format_exc(20))
                    raise Error(http.BAD_REQUEST,
                                "enclosed transaction is not"
                                " valid {}".format(data))

                LOGGER.info('transaction %s is valid',
                            msg.Transaction.Identifier)

        # and finally execute the associated method
        # and send back the results

        self.Ledger.handle_message(msg)
        return msg
Esempio n. 33
0
        key_file = os.path.join(key_dir, key_name + '.wif')

    if not os.path.exists(key_file):
        raise ClientException('no such file: {}'.format(key_file))

    try:
        if filename == '-':
            json_content = sys.stdin.read()
        else:
            with open(filename) as fd:
                json_content = fd.read()
    except IOError, e:
        raise CliException(str(e))

    try:
        txn_content = json2dict(json_content)
    except ValueError, e:
        raise CliException("Decoding JSON: {}".format(str(e)))

    try:
        txnfamily = importlib.import_module(family_name)
    except ImportError:
        raise CliException(
            "transaction family not found: {}".format(family_name))

    fake_journal = FakeJournal()
    txnfamily.register_transaction_types(fake_journal)

    client = SawtoothClient(base_url=url,
                            keyfile=key_file,
                            store_name=fake_journal.store_class.__name__)
    def verify_signup_info(cls,
                           signup_info,
                           originator_public_key,
                           validator_network_basename,
                           most_recent_wait_certificate_id):
        # Verify the attestation verification report signature
        attestation_verification_report = \
            signup_info.proof_data.get('attestation_verification_report')
        if attestation_verification_report is None:
            raise \
                SignupInfoError(
                    'Attestation verification report is missing from proof '
                    'data')

        if not pybitcointools.ecdsa_verify(
                dict2json(attestation_verification_report),
                signup_info.proof_data.get('signature'),
                cls._report_public_key):
            raise \
                SignupInfoError(
                    'Attestation verification report signature is invalid')

        # Verify the presence of the anti-Sybil ID
        anti_sybil_id = attestation_verification_report.get('anti_sybil_id')
        if anti_sybil_id is None:
            raise \
                SignupInfoError(
                    'Attestation verification report does not contain an '
                    'anti-Sybil ID')

        # Verify that the report data field in the report contains the SHA256
        # digest of the originator's public key SHA 256 digest and the PoET
        # public key.
        attestation_evidence_payload = \
            attestation_verification_report.get(
                'attestation_evidence_payload')
        if attestation_evidence_payload is None:
            raise \
                SignupInfoError(
                    'Attestation verification report does not contain '
                    'attestation evidence payload')

        enclave_quote = attestation_evidence_payload.get('enclave_quote')
        if enclave_quote is None:
            raise \
                SignupInfoError(
                    'Attestation evidence payload does not contain an '
                    'enclave quote')

        report = json2dict(pybitcointools.base64.b64decode(enclave_quote))
        report_data = report.get('report_data')
        if report_data is None:
            raise \
                SignupInfoError('Enclave quote does not contain report data')

        target_report_data = {
            'originator_public_key_hash':
                pybitcointools.sha256(
                    pybitcointools.encode_pubkey(
                        originator_public_key,
                        'hex')),
            'poet_public_key': signup_info.poet_public_key
        }
        target_report_data_digest = \
            pybitcointools.sha256(dict2json(target_report_data))

        if report_data != target_report_data_digest:
            raise SignupInfoError('Enclave quote report data is invalid')

        # Verify that the validator base name in the enclave quote report
        # matches the provided validator network basename
        validator_net_basename = report.get('validator_network_basename')
        if validator_net_basename is None:
            raise \
                SignupInfoError(
                    'Enclave quote report does not have a validator network '
                    'basename')

        if validator_net_basename != validator_network_basename:
            raise \
                SignupInfoError(
                    'Enclave quote report validator network basename [{0}] '
                    'does not match [{1}]'.format(
                        validator_net_basename,
                        validator_network_basename))
Esempio n. 35
0
    def do_post(self, request):
        """
        Handle two types of HTTP POST requests:
         - gossip messages.  relayed to the gossip network as is
         - validator command and control (/command)
        """

        # break the path into its component parts

        components = request.path.split('/')
        while components and components[0] == '':
            components.pop(0)

        prefix = components.pop(0) if components else 'error'
        if prefix not in self.PostPageMap:
            prefix = 'default'

        encoding = request.getHeader('Content-Type')
        data = request.content.getvalue()

        # process non-gossip API requests
        if prefix == 'command':

            try:
                if encoding == 'application/json':
                    minfo = json2dict(data)
                else:
                    return self.error_response(request, http.BAD_REQUEST,
                                               'bad message encoding, {0}',
                                               encoding)
            except:
                logger.info('exception while decoding http request %s; %s',
                            request.path, traceback.format_exc(20))
                return self.error_response(
                    request, http.BAD_REQUEST,
                    'unable to decode incoming request {0}', data)

            # process /command
            try:
                response = self.PostPageMap[prefix](request, components, minfo)
                request.responseHeaders.addRawHeader("content-type", encoding)
                result = dict2json(response)
                return result

            except Error as e:
                return self.error_response(
                    request, int(e.status),
                    'exception while processing request {0}; {1}',
                    request.path, str(e))

            except:
                logger.info('exception while processing http request %s; %s',
                            request.path, traceback.format_exc(20))
                return self.error_response(
                    request, http.BAD_REQUEST,
                    'error processing http request {0}', request.path)
        else:
            try:
                if encoding == 'application/json':
                    minfo = json2dict(data)
                elif encoding == 'application/cbor':
                    minfo = cbor2dict(data)
                else:
                    return self.error_response(
                        request, http.BAD_REQUEST,
                        'unknown message encoding, {0}', encoding)
                typename = minfo.get('__TYPE__', '**UNSPECIFIED**')
                if typename not in self.Ledger.MessageHandlerMap:
                    return self.error_response(
                        request, http.BAD_REQUEST,
                        'received request for unknown message type, {0}',
                        typename)

                msg = self.Ledger.MessageHandlerMap[typename][0](minfo)

            except:
                logger.info('exception while decoding http request %s; %s',
                            request.path, traceback.format_exc(20))
                return self.error_response(
                    request, http.BAD_REQUEST,
                    'unabled to decode incoming request {0}', data)

            # determine if the message contains a valid transaction before
            # we send the message to the network

            # we need to start with a copy of the message due to cases
            # where side effects of the validity check may impact objects
            # related to msg
            mymsg = copy.deepcopy(msg)

            if hasattr(mymsg, 'Transaction') and mymsg.Transaction is not None:
                mytxn = mymsg.Transaction
                logger.info(
                    'starting local validation '
                    'for txn id: %s type: %s', mytxn.Identifier,
                    mytxn.TransactionTypeName)
                block_id = self.Ledger.MostRecentCommittedBlockID

                real_store_map = self.Ledger.GlobalStoreMap.get_block_store(
                    block_id)
                temp_store_map = \
                    global_store_manager.BlockStore(real_store_map)
                if not temp_store_map:
                    logger.info('no store map for block %s', block_id)
                    return self.error_response(
                        request, http.BAD_REQUEST,
                        'unable to validate enclosed transaction {0}', data)

                transaction_type = mytxn.TransactionTypeName
                if transaction_type not in temp_store_map.TransactionStores:
                    logger.info('transaction type %s not in global store map',
                                transaction_type)
                    return self.error_response(
                        request, http.BAD_REQUEST,
                        'unable to validate enclosed transaction {0}', data)

                # clone a copy of the ledger's message queue so we can
                # temporarily play forward all locally submitted yet
                # uncommitted transactions
                my_queue = copy.deepcopy(self.Ledger.MessageQueue)

                # apply any enqueued messages
                while len(my_queue) > 0:
                    qmsg = my_queue.pop()
                    if qmsg and \
                       qmsg.MessageType in self.Ledger.MessageHandlerMap:
                        if (hasattr(qmsg, 'Transaction')
                                and qmsg.Transaction is not None):
                            my_store = temp_store_map.get_transaction_store(
                                qmsg.Transaction.TransactionTypeName)
                            if qmsg.Transaction.is_valid(my_store):
                                myqtxn = copy.copy(qmsg.Transaction)
                                myqtxn.apply(my_store)

                # apply any local pending transactions
                for txn_id in self.Ledger.PendingTransactions.iterkeys():
                    pend_txn = self.Ledger.TransactionStore[txn_id]
                    my_store = temp_store_map.get_transaction_store(
                        pend_txn.TransactionTypeName)
                    if pend_txn and pend_txn.is_valid(my_store):
                        my_pend_txn = copy.copy(pend_txn)
                        logger.debug(
                            'applying pending transaction '
                            '%s to temp store', txn_id)
                        my_pend_txn.apply(my_store)

                # determine validity of the POSTed transaction against our
                # new temporary state
                my_store = temp_store_map.get_transaction_store(
                    mytxn.TransactionTypeName)
                try:
                    mytxn.check_valid(my_store)
                except InvalidTransactionError as e:
                    logger.info(
                        'submitted transaction fails transaction '
                        'family validation check: %s; %s', request.path,
                        mymsg.dump())
                    return self.error_response(
                        request, http.BAD_REQUEST,
                        "enclosed transaction failed transaction "
                        "family validation check: {}".format(str(e)), data)
                except:
                    logger.info(
                        'submitted transaction is '
                        'not valid %s; %s; %s', request.path, mymsg.dump(),
                        traceback.format_exc(20))
                    return self.error_response(
                        request, http.BAD_REQUEST,
                        "enclosed transaction is not valid", data)

                logger.info('transaction %s is valid',
                            msg.Transaction.Identifier)

            # and finally execute the associated method
            # and send back the results
            try:
                response = self.PostPageMap[prefix](request, components, msg)

                request.responseHeaders.addRawHeader("content-type", encoding)
                if encoding == 'application/json':
                    result = dict2json(response.dump())
                else:
                    result = dict2cbor(response.dump())

                return result

            except Error as e:
                return self.error_response(
                    request, int(e.status),
                    'exception while processing request {0}; {1}',
                    request.path, str(e))

            except:
                logger.info('exception while processing http request %s; %s',
                            request.path, traceback.format_exc(20))
                return self.error_response(
                    request, http.BAD_REQUEST,
                    'error processing http request {0}', request.path)
Esempio n. 36
0
        key_file = os.path.join(key_dir, key_name + '.wif')

    if not os.path.exists(key_file):
        raise ClientException('no such file: {}'.format(key_file))

    try:
        if filename == '-':
            json_content = sys.stdin.read()
        else:
            with open(filename) as fd:
                json_content = fd.read()
    except IOError, e:
        raise CliException(str(e))

    try:
        txn_content = json2dict(json_content)
    except ValueError, e:
        raise CliException("Decoding JSON: {}".format(str(e)))

    try:
        txnfamily = importlib.import_module(family_name)
    except ImportError:
        raise CliException(
            "transaction family not found: {}".format(family_name))

    fake_journal = FakeJournal()
    txnfamily.register_transaction_types(fake_journal)

    client = SawtoothClient(
        base_url=url,
        keyfile=key_file,
Esempio n. 37
0
 def deserialize(cls, serialized):
     deserialized = json2dict(serialized)
     return deserialized
Esempio n. 38
0
    def render_POST(self, request):
        """
        Handle two types of HTTP POST requests:
         - gossip messages.  relayed to the gossip network as is
         - validator command and control (/command)
        """
        # pylint: disable=invalid-name

        # break the path into its component parts
        components = request.path.split('/')
        while components and components[0] == '':
            components.pop(0)

        prefix = components.pop(0) if components else 'error'
        if prefix not in self.PostPageMap:
            prefix = 'default'

        encoding = request.getHeader('Content-Type')
        data = request.content.getvalue()

        # process non-gossip API requests
        if prefix == 'command':

            try:
                if encoding == 'application/json':
                    minfo = json2dict(data)
                else:
                    return self.error_response(request, http.BAD_REQUEST,
                                               'bad message encoding, {0}',
                                               encoding)
            except:
                logger.info('exception while decoding http request %s; %s',
                            request.path, traceback.format_exc(20))
                return self.error_response(
                    request, http.BAD_REQUEST,
                    'unable to decode incoming request {0}',
                    data)

            # process /command
            try:
                response = self.PostPageMap[prefix](request, components, minfo)
                request.responseHeaders.addRawHeader("content-type", encoding)
                result = dict2json(response)
                return result

            except Error as e:
                return self.error_response(
                    request, int(e.status),
                    'exception while processing request {0}; {1}',
                    request.path, str(e))

            except:
                logger.info('exception while processing http request %s; %s',
                            request.path, traceback.format_exc(20))
                return self.error_response(request, http.BAD_REQUEST,
                                           'error processing http request {0}',
                                           request.path)
        else:
            try:
                if encoding == 'application/json':
                    minfo = json2dict(data)
                elif encoding == 'application/cbor':
                    minfo = cbor2dict(data)
                else:
                    return self.error_response(request, http.BAD_REQUEST,
                                               'unknown message encoding, {0}',
                                               encoding)
                typename = minfo.get('__TYPE__', '**UNSPECIFIED**')
                if typename not in self.Ledger.MessageHandlerMap:
                    return self.error_response(
                        request, http.BAD_REQUEST,
                        'received request for unknown message type, {0}',
                        typename)

                msg = self.Ledger.MessageHandlerMap[typename][0](minfo)

            except:
                logger.info('exception while decoding http request %s; %s',
                            request.path, traceback.format_exc(20))
                return self.error_response(
                    request, http.BAD_REQUEST,
                    'unabled to decode incoming request {0}',
                    data)

            # determine if the message contains a valid transaction before
            # we send the message to the network

            # we need to start with a copy of the message due to cases
            # where side effects of the validity check may impact objects
            # related to msg
            mymsg = copy.deepcopy(msg)

            if hasattr(mymsg, 'Transaction') and mymsg.Transaction is not None:
                mytxn = mymsg.Transaction
                logger.info('starting local validation '
                            'for txn id: %s type: %s',
                            mytxn.Identifier,
                            mytxn.TransactionTypeName)
                blockid = self.Ledger.MostRecentCommittedBlockID

                realstoremap = self.Ledger.GlobalStoreMap.get_block_store(
                    blockid)
                tempstoremap = global_store_manager.BlockStore(realstoremap)
                if not tempstoremap:
                    logger.info('no store map for block %s', blockid)
                    return self.error_response(
                        request, http.BAD_REQUEST,
                        'unable to validate enclosed transaction {0}',
                        data)

                transtype = mytxn.TransactionTypeName
                if transtype not in tempstoremap.TransactionStores:
                    logger.info('transaction type %s not in global store map',
                                transtype)
                    return self.error_response(
                        request, http.BAD_REQUEST,
                        'unable to validate enclosed transaction {0}',
                        data)

                # clone a copy of the ledger's message queue so we can
                # temporarily play forward all locally submitted yet
                # uncommitted transactions
                myqueue = copy.deepcopy(self.Ledger.MessageQueue)

                # apply any enqueued messages
                while len(myqueue) > 0:
                    qmsg = myqueue.pop()
                    if qmsg and \
                       qmsg.MessageType in self.Ledger.MessageHandlerMap:
                        if (hasattr(qmsg, 'Transaction') and
                                qmsg.Transaction is not None):
                            mystore = tempstoremap.get_transaction_store(
                                qmsg.Transaction.TransactionTypeName)
                            if qmsg.Transaction.is_valid(mystore):
                                myqtxn = copy.copy(qmsg.Transaction)
                                myqtxn.apply(mystore)

                # apply any local pending transactions
                for txnid in self.Ledger.PendingTransactions.iterkeys():
                    pendtxn = self.Ledger.TransactionStore[txnid]
                    mystore = tempstoremap.get_transaction_store(
                        pendtxn.TransactionTypeName)
                    if pendtxn and pendtxn.is_valid(mystore):
                        mypendtxn = copy.copy(pendtxn)
                        logger.debug('applying pending transaction '
                                     '%s to temp store', txnid)
                        mypendtxn.apply(mystore)

                # determine validity of the POSTed transaction against our
                # new temporary state
                mystore = tempstoremap.get_transaction_store(
                    mytxn.TransactionTypeName)
                try:
                    mytxn.check_valid(mystore)
                except InvalidTransactionError as e:
                    logger.info('submitted transaction fails transaction '
                                'family validation check: %s; %s',
                                request.path, mymsg.dump())
                    return self.error_response(
                        request, http.BAD_REQUEST,
                        "enclosed transaction failed transaction "
                        "family validation check: {}".format(str(e)),
                        data)
                except:
                    logger.info('submitted transaction is '
                                'not valid %s; %s; %s',
                                request.path, mymsg.dump(),
                                traceback.format_exc(20))
                    return self.error_response(
                        request, http.BAD_REQUEST,
                        "enclosed transaction is not valid",
                        data)

                logger.info('transaction %s is valid',
                            msg.Transaction.Identifier)

            # and finally execute the associated method
            # and send back the results
            try:
                response = self.PostPageMap[prefix](request, components, msg)

                request.responseHeaders.addRawHeader("content-type", encoding)
                if encoding == 'application/json':
                    result = dict2json(response.dump())
                else:
                    result = dict2cbor(response.dump())

                return result

            except Error as e:
                return self.error_response(
                    request, int(e.status),
                    'exception while processing request {0}; {1}',
                    request.path, str(e))

            except:
                logger.info('exception while processing http request %s; %s',
                            request.path, traceback.format_exc(20))
                return self.error_response(request, http.BAD_REQUEST,
                                           'error processing http request {0}',
                                           request.path)
Esempio n. 39
0
    def render_POST(self, request):
        """
        Handle a POST request on the HTTP interface. All message on the POST
        interface are gossip messages that should be relayed into the gossip
        network as is.
        """
        # pylint: disable=invalid-name

        # break the path into its component parts
        components = request.path.split('/')
        while components and components[0] == '':
            components.pop(0)

        prefix = components.pop(0) if components else 'error'
        if prefix not in self.PostPageMap:
            prefix = 'default'

        # process the message encoding
        encoding = request.getHeader('Content-Type')
        data = request.content.getvalue()

        try:
            if encoding == 'application/json':
                minfo = json2dict(data)
            elif encoding == 'application/cbor':
                minfo = cbor2dict(data)
            else:
                return self.error_response(request, http.BAD_REQUEST,
                                           'unknown message encoding, {0}',
                                           encoding)

            typename = minfo.get('__TYPE__', '**UNSPECIFIED**')
            if typename not in self.Ledger.MessageHandlerMap:
                return self.error_response(
                    request, http.BAD_REQUEST,
                    'received request for unknown message type, {0}', typename)

            msg = self.Ledger.MessageHandlerMap[typename][0](minfo)

        except:
            logger.info('exception while decoding http request %s; %s',
                        request.path, traceback.format_exc(20))
            return self.error_response(
                request, http.BAD_REQUEST,
                'unabled to decode incoming request {0}', data)

        # and finally execute the associated method and send back the results
        try:
            response = self.PostPageMap[prefix](request, components, msg)

            request.responseHeaders.addRawHeader("content-type", encoding)
            if encoding == 'application/json':
                return dict2json(response.dump())
            else:
                return dict2cbor(response.dump())

        except Error as e:
            return self.error_response(
                request, int(e.status),
                'exception while processing request {0}; {1}', request.path,
                str(e))

        except:
            logger.info('exception while processing http request %s; %s',
                        request.path, traceback.format_exc(20))
            return self.error_response(request, http.BAD_REQUEST,
                                       'error processing http request {0}',
                                       request.path)
    def render_post(self, request, components, msg):
        """
        Forward a signed message through the gossip network.
        """
        encoding = request.getHeader('Content-Type')
        data = request.content.getvalue()
        try:
            if encoding == 'application/json':
                minfo = json2dict(data)

            elif encoding == 'application/cbor':
                minfo = cbor2dict(data)
            else:
                raise Error(
                    "", 'unknown message'
                    ' encoding: {0}'.format(encoding))
            typename = minfo.get('__TYPE__', '**UNSPECIFIED**')
            if typename not in self.Ledger.MessageHandlerMap:
                raise Error(
                    "", 'received request for unknown message'
                    ' type, {0}'.format(typename))
            msg = self.Ledger.MessageHandlerMap[typename][0](minfo)
        except Error as e:
            LOGGER.info('exception while decoding http request %s; %s',
                        request.path, traceback.format_exc(20))
            raise Error(http.BAD_REQUEST,
                        'unable to decode incoming request: {0}'.format(e))

        if self.Validator.Config.get("LocalValidation", True):
            # determine if the message contains a valid transaction before
            # we send the message to the network

            # we need to start with a copy of the message due to cases
            # where side effects of the validity check may impact objects
            # related to msg
            mymsg = copy.deepcopy(msg)

            if hasattr(mymsg, 'Transaction') and mymsg.Transaction is not None:
                mytxn = mymsg.Transaction
                LOGGER.info(
                    'starting local validation '
                    'for txn id: %s type: %s', mytxn.Identifier,
                    mytxn.TransactionTypeName)

                pending_block_txns = None
                if self.Ledger.PendingTransactionBlock is not None:
                    pending_block_txns = \
                        self.Ledger.PendingTransactionBlock.TransactionIDs

                block_id = self.Ledger.MostRecentCommittedBlockID

                real_store_map = \
                    self.Ledger.GlobalStoreMap.get_block_store(block_id)
                temp_store_map = \
                    global_store_manager.BlockStore(real_store_map)
                if not temp_store_map:
                    LOGGER.info('no store map for block %s', block_id)
                    raise Error(
                        http.BAD_REQUEST, 'unable to validate enclosed'
                        ' transaction {0}'.format(data))

                pending_txns = copy.copy(self.Ledger.PendingTransactions)
                pending_txn_ids = [x for x in pending_txns.iterkeys()]

                # clone a copy of the ledger's message queue so we can
                # temporarily play forward all locally submitted yet
                # uncommitted transactions
                my_queue = copy.deepcopy(self.Ledger.MessageQueue)

                transaction_type = mytxn.TransactionTypeName
                if transaction_type not in temp_store_map.TransactionStores:
                    LOGGER.info('transaction type %s not in global store map',
                                transaction_type)
                    raise Error(
                        http.BAD_REQUEST, 'unable to validate enclosed'
                        ' transaction {0}'.format(data))

                if pending_block_txns is not None:
                    pending_txn_ids = pending_block_txns + pending_txn_ids

                # apply any local pending transactions
                for txn_id in pending_txn_ids:
                    pend_txn = self.Ledger.TransactionStore[txn_id]
                    my_store = temp_store_map.get_transaction_store(
                        pend_txn.TransactionTypeName)
                    if pend_txn and pend_txn.is_valid(my_store):
                        my_pend_txn = copy.copy(pend_txn)
                        my_pend_txn.apply(my_store)

                # apply any enqueued messages
                while len(my_queue) > 0:
                    qmsg = my_queue.pop()
                    if qmsg and \
                            qmsg.MessageType in self.Ledger.MessageHandlerMap:
                        if (hasattr(qmsg, 'Transaction')
                                and qmsg.Transaction is not None):
                            my_store = temp_store_map.get_transaction_store(
                                qmsg.Transaction.TransactionTypeName)
                            if qmsg.Transaction.is_valid(my_store):
                                myqtxn = copy.copy(qmsg.Transaction)
                                myqtxn.apply(my_store)

                # determine validity of the POSTed transaction against our
                # new temporary state
                my_store = temp_store_map.get_transaction_store(
                    mytxn.TransactionTypeName)
                try:
                    mytxn.check_valid(my_store)
                except InvalidTransactionError as e:
                    LOGGER.info(
                        'submitted transaction fails transaction '
                        'family validation check: %s; %s', request.path,
                        mymsg.dump())
                    raise Error(
                        http.BAD_REQUEST,
                        "enclosed transaction failed transaction "
                        "family validation check: {}".format(str(e)))
                except:
                    LOGGER.info(
                        'submitted transaction is '
                        'not valid %s; %s; %s', request.path, mymsg.dump(),
                        traceback.format_exc(20))
                    raise Error(
                        http.BAD_REQUEST, "enclosed transaction is not"
                        " valid {}".format(data))

                LOGGER.info('transaction %s is valid',
                            msg.Transaction.Identifier)

        # and finally execute the associated method
        # and send back the results

        self.Ledger.handle_message(msg)
        return msg
Esempio n. 41
0
    def verify_signup_info(cls, signup_info, originator_public_key_hash,
                           most_recent_wait_certificate_id):
        # Verify the attestation verification report signature
        proof_data_dict = json2dict(signup_info.proof_data)
        verification_report = proof_data_dict.get('verification_report')
        if verification_report is None:
            raise \
                SignupInfoError(
                    'Verification report is missing from proof data')

        signature = proof_data_dict.get('signature')
        if signature is None:
            raise \
                SignupInfoError(
                    'Signature is missing from proof data')

        if not signing.verify(verification_report, signature,
                              cls._report_public_key):
            raise \
                SignupInfoError('Verification report signature is invalid')

        verification_report_dict = json2dict(verification_report)

        # Verify that the verification report contains a PSE manifest status
        # and it is OK
        pse_manifest_status = \
            verification_report_dict.get('pseManifestStatus')
        if pse_manifest_status is None:
            raise \
                SignupInfoError(
                    'Verification report does not contain a PSE manifest '
                    'status')
        if pse_manifest_status != 'OK':
            raise \
                SignupInfoError(
                    'PSE manifest status is {} (i.e., not OK)'.format(
                        pse_manifest_status))

        # Verify that the verification report contains a PSE manifest hash
        # and it is the value we expect
        pse_manifest_hash = \
            verification_report_dict.get('pseManifestHash')
        if pse_manifest_hash is None:
            raise \
                SignupInfoError(
                    'Verification report does not contain a PSE manifest '
                    'hash')

        expected_pse_manifest_hash = \
            base64.b64encode(
                hashlib.sha256(
                    b'Do you believe in manifest destiny?').hexdigest())

        if pse_manifest_hash != expected_pse_manifest_hash:
            raise \
                SignupInfoError(
                    'PSE manifest hash {0} does not match {1}'.format(
                        pse_manifest_hash,
                        expected_pse_manifest_hash))

        # Verify that the verification report contains an enclave quote and
        # that its status is OK
        enclave_quote_status = \
            verification_report_dict.get('isvEnclaveQuoteStatus')
        if enclave_quote_status is None:
            raise \
                SignupInfoError(
                    'Verification report does not contain an enclave quote '
                    'status')
        if enclave_quote_status != 'OK':
            raise \
                SignupInfoError(
                    'Enclave quote status is {} (i.e., not OK)'.format(
                        enclave_quote_status))

        enclave_quote = verification_report_dict.get('isvEnclaveQuoteBody')
        if enclave_quote is None:
            raise \
                SignupInfoError(
                    'Verification report does not contain an enclave quote')

        # Verify that the enclave quote contains a report body with the value
        # we expect (i.e., SHA256(SHA256(OPK)|PPK)
        report_data = '{0}{1}'.format(originator_public_key_hash.upper(),
                                      signup_info.poet_public_key.upper())
        expected_report_body = hashlib.sha256(
            dict2json(report_data)).hexdigest()

        enclave_quote_dict = \
            json2dict(base64.b64decode(enclave_quote))
        report_body = enclave_quote_dict.get('report_body')
        if report_body is None:
            raise \
                SignupInfoError(
                    'Enclave quote does not contain a report body')

        if report_body != expected_report_body:
            raise \
                SignupInfoError(
                    'Enclave quote report body {0} does not match {1}'.format(
                        report_body,
                        expected_report_body))

        # Verify that the wait certificate ID in the verification report
        # matches the provided wait certificate ID.  The wait certificate ID
        # is stored in the nonce field.
        nonce = verification_report_dict.get('nonce')
        if nonce is None:
            raise \
                SignupInfoError(
                    'Verification report does not have a nonce')
    def verify_signup_info(cls,
                           signup_info,
                           originator_public_key_hash,
                           most_recent_wait_certificate_id):
        # Verify the attestation verification report signature
        proof_data_dict = json2dict(signup_info.proof_data)
        verification_report = proof_data_dict.get('verification_report')
        if verification_report is None:
            raise ValueError('Verification report is missing from proof data')

        signature = proof_data_dict.get('signature')
        if signature is None:
            raise ValueError('Signature is missing from proof data')

        if not signing.verify(
                verification_report,
                signature,
                cls._report_public_key):
            raise ValueError('Verification report signature is invalid')

        verification_report_dict = json2dict(verification_report)

        # Verify that the verification report contains a PSE manifest status
        # and it is OK
        pse_manifest_status = \
            verification_report_dict.get('pseManifestStatus')
        if pse_manifest_status is None:
            raise \
                ValueError(
                    'Verification report does not contain a PSE manifest '
                    'status')
        if pse_manifest_status != 'OK':
            raise \
                ValueError(
                    'PSE manifest status is {} (i.e., not OK)'.format(
                        pse_manifest_status))

        # Verify that the verification report contains a PSE manifest hash
        # and it is the value we expect
        pse_manifest_hash = \
            verification_report_dict.get('pseManifestHash')
        if pse_manifest_hash is None:
            raise \
                ValueError(
                    'Verification report does not contain a PSE manifest '
                    'hash')

        expected_pse_manifest_hash = \
            base64.b64encode(
                hashlib.sha256(
                    bytes(b'Do you believe in '
                          b'manifest destiny?')).hexdigest()
                .encode()).decode()

        if pse_manifest_hash != expected_pse_manifest_hash:
            raise \
                ValueError(
                    'PSE manifest hash {0} does not match {1}'.format(
                        pse_manifest_hash,
                        expected_pse_manifest_hash))

        # Verify that the verification report contains an enclave quote and
        # that its status is OK
        enclave_quote_status = \
            verification_report_dict.get('isvEnclaveQuoteStatus')
        if enclave_quote_status is None:
            raise \
                ValueError(
                    'Verification report does not contain an enclave quote '
                    'status')
        if enclave_quote_status != 'OK':
            raise \
                ValueError(
                    'Enclave quote status is {} (i.e., not OK)'.format(
                        enclave_quote_status))

        enclave_quote = verification_report_dict.get('isvEnclaveQuoteBody')
        if enclave_quote is None:
            raise \
                ValueError(
                    'Verification report does not contain an enclave quote')

        # Verify that the enclave quote contains a report body with the value
        # we expect (i.e., SHA256(SHA256(OPK)|PPK)
        report_data = '{0}{1}'.format(
            originator_public_key_hash.upper(),
            signup_info.poet_public_key.upper()
        )
        expected_report_body = hashlib.sha256(
            dict2json(report_data).encode()).hexdigest()

        enclave_quote_dict = \
            json2dict(base64.b64decode(enclave_quote).decode())
        report_body = enclave_quote_dict.get('report_body')
        if report_body is None:
            raise ValueError('Enclave quote does not contain a report body')

        if report_body != expected_report_body:
            raise \
                ValueError(
                    'Enclave quote report body {0} does not match {1}'.format(
                        report_body,
                        expected_report_body))

        # Verify that the wait certificate ID in the verification report
        # matches the provided wait certificate ID.  The wait certificate ID
        # is stored in the nonce field.
        nonce = verification_report_dict.get('nonce')
        if nonce is None:
            raise \
                ValueError(
                    'Verification report does not have a nonce')
Esempio n. 43
0
    def postmsg(self, msgtype, info):
        """
        Post a transaction message to the validator, parse the returning CBOR
        and return the corresponding dictionary.
        """

        data = dict2cbor(info)
        datalen = len(data)
        url = urlparse.urljoin(self._base_url, msgtype)

        LOGGER.debug('post transaction to %s with DATALEN=%d, DATA=<%s>', url,
                     datalen, data)

        try:
            request = urllib2.Request(url, data, {
                'Content-Type': 'application/cbor',
                'Content-Length': datalen
            })

            if self._cookie:
                request.add_header('cookie', self._cookie)

            opener = urllib2.build_opener(self._proxy_handler)
            response = opener.open(request, timeout=10)
            if not self._cookie:
                self._cookie = response.headers.get('Set-Cookie')
        except urllib2.HTTPError as err:
            content = err.read()
            if content is not None:
                headers = err.info()
                encoding = headers.get('Content-Type')

                if encoding == 'application/json':
                    value = json2dict(content)
                elif encoding == 'application/cbor':
                    value = cbor2dict(content)
                else:
                    LOGGER.warn('operation failed with response: %s', err.code)
                    raise MessageException(
                        'operation failed with response: {0}'.format(err.code))
                LOGGER.warn('operation failed with response: %s %s', err.code,
                            str(value))
                if "errorType" in value:
                    if value['errorType'] == "InvalidTransactionError":
                        raise InvalidTransactionError(
                            value['error'] if 'error' in value else value)
                    else:
                        raise MessageException(str(value))
            else:
                raise MessageException(
                    'operation failed with response: {0}'.format(err.code))
        except urllib2.URLError as err:
            LOGGER.warn('operation failed: %s', err.reason)
            raise MessageException('operation failed: {0}'.format(err.reason))

        except:
            LOGGER.warn('no response from server')
            raise MessageException('no response from server')

        content = response.read()
        headers = response.info()
        response.close()

        encoding = headers.get('Content-Type')

        if encoding == 'application/json':
            value = json2dict(content)
        elif encoding == 'application/cbor':
            value = cbor2dict(content)
        else:
            LOGGER.info('server responds with message %s of type %s', content,
                        encoding)
            return None

        LOGGER.debug(pretty_print_dict(value))
        return value