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
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
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