def get_openstack_uuid(uuid_service_ip='169.254.169.254', uuid_service_resource='/openstack/2012-08-10/meta_data.json'): logger.debug("Getting instance UUID from openstack http://%s%s"%(uuid_service_ip,uuid_service_resource)) try: response = tornado_requests.request("GET", "http://" + uuid_service_ip + uuid_service_resource) if response.status_code == 200: response_body = response.json() return response_body["uuid"] logger.debug("Forcing using locally generated uuid.") return str(uuid.uuid4()) except Exception: logger.debug("Using locally generated uuid. Error getting UUID from openstack: %s\n"%(e)) return str(uuid.uuid4())
def do_cvreactivate(self): response = tornado_requests.request( "PUT", "http://%s:%s/v2/instances/%s/reactivate" % (self.cloudverifier_ip, self.cloudverifier_port, self.node_uuid), context=self.context, data=b'') if response.status_code != 200: logger.error( "Update command response: %d Unexpected response from Cloud Verifier." % response.status_code) common.log_http_response(logger, logging.ERROR, response.json()) else: logger.info("Node %s re-activated" % (self.node_uuid))
def test_031_cv_instance_put(self): """Test CV's PUT /v2/instances/{UUID} Interface""" #TODO: this should actually test PUT functionality (e.g., make node fail and then PUT back up) response = tornado_requests.request( "PUT", "http://%s:%s/v2/instances/%s"%(tenant_templ.cloudverifier_ip,tenant_templ.cloudverifier_port,tenant_templ.node_uuid), data=b'', context=tenant_templ.context ) self.assertEqual(response.status_code, 200, "Non-successful CV Instance Post return code!") response_body = response.json() # Ensure response is well-formed self.assertIn("results", response_body, "Malformed response body!")
def test_010_reg_instance_post(self): """Test registrar's POST /v2/instances/{UUID} Interface""" global keyblob, aik, vtpm, ek # Change CWD for TPM-related operations cwd = os.getcwdu() common.ch_dir(common.WORK_DIR,None) secdir = secure_mount.mount() # Initialize the TPM with AIK (ek,ekcert,aik) = tpm_initialize.init(self_activate=False,config_pw=config.get('cloud_node','tpm_ownerpassword')) vtpm = tpm_initialize.is_vtpm() # Seed RNG (root only) if common.REQUIRE_ROOT: tpm_random.init_system_rand() # Handle virtualized and emulated TPMs if ekcert is None: if vtpm: ekcert = 'virtual' elif tpm_initialize.is_emulator(): ekcert = 'emulator' # Get back to our original CWD common.ch_dir(cwd,None) data = { 'ek': ek, 'ekcert': ekcert, 'aik': aik, } v_json_message = json.dumps(data) response = tornado_requests.request( "POST", "http://%s:%s/v2/instances/%s"%(tenant_templ.registrar_ip,tenant_templ.registrar_boot_port,tenant_templ.node_uuid), data=v_json_message, context=None ) self.assertEqual(response.status_code, 200, "Non-successful Registrar Instance Add return code!") response_body = response.json() # Ensure response is well-formed self.assertIn("results", response_body, "Malformed response body!") self.assertIn("blob", response_body["results"], "Malformed response body!") keyblob = response_body["results"]["blob"] self.assertIsNotNone(keyblob, "Malformed response body!")
def doRegisterAgent(registrar_ip, registrar_port, agent_id, tpm_version, pub_ek, ekcert, pub_aik, pub_ek_tpm=None, aik_name=None): data = { 'ek': pub_ek, 'ekcert': ekcert, 'aik': pub_aik, 'aik_name': aik_name, 'ek_tpm': pub_ek_tpm, 'tpm_version': tpm_version, } v_json_message = json.dumps(data) response = tornado_requests.request( "POST", "http://%s:%s/agents/%s" % (registrar_ip, registrar_port, agent_id), data=v_json_message, context=None) response_body = response.json() if response.status_code != 200: logger.error( "Error: unexpected http response code from Registrar Server: " + str(response.status_code)) common.log_http_response(logger, logging.ERROR, response_body) return None logger.info("Agent registration requested for %s" % agent_id) if "results" not in response_body: logger.critical( "Error: unexpected http response body from Registrar Server: %s" % str(response.status_code)) return None if "blob" not in response_body["results"]: logger.critical( "Error: did not receive blob from Registrar Server: %s" % str(response.status_code)) return None return response_body["results"]["blob"]
def test_050_cv_instance_delete(self): """Test CV's DELETE /v2/instances/{UUID} Interface""" time.sleep(5) response = tornado_requests.request( "DELETE", "http://%s:%s/v2/instances/%s" % (tenant_templ.cloudverifier_ip, tenant_templ.cloudverifier_port, tenant_templ.node_uuid), context=tenant_templ.context) self.assertEqual(response.status_code, 200, "Non-successful CV Instance Delete return code!") response_body = response.json() # Ensure response is well-formed self.assertIn("results", response_body, "Malformed response body!")
def test_013_reg_agents_get(self): """Test registrar's GET /v2/agents Interface""" response = tornado_requests.request( "GET", "http://%s:%s/v%s/agents/"%(tenant_templ.registrar_ip,tenant_templ.registrar_port,self.api_version), context=tenant_templ.context ) self.assertEqual(response.status_code, 200, "Non-successful Registrar agent List return code!") response_body = response.json() # Ensure response is well-formed self.assertIn("results", response_body, "Malformed response body!") self.assertIn("uuids", response_body["results"], "Malformed response body!") # We registered exactly one agent so far self.assertEqual(1, len(response_body["results"]["uuids"]), "Incorrect system state!")
def test_032_cv_agents_get(self): """Test CV's GET /v2/agents Interface""" response = tornado_requests.request( "GET", "http://%s:%s/v%s/agents/"%(tenant_templ.cloudverifier_ip,tenant_templ.cloudverifier_port,self.api_version), context=tenant_templ.context ) self.assertEqual(response.status_code, 200, "Non-successful CV agent List return code!") response_body = response.json() # Ensure response is well-formed self.assertIn("results", response_body, "Malformed response body!") self.assertIn("uuids", response_body["results"], "Malformed response body!") # Be sure our agent is registered self.assertEqual(1, len(response_body["results"]["uuids"]))
def do_cvdelete(self): """initiaite v, instance_id and ip initiate the cloudinit sequence""" response = tornado_requests.request( "DELETE", "http://%s:%s/v2/instances/%s" % (self.cloudverifier_ip, self.cloudverifier_port, self.node_uuid), context=self.context) if response.status_code != 200: logger.error( "Delete command response: %d Unexpected response from Cloud Verifier." % response.status_code) common.log_http_response(logger, logging.ERROR, response.json()) else: logger.info("Node %s deleted from CV" % (self.node_uuid))
def test_033_cv_agent_get(self): """Test CV's GET /v2/agents/{UUID} Interface""" response = tornado_requests.request( "GET", "http://%s:%s/v%s/agents/%s"%(tenant_templ.cloudverifier_ip,tenant_templ.cloudverifier_port,self.api_version,tenant_templ.agent_uuid), context=tenant_templ.context ) self.assertEqual(response.status_code, 200, "Non-successful CV agent return code!") response_body = response.json() # Ensure response is well-formed self.assertIn("results", response_body, "Malformed response body!") # Check a few of the important properties are present self.assertIn("operational_state", response_body["results"], "Malformed response body!") self.assertIn("ip", response_body["results"], "Malformed response body!") self.assertIn("port", response_body["results"], "Malformed response body!")
def get_instance_state(self, instance_id): try: response = tornado_requests.request( "GET", "http://%s:%s/v2/instances/%s" % (tenant_templ.cloudverifier_ip, tenant_templ.cloudverifier_port, instance_id), context=tenant_templ.context) except Exception as e: logger.error( "Status command response: %s:%s Unexpected response from Cloud Verifier." % (tenant_templ.cloudverifier_ip, tenant_templ.cloudverifier_port)) logger.error(traceback.print_exc()) logger.error("Error: %s " % str(e)) common.echo_json_response( self, 500, "Unexpected response from Cloud Verifier", str(e)) return inst_response_body = response.json() if response.status_code != 200 and response.status_code != 404: logger.error( "Status command response: %d Unexpected response from Cloud Verifier." % response.status_code) common.log_http_response(logger, logging.ERROR, inst_response_body) return None if "results" not in inst_response_body: logger.critical( "Error: unexpected http response body from Cloud Verifier: %s" % str(response.status_code)) return None # Node not added to CV (but still registered) if response.status_code == 404: return { "operational_state": cloud_verifier_common.CloudInstance_Operational_State. REGISTERED } else: return inst_response_body["results"] return None
def doActivateVirtualNode(registrar_ip,registrar_port,instance_id,deepquote): global context data = { 'command': 'activate_virtual_node', 'deepquote': deepquote, } v_json_message = json.dumps(data) response = tornado_requests.request("PUT", "http://%s:%s/v1/instance_id/%s"%(registrar_ip,registrar_port,instance_id), data=v_json_message, context=context) if response.status_code == 200: logger.info("Registration activated for node %s."%instance_id) else: logger.error("Error: unexpected http response code from Registrar Server: " + str(response.status_code))
def doActivateNode(registrar_ip,registrar_port,instance_id,key): global context data = { 'command': 'activate_node', 'auth_tag': crypto.do_hmac(base64.b64decode(key),instance_id), } v_json_message = json.dumps(data) response = tornado_requests.request("PUT", "http://%s:%s/v1/instance_id/%s"%(registrar_ip,registrar_port,instance_id), data=v_json_message, context=context) if response.status_code == 200: logger.info("Registration activated for node %s."%instance_id) else: logger.error("Error: unexpected http response code from Registrar Server: " + str(response.status_code))
def doActivateVirtualNode(registrar_ip,registrar_port,instance_id,deepquote): data = { 'deepquote': deepquote, } v_json_message = json.dumps(data) response = tornado_requests.request("PUT", "http://%s:%s/v2/instances/%s/vactivate"%(registrar_ip,registrar_port,instance_id), data=v_json_message, context=None) if response.status_code == 200: logger.info("Registration activated for node %s."%instance_id) return True else: logger.error("Error: unexpected http response code from Registrar Server: " + str(response.status_code)) common.log_http_response(logger,logging.ERROR,response.json()) return False
def doActivateNode(registrar_ip,registrar_port,instance_id,key): data = { 'auth_tag': crypto.do_hmac(base64.b64decode(key),instance_id), } v_json_message = json.dumps(data) response = tornado_requests.request("PUT", "http://%s:%s/v2/instances/%s/activate"%(registrar_ip,registrar_port,instance_id), data=v_json_message, context=None) if response.status_code == 200: logger.info("Registration activated for node %s."%instance_id) return True else: logger.error("Error: unexpected http response code from Registrar Server: " + str(response.status_code)) common.log_http_response(logger,logging.ERROR,response.json()) return False
def getKeys(registrar_ip, registrar_port, instance_id): global context #make absolutely sure you don't ask for AIKs unauthenticated if context is None or context.verify_mode != ssl.CERT_REQUIRED: raise Exception( "It is unsafe to use this interface to query AIKs with out server authenticated TLS" ) try: response = tornado_requests.request( "GET", "http://%s:%s/v2/instances/%s" % (registrar_ip, registrar_port, instance_id), context=context) response_body = response.json() if response.status_code != 200: logger.critical( "Error: unexpected http response code from Registrar Server: %s" % str(response.status_code)) common.log_http_response(logger, logging.CRITICAL, response_body) return None if "results" not in response_body: logger.critical( "Error: unexpected http response body from Registrar Server: %s" % str(response.status_code)) return None if "aik" not in response_body["results"]: logger.critical( "Error: did not receive aik from Registrar Server: %s" % str(response.status_code)) return None return response_body["results"] except Exception as e: logger.critical(traceback.format_exc()) logger.critical("An unexpected error occurred: " + str(e)) return None
def do_verify(self): """initiaite v, instance_id and ip initiate the cloudinit sequence""" challenge = tpm_initialize.random_password(20) numtries = 0 while True: try: response = tornado_requests.request("GET", "http://%s:%s/v2/keys/verify/challenge/%s/"%(self.cloudnode_ip,self.cloudnode_port,challenge)) except Exception as e: # this is one exception that should return a 'keep going' response if tornado_requests.is_refused(e): numtries+=1 maxr = config.getint('tenant','max_retries') if numtries >= maxr: logger.error("Quitting after max number of retries to connect to %s"%(self.cloudnode_ip)) raise e retry = config.getfloat('tenant','retry_interval') logger.info("Connection to %s refused %d/%d times, trying again in %f seconds..."%(self.cloudnode_ip,numtries,maxr,retry)) time.sleep(retry) continue else: raise e response_body = response.json() if response.status_code == 200: if "results" not in response_body or 'hmac' not in response_body['results']: logger.critical("Error: unexpected http response body from Cloud Node: %s"%str(response.status_code)) break mac = response_body['results']['hmac'] ex_mac = crypto.do_hmac(self.K,challenge) if mac == ex_mac: logger.info("Key derivation successful") else: logger.error("Key derivation failed") else: common.log_http_response(logger,logging.ERROR,response_body) retry = config.getfloat('tenant','retry_interval') logger.error("Key derivation not yet complete...trying again in %s seconds...Ctrl-C to stop"%retry) time.sleep(retry) continue break;
def test_014_reg_agent_get(self): """Test registrar's GET /v2/agents/{UUID} Interface""" global aik response = tornado_requests.request( "GET", "http://%s:%s/v%s/agents/%s"%(tenant_templ.registrar_ip,tenant_templ.registrar_port,self.api_version,tenant_templ.agent_uuid), context=tenant_templ.context ) self.assertEqual(response.status_code, 200, "Non-successful Registrar agent return code!") response_body = response.json() # Ensure response is well-formed self.assertIn("results", response_body, "Malformed response body!") self.assertIn("aik", response_body["results"], "Malformed response body!") self.assertIn("ek", response_body["results"], "Malformed response body!") self.assertIn("ekcert", response_body["results"], "Malformed response body!") aik = response_body["results"]["aik"]
def do_cvdelete(self): """initiaite v, instance_id and ip initiate the cloudinit sequence""" params = { 'instance_id': self.node_uuid, } response = tornado_requests.request( "DELETE", "http://%s:%s/v1/instances" % (self.cloudverifier_ip, self.cloudverifier_port), params=params, context=self.context) if response.status_code != 200: logger.error( "Delete command response: %d Unexpected response from Cloud Verifier." % response.status_code) else: logger.info("Node %s deleted from CV" % (self.node_uuid))
def post_cfssl(url,data): numtries = 0 maxr = 10 retry=0.05 while True: try: response = tornado_requests.request("POST",url,params=None,data=data,context=None) break except Exception as e: if tornado_requests.is_refused(e): numtries+=1 if numtries >= maxr: logger.error("Quiting after max number of retries to connect to cfssl server") raise e logger.info("Connection to cfssl refused %d/%d times, trying again in %f seconds..."%(numtries,maxr,retry)) time.sleep(retry) continue else: raise e return response
def do_cvstatus(self, listing=False): """initiaite v, instance_id and ip initiate the cloudinit sequence""" params = {} if not listing: params['instance_id'] = self.node_uuid response = tornado_requests.request( "GET", "http://%s:%s/v1/instances" % (self.cloudverifier_ip, self.cloudverifier_port), params=params, context=self.context) if response.status_code != 200: logger.error( "Status command response: %d Unexpected response from Cloud Verifier." % response.status_code) else: logger.info("Node Status %d: %s" % (response.status_code, response.json()))
def do_cvstatus(self, listing=False): """initiaite v, agent_id and ip initiate the cloudinit sequence""" agent_uuid = "" if not listing: agent_uuid = self.agent_uuid response = tornado_requests.request( "GET", "http://%s:%s/agents/%s" % (self.cloudverifier_ip, self.cloudverifier_port, agent_uuid), context=self.context) if response.status_code != 200: raise UserError( "Status command response: %d Unexpected response from Cloud Verifier." % response.status_code) common.log_http_response(logger, logging.ERROR, response.json()) else: logger.info("Agent Status %d: %s" % (response.status_code, response.json()))
def test_041_agent_keys_verify_get(self): """Test agent's GET /v2/keys/verify Interface""" self.assertIsNotNone(self.K, "Required value not set. Previous step may have failed?") challenge = TPM_Utilities.random_password(20) response = tornado_requests.request( "GET", "http://%s:%s/v%s/keys/verify?challenge=%s"%(tenant_templ.cloudagent_ip,tenant_templ.cloudagent_port,self.api_version,challenge) ) self.assertEqual(response.status_code, 200, "Non-successful Agent verify return code!") response_body = response.json() # Ensure response is well-formed self.assertIn("results", response_body, "Malformed response body!") self.assertIn("hmac", response_body["results"], "Malformed response body!") # Be sure response is valid mac = response_body['results']['hmac'] ex_mac = crypto.do_hmac(self.K, challenge) self.assertEqual(mac, ex_mac, "Agent failed to validate challenge code!")
def test_020_agent_keys_pubkey_get(self): """Test agent's GET /v2/keys/pubkey Interface""" # We want a real cloud agent to communicate with! launch_cloudagent() response = tornado_requests.request( "GET", "http://%s:%s/v%s/keys/pubkey"%(tenant_templ.cloudagent_ip,tenant_templ.cloudagent_port,self.api_version), context=None ) self.assertEqual(response.status_code, 200, "Non-successful Agent pubkey return code!") response_body = response.json() # Ensure response is well-formed self.assertIn("results", response_body, "Malformed response body!") self.assertIn("pubkey", response_body["results"], "Malformed response body!") global public_key public_key = response_body["results"]["pubkey"] self.assertNotEqual(public_key, None, "Malformed response body!")
def test_040_agent_quotes_integrity_get(self): """Test agent's GET /v2/quotes/integrity Interface""" global public_key, aik self.assertIsNotNone(aik, "Required value not set. Previous step may have failed?") nonce = TPM_Utilities.random_password(20) mask = self.tpm_policy["mask"] vmask = self.vtpm_policy["mask"] partial = "1" if public_key is None: partial = "0" response = tornado_requests.request( "GET", "http://%s:%s/v%s/quotes/integrity?nonce=%s&mask=%s&vmask=%s&partial=%s"%(tenant_templ.cloudagent_ip,tenant_templ.cloudagent_port,self.api_version,nonce,mask,vmask,partial) ) self.assertEqual(response.status_code, 200, "Non-successful Agent Integrity Get return code!") response_body = response.json() # Ensure response is well-formed self.assertIn("results", response_body, "Malformed response body!") self.assertIn("quote", response_body["results"], "Malformed response body!") if public_key is None: self.assertIn("pubkey", response_body["results"], "Malformed response body!") public_key = response_body["results"]["pubkey"] self.assertIn("tpm_version", response_body["results"], "Malformed response body!") self.assertIn("hash_alg", response_body["results"], "Malformed response body!") quote = response_body["results"]["quote"] tpm_version = response_body["results"]["tpm_version"] hash_alg = response_body["results"]["hash_alg"] validQuote = tpm.check_quote(nonce, public_key, quote, aik, self.tpm_policy, hash_alg=hash_alg) self.assertTrue(validQuote)
def doRegisterNode(registrar_ip,registrar_port,instance_id,pub_ek,ekcert,pub_aik): global context data = { 'command': 'register_node', 'ek': pub_ek, 'ekcert': ekcert, 'aik': pub_aik, } v_json_message = json.dumps(data) response = tornado_requests.request("PUT", "http://%s:%s/v1/instance_id/%s"%(registrar_ip,registrar_port,instance_id), data=v_json_message, context=context) if response.status_code == 200: logger.info("Node registration requested for %s"%instance_id) response_body = response.json() return response_body["blob"] else: logger.error("Error: unexpected http response code from Registrar Server: " + str(response.status_code)) return None
def do_cvreactivate(self): """initiaite v, instance_id and ip initiate the cloudinit sequence""" params = { 'instance_id': self.node_uuid, } data = { 'operational_state': cloud_verifier_common.CloudInstance_Operational_State.START } response = tornado_requests.request( "POST", "http://%s:%s/v1/instances" % (self.cloudverifier_ip, self.cloudverifier_port), params=params, data=json.dumps(data), context=self.context) if response.status_code != 200: logger.error( "Update command response: %d Unexpected response from Cloud Verifier." % response.status_code) else: logger.info("Node %s re-activated" % (self.node_uuid))
def test_023_node_keys_ukey_post(self): """Test node's POST /v2/keys/ukey Interface""" global public_key self.assertIsNotNone( public_key, "Required value not set. Previous step may have failed?") self.assertIsNotNone( self.U, "Required value not set. Previous step may have failed?") self.assertIsNotNone( self.auth_tag, "Required value not set. Previous step may have failed?") self.assertIsNotNone( self.payload, "Required value not set. Previous step may have failed?") encrypted_U = crypto.rsa_encrypt(crypto.rsa_import_pubkey(public_key), str(self.U)) b64_encrypted_u = base64.b64encode(encrypted_U) data = { 'encrypted_key': b64_encrypted_u, 'auth_tag': self.auth_tag, 'payload': self.payload } u_json_message = json.dumps(data) response = tornado_requests.request( "POST", "http://%s:%s/v2/keys/ukey" % (tenant_templ.cloudnode_ip, tenant_templ.cloudnode_port), data=u_json_message) self.assertEqual(response.status_code, 200, "Non-successful Node ukey post return code!") response_body = response.json() # Ensure response is well-formed self.assertIn("results", response_body, "Malformed response body!")
def test_040_node_quotes_integrity_get(self): """Test node's GET /v2/quotes/integrity Interface""" global public_key, aik self.assertIsNotNone( aik, "Required value not set. Previous step may have failed?") nonce = tpm_initialize.random_password(20) mask = self.tpm_policy["mask"] vmask = self.vtpm_policy["mask"] partial = "1" if public_key is None: partial = "0" response = tornado_requests.request( "GET", "http://%s:%s/v2/quotes/integrity/nonce/%s/mask/%s/vmask/%s/partial/%s/" % (tenant_templ.cloudnode_ip, tenant_templ.cloudnode_port, nonce, mask, vmask, partial)) self.assertEqual(response.status_code, 200, "Non-successful Node Integrity Get return code!") response_body = response.json() # Ensure response is well-formed self.assertIn("results", response_body, "Malformed response body!") self.assertIn("quote", response_body["results"], "Malformed response body!") if public_key is None: self.assertIn("pubkey", response_body["results"], "Malformed response body!") public_key = response_body["results"]["pubkey"] quote = response_body["results"]["quote"] validQuote = tpm_quote.check_quote(nonce, public_key, quote, aik, self.tpm_policy) self.assertTrue(validQuote)
def test_011_reg_agent_activate_put(self): """Test registrar's PUT /v2/agents/{UUID}/activate Interface""" global keyblob, aik self.assertIsNotNone(keyblob, "Required value not set. Previous step may have failed?") self.assertIsNotNone(aik, "Required value not set. Previous step may have failed?") key = tpm.activate_identity(keyblob) data = { 'auth_tag': crypto.do_hmac(base64.b64decode(key),tenant_templ.agent_uuid), } v_json_message = json.dumps(data) response = tornado_requests.request( "PUT", "http://%s:%s/v%s/agents/%s/activate"%(tenant_templ.registrar_ip,tenant_templ.registrar_boot_port,self.api_version,tenant_templ.agent_uuid), data=v_json_message, context=None ) self.assertEqual(response.status_code, 200, "Non-successful Registrar agent Activate return code!") response_body = response.json() # Ensure response is well-formed self.assertIn("results", response_body, "Malformed response body!")