示例#1
0
    def do_quote(self):
        """initiaite v, agent_id and ip
        initiate the cloudinit sequence"""
        self.nonce = TPM_Utilities.random_password(20)

        numtries = 0
        response = None
        # Note: We need a specific retry handler (perhaps in common), no point having localised unless we have too.
        while True:
            try:
                #params = '/quotes/identity?nonce=%s'%(self.nonce)
                params = f'/quotes/identity?nonce={self.nonce}'
                response = httpclient_requests.request("GET", "%s"%(self.cloudagent_ip), self.cloudagent_port, params=params, context=None)
                response_body = json.loads(response.read().decode())
            except Exception as e:
                if response == 503 or response == 504:
                    numtries+=1
                    maxr = config.getint('tenant','max_retries')
                    if numtries >= maxr:
                        logger.error(f"tenant cannot establish connection to agent on {self.cloudagent_ip} with port {self.cloudagent_port}")
                        exit()
                    retry  = config.getfloat('tenant','retry_interval')
                    logger.info(f"tenant connection to agent at {self.cloudagent_ip} refused {numtries}/{maxr} times, trying again in {retry} seconds...")
                    time.sleep(retry)
                    continue
                else:
                    raise(e)
            break

        try:
            if response is not None and response.status != 200:
                raise UserError("Status command response: %d Unexpected response from Cloud Agent."%response.status)

            if "results" not in response_body:
                raise UserError("Error: unexpected http response body from Cloud Agent: %s"%str(response.status))

            quote = response_body["results"]["quote"]
            logger.debug(f"agent_quote received quote: {quote}")

            public_key = response_body["results"]["pubkey"]
            logger.debug(f"agent_quote received public key: {public_key}")

            # Get tpm_version, hash_alg
            tpm_version = response_body["results"]["tpm_version"]
            logger.debug(f"agent_quote received tpm version: {str(tpm_version)}")

            # Ensure hash_alg is in accept_tpm_hash_algs list
            hash_alg = response_body["results"]["hash_alg"]
            logger.debug(f"agent_quote received hash algorithm: {hash_alg}")
            if not Hash_Algorithms.is_accepted(hash_alg, config.get('tenant','accept_tpm_hash_algs').split(',')):
                raise UserError("TPM Quote is using an unaccepted hash algorithm: %s"%hash_alg)

            # Ensure enc_alg is in accept_tpm_encryption_algs list
            enc_alg = response_body["results"]["enc_alg"]
            logger.debug(f"agent_quote received encryption algorithm: {enc_alg}")
            if not Encrypt_Algorithms.is_accepted(enc_alg, config.get('tenant','accept_tpm_encryption_algs').split(',')):
                raise UserError("TPM Quote is using an unaccepted encryption algorithm: %s"%enc_alg)

            # Ensure sign_alg is in accept_tpm_encryption_algs list
            sign_alg = response_body["results"]["sign_alg"]
            logger.debug(f"agent_quote received signing algorithm: {sign_alg}")
            if not Sign_Algorithms.is_accepted(sign_alg, config.get('tenant','accept_tpm_signing_algs').split(',')):
                raise UserError("TPM Quote is using an unaccepted signing algorithm: %s"%sign_alg)

            if not self.validate_tpm_quote(public_key, quote, tpm_version, hash_alg):
                raise UserError("TPM Quote from cloud agent is invalid for nonce: %s"%self.nonce)

            logger.info(f"Quote from {self.cloudagent_ip} validated")

            # encrypt U with the public key
            # encrypted_U = crypto.rsa_encrypt(crypto.rsa_import_pubkey(public_key),str(self.U))
            encrypted_U = crypto.rsa_encrypt(crypto.rsa_import_pubkey(public_key),self.U)

            b64_encrypted_u = base64.b64encode(encrypted_U)
            logger.debug("b64_encrypted_u: " + b64_encrypted_u.decode('utf-8'))
            data = {
                      'encrypted_key': b64_encrypted_u,
                      'auth_tag': self.auth_tag
                    }

            if self.payload is not None:
                data['payload']=self.payload

            u_json_message = json.dumps(data)

            #post encrypted U back to CloudAgent
            params = '/keys/ukey'
            response = httpclient_requests.request("POST", "%s"%(self.cloudagent_ip), self.cloudagent_port, params=params, data=u_json_message)

            if response == 503:
                logger.error(f"Cannot connect to Verifier at {self.cloudverifier_ip} with Port {self.cloudverifier_port}. Connection refused.")
                exit()
            elif response == 504:
                logger.error(f"Verifier at {self.cloudverifier_ip} with Port {self.cloudverifier_port} timed out.")
                exit()

            if response.status != 200:
                keylime_logging.log_http_response(logger,logging.ERROR,response_body)
                raise UserError("Posting of Encrypted U to the Cloud Agent failed with response code %d" %response.status)

        except Exception as e:
            self.do_cvstop()
            raise e
示例#2
0
def process_quote_response(agent, json_response):
    """Validates the response from the Cloud agent.

    This method invokes an Registrar Server call to register, and then check the quote.
    """
    received_public_key = None
    quote = None

    # in case of failure in response content do not continue
    try:
        received_public_key = json_response.get("pubkey", None)
        quote = json_response["quote"]

        ima_measurement_list = json_response.get("ima_measurement_list", None)

        logger.debug("received quote:      %s" % quote)
        logger.debug("for nonce:           %s" % agent['nonce'])
        logger.debug("received public key: %s" % received_public_key)
        logger.debug("received ima_measurement_list    %s" %
                     (ima_measurement_list is not None))
    except Exception:
        return None

    # if no public key provided, then ensure we have cached it
    if received_public_key is None:
        if agent.get('public_key', "") == "" or agent.get(
                'b64_encrypted_V', "") == "":
            logger.error(
                "agent did not provide public key and no key or encrypted_v was cached at CV"
            )
            return False
        agent['provide_V'] = False
        received_public_key = agent['public_key']

    if agent.get('registrar_keys', "") is "":
        registrar_client.init_client_tls(config, 'cloud_verifier')
        registrar_keys = registrar_client.getKeys(
            config.get("general", "registrar_ip"),
            config.get("general", "registrar_tls_port"), agent['agent_id'])
        if registrar_keys is None:
            logger.warning("AIK not found in registrar, quote not validated")
            return False
        agent['registrar_keys'] = registrar_keys

    tpm_version = json_response.get('tpm_version')
    tpm = tpm_obj.getTPM(need_hw_tpm=False, tpm_version=tpm_version)
    hash_alg = json_response.get('hash_alg')
    enc_alg = json_response.get('enc_alg')
    sign_alg = json_response.get('sign_alg')

    # Update chosen tpm and algorithms
    agent['tpm_version'] = tpm_version
    agent['hash_alg'] = hash_alg
    agent['enc_alg'] = enc_alg
    agent['sign_alg'] = sign_alg

    # Ensure hash_alg is in accept_tpm_hash_alg list
    if not Hash_Algorithms.is_accepted(hash_alg,
                                       agent['accept_tpm_hash_algs']):
        raise Exception("TPM Quote is using an unaccepted hash algorithm: %s" %
                        hash_alg)

    # Ensure enc_alg is in accept_tpm_encryption_algs list
    if not Encrypt_Algorithms.is_accepted(enc_alg,
                                          agent['accept_tpm_encryption_algs']):
        raise Exception(
            "TPM Quote is using an unaccepted encryption algorithm: %s" %
            enc_alg)

    # Ensure sign_alg is in accept_tpm_encryption_algs list
    if not Sign_Algorithms.is_accepted(sign_alg,
                                       agent['accept_tpm_signing_algs']):
        raise Exception(
            "TPM Quote is using an unaccepted signing algorithm: %s" %
            sign_alg)

    if tpm.is_deep_quote(quote):
        validQuote = tpm.check_deep_quote(
            agent['agent_id'], agent['nonce'], received_public_key, quote,
            agent['registrar_keys']['aik'],
            agent['registrar_keys']['provider_keys']['aik'],
            agent['vtpm_policy'], agent['tpm_policy'], ima_measurement_list,
            agent['ima_whitelist'])
    else:
        validQuote = tpm.check_quote(agent['agent_id'], agent['nonce'],
                                     received_public_key, quote,
                                     agent['registrar_keys']['aik'],
                                     agent['tpm_policy'], ima_measurement_list,
                                     agent['ima_whitelist'], hash_alg)
    if not validQuote:
        return False

    # set a flag so that we know that the agent was verified once.
    # we only issue notifications for agents that were at some point good
    agent['first_verified'] = True

    # has public key changed? if so, clear out b64_encrypted_V, it is no longer valid
    if received_public_key != agent.get('public_key', ""):
        agent['public_key'] = received_public_key
        agent['b64_encrypted_V'] = ""
        agent['provide_V'] = True

    # ok we're done
    return validQuote