Beispiel #1
0
def process_quote_response(instance, json_response):
    """Validates the response from the Cloud node.
    
    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" % instance['nonce'])
        logger.debug("received public key: %s" % received_public_key)
        logger.debug("received ima_measurement_list    %s" %
                     (ima_measurement_list != None))
    except Exception:
        return None

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

    if instance.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"),
            instance['instance_id'])
        if registrar_keys is None:
            logger.warning("AIK not found in registrar, quote not validated")
            return False
        instance['registrar_keys'] = registrar_keys

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

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

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

    # ok we're done
    return validQuote
    def do_PUT(self):
        """This method handles the PUT requests to add instances to the Registrar Server.
        
        Currently, only instances resources are available for PUTing, i.e. /v2/instances. All other PUT uri's
        will return errors.
        """
        rest_params = common.get_restful_params(self.path)
        if rest_params is None:
            common.echo_json_response(
                self, 405, "Not Implemented: Use /v2/instances/ interface")
            return

        if "instances" not in rest_params:
            common.echo_json_response(self, 400, "uri not supported")
            logger.warning(
                'PUT instance returning 400 response. uri not supported: ' +
                self.path)
            return

        instance_id = rest_params["instances"]

        if instance_id is None:
            common.echo_json_response(self, 400,
                                      "instance id not found in uri")
            logger.warning(
                'PUT instance returning 400 response. instance id not found in uri '
                + self.path)
            return

        try:
            content_length = int(self.headers.get('Content-Length', 0))
            if content_length == 0:
                common.echo_json_response(self, 400,
                                          "Expected non zero content length")
                logger.warning(
                    'PUT for ' + instance_id +
                    ' returning 400 response. Expected non zero content length.'
                )
                return

            post_body = self.rfile.read(content_length)
            json_body = json.loads(post_body)

            if "activate" in rest_params:
                auth_tag = json_body['auth_tag']

                instance = self.server.db.get_instance(instance_id)
                if instance is None:
                    raise Exception(
                        "attempting to activate instance before requesting registrar for %s"
                        % instance_id)

                if instance['virtual']:
                    raise Exception(
                        "attempting to activate virtual AIK using physical interface for %s"
                        % instance_id)

                if common.STUB_TPM:
                    self.server.db.update_instance(instance_id, 'active', True)
                else:
                    ex_mac = crypto.do_hmac(base64.b64decode(instance['key']),
                                            instance_id)
                    if ex_mac == auth_tag:
                        self.server.db.update_instance(instance_id, 'active',
                                                       True)
                    else:
                        raise Exception(
                            "Auth tag %s does not match expected value %s" %
                            (auth_tag, ex_mac))

                common.echo_json_response(self, 200, "Success")
                logger.info('PUT activated: ' + instance_id)
            elif "vactivate" in rest_params:
                deepquote = json_body.get('deepquote', None)

                instance = self.server.db.get_instance(instance_id)
                if instance is None:
                    raise Exception(
                        "attempting to activate instance before requesting registrar for %s"
                        % instance_id)

                if not instance['virtual']:
                    raise Exception(
                        "attempting to activate physical AIK using virtual interface for %s"
                        % instance_id)

                # get an physical AIK for this host
                registrar_client.init_client_tls(config, 'registrar')
                provider_keys = registrar_client.getKeys(
                    config.get('general', 'provider_registrar_ip'),
                    config.get('general', 'provider_registrar_tls_port'),
                    instance_id)
                # we already have the vaik
                if not tpm_quote.check_deep_quote(
                        hashlib.sha1(instance['key']).hexdigest(),
                        instance_id + instance['aik'] + instance['ek'],
                        deepquote, instance['aik'], provider_keys['aik']):
                    raise Exception("Deep quote invalid")

                self.server.db.update_instance(instance_id, 'active', True)
                self.server.db.update_instance(instance_id, 'provider_keys',
                                               provider_keys)

                common.echo_json_response(self, 200, "Success")
                logger.info('PUT activated: ' + instance_id)
            else:
                pass
        except Exception as e:
            common.echo_json_response(self, 400, "Error: %s" % e)
            logger.warning("PUT for " + instance_id +
                           " returning 400 response. Error: %s" % e)
            logger.warning(traceback.format_exc())
            return
Beispiel #3
0
def process_quote_response(instance, json_response, config):
    """Validates the response from the Cloud node.
    
    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" % instance['nonce'])
        logger.debug("received public key: %s" % received_public_key)
        logger.debug("received ima_measurement_list    %s" %
                     (ima_measurement_list != None))
    except Exception:
        return None

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

    if instance.get('aikFromRegistrar', "") is "" or instance.get(
            'aikFromRegistrarCacheHits', common.MAX_STALE_REGISTRAR_CACHE
    ) >= common.MAX_STALE_REGISTRAR_CACHE:
        # talk to yourself fool
        registrar_client.serverAuthTLSContext(config, 'cloud_verifier')
        aikFromRegistrar = registrar_client.getAIK(
            config.get("general", "registrar_ip"),
            config.get("general", "registrar_port"), instance['instance_id'])
        if aikFromRegistrar is None:
            logger.warning("AIK not found in registrar, quote not validated")
            return False
        instance['aikFromRegistrar'] = aikFromRegistrar
        instance['aikFromRegistrarCacheHits'] = 0
    else:
        aikFromRegistrar = instance['aikFromRegistrar']
        instance['aikFromRegistrarCacheHits'] += 1

    if not instance['vtpm_policy']:
        validQuote = tpm_quote.check_quote(instance['nonce'],
                                           received_public_key, quote,
                                           aikFromRegistrar,
                                           instance['tpm_policy'],
                                           ima_measurement_list,
                                           instance['ima_whitelist'])
    else:
        registrar_client.serverAuthTLSContext(config, 'cloud_verifier')
        dq_aik = registrar_client.getAIK(
            config.get("general", "provider_registrar_ip"),
            config.get("general", "provider_registrar_port"),
            instance['instance_id'])
        if dq_aik is None:
            logger.warning(
                "provider AIK not found in registrar, deep quote not validated"
            )
            return False
        validQuote = tpm_quote.check_deep_quote(
            instance['nonce'], received_public_key, quote, aikFromRegistrar,
            dq_aik, instance['vtpm_policy'], instance['tpm_policy'],
            ima_measurement_list, instance['ima_whitelist'])
    if not validQuote:
        return False

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

    # ok we're done
    return validQuote
Beispiel #4
0
    def do_PUT(self):
        """This method handles the POST requests to add instances to the Registrar Server. 
        
        Currently, only instances resources are available for POSTing, i.e. /v1/instances. All other POST uri's 
        will return errors. PUT requests require an an instance_id identifying the instance to add, and json 
        block sent in the body with 2 entries: ek and aik.  
        """
        if not self.is_instance_resource():
            self.send_response(400)
            self.end_headers()
            logger.warning('PUT instance returning 400 response. uri not supported: ' + self.path)
            return
        
        instance_id = self.get_resource_name()
        
        if instance_id is None:
            self.send_response(400)
            self.end_headers()
            logger.warning('PUT instance returning 400 response. instance_id not found in uri ' + self.path)
            return                   

        try:
            content_length = int(self.headers.get('Content-Length', 0))
            if content_length == 0:
                self.send_response(400)
                self.end_headers()
                logger.warning('PUT for ' + instance_id + ' returning 400 response. Expected non zero content length.')
                return 
        
            post_body = self.rfile.read(content_length)
            json_body = json.loads(post_body)
            
            command = json_body['command']
            
            if command=='register_node':
                ek = json_body['ek']
                ekcert = json_body['ekcert']
                aik = json_body['aik']
                
                # config option must be on to check for EK certs
                if config.getboolean('registrar','require_ek_cert'):
                    # no EK provided
                    if ekcert is None and not common.DEVELOP_IN_ECLIPSE:
                        raise Exception("No EK cert provided, require_ek_cert option in config set to True")
                    
                    # there is an EK
                    if not common.STUB_TPM and (ekcert!=None and ekcert!='virtual' and not tpm_initialize.verify_ek(base64.b64decode(ekcert), ek)):
                            raise Exception("Invalid EK certificate")
                
                # try to encrypt the AIK
                (blob,key) = tpm_initialize.encryptAIK(instance_id,aik,ek)
                self.server.add_instance(instance_id, key, aik,ek,ekcert)
                response = {
                        'blob': blob,
                }
                json_response = json.dumps(response)
                self.send_response(200)
                self.end_headers()
                self.wfile.write(json_response)
                
                logger.info('PUT returning key blob for instance_id: ' + instance_id)
                return
            elif command=='activate_node':
                auth_tag=json_body['auth_tag']
                
                instance = self.server.find_instance(instance_id)
                if instance is None:
                    raise Exception("attempting to activate instance before requesting registrar for %s"%instance_id)
         
                if instance['virtual']:
                    raise Exception("attempting to activate virtual AIK using physical interface for %s"%instance_id)
                
                if common.STUB_TPM:
                    self.server.update_instance(instance_id, 'active',True)
                else:
                    ex_mac = crypto.do_hmac(base64.b64decode(instance['key']),instance_id)
                    if ex_mac == auth_tag:
                        self.server.update_instance(instance_id, 'active',True)
                    else:
                        raise Exception("Auth tag %s does not match expected value %s"%(auth_tag,ex_mac))
                
                self.send_response(200)
                self.end_headers()
                logger.info('PUT activated: ' + instance_id)      
            elif command=='activate_virtual_node':
                deepquote = json_body.get('deepquote',None)

                instance = self.server.find_instance(instance_id)
                if instance is None:
                    raise Exception("attempting to activate instance before requesting registrar for %s"%instance_id)
                      
                if not instance['virtual']:
                    raise Exception("attempting to activate physical AIK using virtual interface for %s"%instance_id)
                
                # get an physical AIK for this host
                registrar_client.serverAuthTLSContext(config, 'registrar')
                dq_aik = registrar_client.getAIK(config.get('general', 'provider_registrar_ip'), config.get('general', 'provider_registrar_port'), instance_id)
                # we already have the vaik
                if not tpm_quote.check_deep_quote(hashlib.sha1(instance['key']),
                                                  instance_id+instance['aik']+instance['ek'], 
                                                  deepquote,  
                                                  instance['aik'],  
                                                  dq_aik):
                    raise Exception("Deep quote invalid")
                
                self.server.update_instance(instance_id, 'active',True)
                
                self.send_response(200)
                self.end_headers()
                logger.info('PUT activated: ' + instance_id)           
            else:
                pass           
        except Exception as e:
            self.send_response(400)
            self.end_headers()
            logger.warning("PUT for " + instance_id + " returning 400 response. Error: %s"%e)
            logger.warning(traceback.format_exc())
            return