def test_034_cv_agent_post_invalid_exclude_list(self): """Test CV's POST /v2/agents/{UUID} Interface""" self.assertIsNotNone(self.V, "Required value not set. Previous step may have failed?") b64_v = base64.b64encode(self.V) # Set unsupported regex in exclude list allowlist = {'exclude': ['*']} data = { 'v': b64_v, 'cloudagent_ip': tenant_templ.cloudagent_ip, 'cloudagent_port': tenant_templ.cloudagent_port, 'tpm_policy': json.dumps(self.tpm_policy), 'vtpm_policy': json.dumps(self.vtpm_policy), 'allowlist': json.dumps(allowlist), 'ima_sign_verification_keys': '', 'metadata': json.dumps(self.metadata), 'revocation_key': self.revocation_key, 'accept_tpm_hash_algs': config.get('tenant', 'accept_tpm_hash_algs').split(','), 'accept_tpm_encryption_algs': config.get('tenant', 'accept_tpm_encryption_algs').split(','), 'accept_tpm_signing_algs': config.get('tenant', 'accept_tpm_signing_algs').split(','), } client = RequestsClient(tenant_templ.verifier_base_url, tls_enabled) response = client.post( f'/v{self.api_version}/agents/{tenant_templ.agent_uuid}', cert=tenant_templ.cert, data=json.dumps(data), verify=False ) self.assertEqual(response.status_code, 400, "Successful CV agent Post return code!") # Ensure response is well-formed json_response = response.json() self.assertIn("results", json_response, "Malformed response body!")
def _eval_severity_config() -> Tuple[List[Callable[[str], Optional[SeverityLabel]]], SeverityLabel]: """ Generates the list of rules to match a event_id against. """ labels_list = ast.literal_eval(config.get("cloud_verifier", "severity_labels")) labels = {} for label, level in zip(labels_list, range(0, len(labels_list))): labels[label] = SeverityLabel(label, level) label_max = labels[labels_list[-1]] policies = ast.literal_eval(config.get("cloud_verifier", "severity_policy")) rules = [] for policy in policies: # TODO validate regex regex = re.compile(policy["event_id"]) def rule(policy_regex: Pattern[Any], label_str: str, event_id: str) -> Optional[SeverityLabel]: if policy_regex.fullmatch(event_id): policy_label = labels.get(label_str) if policy_label is None: logger.error("Label %s is not a valid label. Defaulting to maximal severity label!", label_str) return label_max return policy_label return None new_rule: Callable[[str], Optional[SeverityLabel]] = functools.partial(rule, regex, policy["severity_label"]) rules.append(new_rule) return rules, label_max
def get_tls_context(): ca_cert = config.get('tenant', 'ca_cert') tls_dir = config.get('tenant', 'tls_dir') if tls_dir == 'default': ca_cert = 'cacert.crt' tls_dir = 'cv_ca' # this is relative path, convert to absolute in WORK_DIR if tls_dir[0] != '/': tls_dir = os.path.abspath('%s/%s' % (config.WORK_DIR, tls_dir)) logger.info("Setting up client TLS in %s", tls_dir) ca_path = "%s/%s" % (tls_dir, ca_cert) my_tls_cert = "%s/%s" % (tls_dir, my_cert) my_tls_priv_key = "%s/%s" % (tls_dir, my_priv_key) context = ssl.create_default_context() context.load_verify_locations(cafile=ca_path) context.load_cert_chain(certfile=my_tls_cert, keyfile=my_tls_priv_key) context.verify_mode = ssl.CERT_REQUIRED context.check_hostname = config.getboolean('general', 'tls_check_hostnames') return context
def add_vtpm(inputfile): # read in the file with open(inputfile, encoding="utf-8") as f: group = yaml.load(f, Loader=SafeLoader) # fetch configuration parameters provider_reg_port = config.get('registrar', 'provider_registrar_port') provider_reg_ip = config.get('registrar', 'provider_registrar_ip') # request a vtpm uuid from the manager vtpm_uuid = vtpm_manager.add_vtpm_to_group(group['uuid']) # registrar it and get back a blob keyblob = registrar_client.doRegisterAgent(provider_reg_ip, provider_reg_port, vtpm_uuid, group['pubekpem'], group['ekcert'], group['aikpem']) # get the ephemeral registrar key by activating in the hardware tpm key = base64.b64encode(vtpm_manager.activate_group(group['uuid'], keyblob)) # tell the registrar server we know the key registrar_client.doActivateAgent(provider_reg_ip, provider_reg_port, vtpm_uuid, key) logger.info("Registered new vTPM with UUID: %s", vtpm_uuid) return vtpm_uuid
def __init__(self, server_address, RequestHandlerClass, agent_uuid): """Constructor overridden to provide ability to pass configuration arguments to the server""" secdir = secure_mount.mount() keyname = "%s/%s" % (secdir, config.get('cloud_agent', 'rsa_keyname')) # read or generate the key depending on configuration if os.path.isfile(keyname): # read in private key logger.debug("Using existing key in %s", keyname) f = open(keyname, "rb") rsa_key = crypto.rsa_import_privkey(f.read()) else: logger.debug("key not found, generating a new one") rsa_key = crypto.rsa_generate(2048) with open(keyname, "wb") as f: f.write(crypto.rsa_export_privkey(rsa_key)) self.rsaprivatekey = rsa_key self.rsapublickey_exportable = crypto.rsa_export_pubkey( self.rsaprivatekey) # attempt to get a U value from the TPM NVRAM nvram_u = tpm_instance.read_key_nvram() if nvram_u is not None: logger.info("Existing U loaded from TPM NVRAM") self.add_U(nvram_u) http.server.HTTPServer.__init__(self, server_address, RequestHandlerClass) self.enc_keyname = config.get('cloud_agent', 'enc_keyname') self.agent_uuid = agent_uuid
def test_030_cv_agent_post(self): """Test CV's POST /agents/{UUID} Interface""" self.assertIsNotNone( self.V, "Required value not set. Previous step may have failed?") b64_v = base64.b64encode(self.V) data = { "v": b64_v, "cloudagent_ip": tenant_templ.cloudagent_ip, "cloudagent_port": tenant_templ.cloudagent_port, "tpm_policy": json.dumps(self.tpm_policy), "ima_policy_bundle": json.dumps(self.ima_policy_bundle), "ima_sign_verification_keys": "", "mb_refstate": None, "metadata": json.dumps(self.metadata), "revocation_key": self.revocation_key, "accept_tpm_hash_algs": config.get("tenant", "accept_tpm_hash_algs").split(","), "accept_tpm_encryption_algs": config.get("tenant", "accept_tpm_encryption_algs").split(","), "accept_tpm_signing_algs": config.get("tenant", "accept_tpm_signing_algs").split(","), "supported_version": tenant_templ.supported_version, "ak_tpm": aik_tpm, "mtls_cert": mtls_cert, } test_030_cv_agent_post = RequestsClient(tenant_templ.verifier_base_url, tls_enabled) response = test_030_cv_agent_post.post( f"/v{self.api_version}/agents/{tenant_templ.agent_uuid}", data=json.dumps(data), cert=tenant_templ.cert, verify=False, ) self.assertEqual(response.status_code, 200, "Non-successful CV agent Post return code!") json_response = response.json() # Ensure response is well-formed self.assertIn("results", json_response, "Malformed response body!") time.sleep(10)
def init_client_tls(section): global tls_cert_info global tls_enabled # make this reentrant if tls_cert_info: return if not config.getboolean('general', "enable_tls"): logger.warning("TLS is currently disabled, AIKs may not be authentic.") return logger.warning("TLS is enabled.") tls_enabled = True logger.info("Setting up client TLS...") tls_dir = config.get(section, 'registrar_tls_dir') my_cert = config.get(section, 'registrar_my_cert') my_priv_key = config.get(section, 'registrar_private_key') my_key_pw = config.get(section, 'registrar_private_key_pw') if tls_dir == 'default': tls_dir = 'reg_ca' my_cert = 'client-cert.crt' my_priv_key = 'client-private.pem' if tls_dir == 'CV': tls_dir = 'cv_ca' my_cert = 'client-cert.crt' my_priv_key = 'client-private.pem' # this is relative path, convert to absolute in WORK_DIR if tls_dir[0] != '/': tls_dir = os.path.abspath('%s/%s' % (config.WORK_DIR, tls_dir)) ca_cert = config.get(section, 'registrar_ca_cert') if ca_cert == 'default': ca_path = "%s/cacert.crt" % (tls_dir) else: ca_path = "%s/%s" % (tls_dir, ca_cert) if os.path.isabs(my_cert): tls_cert = my_cert else: tls_cert = "%s/%s" % (tls_dir, my_cert) if os.path.isabs(my_priv_key): tls_priv_key = my_priv_key else: tls_priv_key = "%s/%s" % (tls_dir, my_priv_key) tls_cert_info = (tls_cert, tls_priv_key)
def init_client_tls(section): global tls_cert_info global tls_enabled global ca_cert # make this reentrant if tls_cert_info: return if not config.getboolean("general", "enable_tls"): logger.warning( "Warning: TLS is currently disabled, AIKs may not be authentic.") return logger.warning("TLS is enabled.") tls_enabled = True logger.info("Setting up client TLS...") tls_dir = config.get(section, "registrar_tls_dir") ca_cert = config.get(section, "registrar_ca_cert") my_cert = config.get(section, "registrar_my_cert") my_priv_key = config.get(section, "registrar_private_key") if tls_dir == "default": tls_dir = "reg_ca" ca_cert = "cacert.crt" my_cert = "client-cert.crt" my_priv_key = "client-private.pem" if tls_dir == "CV": tls_dir = "cv_ca" ca_cert = "cacert.crt" my_cert = "client-cert.crt" my_priv_key = "client-private.pem" # this is relative path, convert to absolute in WORK_DIR if tls_dir[0] != "/": tls_dir = os.path.abspath(os.path.join(config.WORK_DIR, tls_dir)) if not os.path.isabs(ca_cert): ca_cert = os.path.join(tls_dir, ca_cert) if os.path.isabs(my_cert): tls_cert = my_cert else: tls_cert = os.path.join(tls_dir, my_cert) if os.path.isabs(my_priv_key): tls_priv_key = my_priv_key else: tls_priv_key = os.path.join(tls_dir, my_priv_key) tls_cert_info = (tls_cert, tls_priv_key)
def test_030_cv_agent_post(self): """Test CV's POST /v2/agents/{UUID} Interface""" self.assertIsNotNone( self.V, "Required value not set. Previous step may have failed?") b64_v = base64.b64encode(self.V) data = { 'v': b64_v, 'cloudagent_ip': tenant_templ.cloudagent_ip, 'cloudagent_port': tenant_templ.cloudagent_port, 'tpm_policy': json.dumps(self.tpm_policy), 'vtpm_policy': json.dumps(self.vtpm_policy), 'allowlist': json.dumps(self.allowlist), 'ima_sign_verification_keys': '', 'mb_refstate': None, 'metadata': json.dumps(self.metadata), 'revocation_key': self.revocation_key, 'accept_tpm_hash_algs': config.get('tenant', 'accept_tpm_hash_algs').split(','), 'accept_tpm_encryption_algs': config.get('tenant', 'accept_tpm_encryption_algs').split(','), 'accept_tpm_signing_algs': config.get('tenant', 'accept_tpm_signing_algs').split(','), } test_030_cv_agent_post = RequestsClient(tenant_templ.verifier_base_url, tls_enabled) response = test_030_cv_agent_post.post( f'/agents/{tenant_templ.agent_uuid}', data=json.dumps(data), cert=tenant_templ.cert, verify=False) self.assertEqual(response.status_code, 200, "Non-successful CV agent Post return code!") json_response = response.json() # Ensure response is well-formed self.assertIn("results", json_response, "Malformed response body!") time.sleep(10)
def mk_name(common_name): return x509.Name([ x509.NameAttribute(NameOID.COUNTRY_NAME, config.get("ca", "cert_country")), x509.NameAttribute(NameOID.COMMON_NAME, common_name), x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, config.get("ca", "cert_state")), x509.NameAttribute(NameOID.LOCALITY_NAME, config.get("ca", "cert_locality")), x509.NameAttribute(NameOID.ORGANIZATION_NAME, config.get("ca", "cert_organization")), x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, config.get("ca", "cert_org_unit")), ])
def __init__(self, server_address, RequestHandlerClass, agent_uuid): """Constructor overridden to provide ability to pass configuration arguments to the server""" secdir = secure_mount.mount() keyname = os.path.join(secdir, config.get('cloud_agent', 'rsa_keyname')) certname = os.path.join(secdir, config.get('cloud_agent', 'mtls_cert')) # read or generate the key depending on configuration if os.path.isfile(keyname): # read in private key logger.debug("Using existing key in %s", keyname) f = open(keyname, "rb") rsa_key = crypto.rsa_import_privkey(f.read()) else: logger.debug("key not found, generating a new one") rsa_key = crypto.rsa_generate(2048) with open(keyname, "wb") as f: f.write(crypto.rsa_export_privkey(rsa_key)) self.rsakey_path = keyname self.rsaprivatekey = rsa_key self.rsapublickey_exportable = crypto.rsa_export_pubkey( self.rsaprivatekey) if os.path.isfile(certname): logger.debug("Using existing mTLS cert in %s", certname) with open(certname, "rb") as f: mtls_cert = x509.load_pem_x509_certificate(f.read()) else: logger.debug("No mTLS certificate found generating a new one") with open(certname, "wb") as f: # By default generate a TLS certificate valid for 5 years valid_util = datetime.datetime.utcnow() + datetime.timedelta( days=(360 * 5)) mtls_cert = crypto.generate_selfsigned_cert( agent_uuid, rsa_key, valid_util) f.write(mtls_cert.public_bytes(serialization.Encoding.PEM)) self.mtls_cert_path = certname self.mtls_cert = mtls_cert # attempt to get a U value from the TPM NVRAM nvram_u = tpm_instance.read_key_nvram() if nvram_u is not None: logger.info("Existing U loaded from TPM NVRAM") self.add_U(nvram_u) http.server.HTTPServer.__init__(self, server_address, RequestHandlerClass) self.enc_keyname = config.get('cloud_agent', 'enc_keyname') self.agent_uuid = agent_uuid
def perform_actions(revocation): actionlist = [] # load the actions from inside the keylime module actionlisttxt = config.get('cloud_agent', 'revocation_actions') if actionlisttxt.strip() != "": actionlist = actionlisttxt.split(',') actionlist = ["revocation_actions.%s" % i for i in actionlist] # load actions from unzipped if os.path.exists("%s/unzipped/action_list" % secdir): with open("%s/unzipped/action_list" % secdir, 'r') as f: actionlisttxt = f.read() if actionlisttxt.strip() != "": localactions = actionlisttxt.strip().split(',') for action in localactions: if not action.startswith('local_action_'): logger.warning("Invalid local action: %s. Must start with local_action_", action) else: actionlist.append(action) uzpath = "%s/unzipped" % secdir if uzpath not in sys.path: sys.path.append(uzpath) for action in actionlist: logger.info("Executing revocation action %s", action) try: module = importlib.import_module(action) execute = getattr(module, 'execute') asyncio.get_event_loop().run_until_complete(execute(revocation)) except Exception as e: logger.warning("Exception during execution of revocation action %s: %s", action, e)
def notify_webhook(tosend): url = config.get('cloud_verifier', 'webhook_url', fallback='') # Check if a url was specified if url == '': return def worker_webhook(tosend, url): retry_interval = config.getfloat('cloud_verifier', 'retry_interval') session = requests.session() logger.info("Sending revocation event via webhook...") for i in range(config.getint('cloud_verifier', 'max_retries')): try: response = session.post(url, json=tosend) if response.status_code in [200, 202]: break logger.debug( f"Unable to publish revocation message {i} times via webhook, " f"trying again in {retry_interval} seconds. " f"Server returned status code: {response.status_code}") except requests.exceptions.RequestException as e: logger.debug( f"Unable to publish revocation message {i} times via webhook, " f"trying again in {retry_interval} seconds: {e} ") time.sleep(retry_interval) w = functools.partial(worker_webhook, tosend, url) t = threading.Thread(target=w) t.start()
def await_notifications(callback, revocation_cert_path): # keep old typo "listen_notfications" around for a few versions assert config.getboolean( "cloud_agent", "listen_notifications", fallback=False) or config.getboolean( "cloud_agent", "listen_notfications", fallback=False) try: import zmq # pylint: disable=import-outside-toplevel except ImportError as error: raise Exception( "install PyZMQ for 'listen_notifications' option") from error if revocation_cert_path is None: raise Exception("must specify revocation_cert_path") context = zmq.Context() mysock = context.socket(zmq.SUB) mysock.setsockopt(zmq.SUBSCRIBE, b"") mysock.connect(f"tcp://{config.get('general', 'receive_revocation_ip')}:" f"{config.getint('general', 'receive_revocation_port')}") logger.info( "Waiting for revocation messages on 0mq %s:%s", config.get("general", "receive_revocation_ip"), config.getint("general", "receive_revocation_port"), ) while True: rawbody = mysock.recv() body = json.loads(rawbody) process_revocation(body, callback, revocation_cert_path)
def perform_actions(revocation): actionlist = [] # load the actions from inside the keylime module actionlisttxt = config.get("cloud_agent", "revocation_actions") if actionlisttxt.strip() != "": actionlist = actionlisttxt.split(",") actionlist = [f"revocation_actions.{i}" % i for i in actionlist] # load actions from unzipped action_list_path = os.path.join(secdir, "unzipped/action_list") if os.path.exists(action_list_path): with open(action_list_path, encoding="utf-8") as f: actionlisttxt = f.read() if actionlisttxt.strip() != "": localactions = actionlisttxt.strip().split(",") for action in localactions: if not action.startswith("local_action_"): logger.warning("Invalid local action: %s. Must start with local_action_", action) else: actionlist.append(action) uzpath = os.path.join(secdir, "unzipped") if uzpath not in sys.path: sys.path.append(uzpath) for action in actionlist: logger.info("Executing revocation action %s", action) try: module = importlib.import_module(action) execute = getattr(module, "execute") asyncio.get_event_loop().run_until_complete(execute(revocation)) except Exception as e: logger.warning("Exception during execution of revocation action %s: %s", action, e)
def setUpClass(cls): """Prepare the keys and payload to give to the CV""" contents = "random garbage to test as payload" # contents = contents.encode('utf-8') ret = user_data_encrypt.encrypt(contents) cls.K = ret["k"] cls.U = ret["u"] cls.V = ret["v"] cls.payload = ret["ciphertext"] # Set up to register an agent cls.auth_tag = crypto.do_hmac(cls.K, tenant_templ.agent_uuid) # Prepare policies for agent cls.tpm_policy = config.get("tenant", "tpm_policy") cls.tpm_policy = tpm_abstract.TPM_Utilities.readPolicy(cls.tpm_policy) # Allow targeting a specific API version (default latest) cls.api_version = "2.0" # Set up allowlist bundles. Use invalid exclusion list regex for bad bundle. cls.ima_policy_bundle = ima.read_allowlist() cls.ima_policy_bundle["excllist"] = [] cls.bad_ima_policy_bundle = ima.read_allowlist() cls.bad_ima_policy_bundle["excllist"] = ["*"]
def convert_crl_to_pem(derfile, pemfile): if config.get('general', 'ca_implementation') == 'openssl': with open(pemfile, 'w', encoding="utf-8") as f: f.write("") else: cmd = ('openssl', 'crl', '-in', derfile, '-inform', 'der', '-out', pemfile) cmd_exec.run(cmd)
def mk_cacert(name=None): """ Make a CA certificate. Returns the certificate, private key and public key. """ if name is None: name = config.get("ca", "cert_ca_name") cert_req, privkey = mk_request(config.getint("ca", "cert_bits"), name) pubkey = privkey.public_key() cert_req = cert_req.public_key(pubkey) cert_req = cert_req.serial_number(1) cert_req = mk_cert_valid(cert_req, config.getint("ca", "cert_ca_lifetime")) cert_req = cert_req.issuer_name(mk_name(name)) # Extensions. extensions = [ # Basic Constraints. x509.BasicConstraints(ca=True, path_length=None), # Subject Key Identifier. x509.SubjectKeyIdentifier.from_public_key(pubkey), # CRL Distribution Points. x509.CRLDistributionPoints([ x509.DistributionPoint( full_name=[ x509.UniformResourceIdentifier("http://localhost/crl.pem"), ], relative_name=None, reasons=None, crl_issuer=None, ), ]), # Key Usage. x509.KeyUsage( key_cert_sign=True, crl_sign=True, digital_signature=False, content_commitment=False, key_encipherment=False, data_encipherment=False, key_agreement=False, encipher_only=False, decipher_only=False, ), ] for ext in extensions: cert_req = cert_req.add_extension(ext, critical=False) cert = cert_req.sign( private_key=privkey, algorithm=hashes.SHA256(), backend=default_backend(), ) return cert, privkey, pubkey
def test_010_reg_agent_post(self): """Test registrar's POST /v2/agents/{UUID} Interface""" global keyblob, aik, vtpm, ek # Change CWD for TPM-related operations cwd = os.getcwd() config.ch_dir(config.WORK_DIR, None) _ = secure_mount.mount() # Initialize the TPM with AIK (ek, ekcert, aik, ek_tpm, aik_name) = tpm.tpm_init(self_activate=False, config_pw=config.get('cloud_agent', 'tpm_ownerpassword')) vtpm = tpm.is_vtpm() # Seed RNG (root only) if config.REQUIRE_ROOT: tpm.init_system_rand() # Handle virtualized and emulated TPMs if ekcert is None: if vtpm: ekcert = 'virtual' elif tpm.is_emulator(): ekcert = 'emulator' # Get back to our original CWD config.ch_dir(cwd, None) data = { 'ek': ek, 'ekcert': ekcert, 'aik': aik, 'aik_name': aik_name, 'ek_tpm': ek_tpm, 'tpm_version': tpm.VERSION, } test_010_reg_agent_post = RequestsClient( tenant_templ.registrar_base_url, tls_enabled=False) response = test_010_reg_agent_post.post( f'/v{self.api_version}/agents/{tenant_templ.agent_uuid}', data=json.dumps(data), cert="", verify=False) self.assertEqual(response.status_code, 200, "Non-successful Registrar agent Add return code!") json_response = response.json() # Ensure response is well-formed self.assertIn("results", json_response, "Malformed response body!") self.assertIn("blob", json_response["results"], "Malformed response body!") keyblob = json_response["results"]["blob"] self.assertIsNotNone(keyblob, "Malformed response body!")
def await_notifications(callback, revocation_cert_path): global cert_key if revocation_cert_path is None: raise Exception("must specify revocation_cert_path") context = zmq.Context() mysock = context.socket(zmq.SUB) mysock.setsockopt(zmq.SUBSCRIBE, b'') mysock.connect("tcp://%s:%s" % (config.get('general', 'receive_revocation_ip'), config.getint('general', 'receive_revocation_port'))) logger.info('Waiting for revocation messages on 0mq %s:%s' % (config.get('general', 'receive_revocation_ip'), config.getint('general', 'receive_revocation_port'))) while True: rawbody = mysock.recv() body = json.loads(rawbody) if cert_key is None: # load up the CV signing public key if revocation_cert_path is not None and os.path.exists( revocation_cert_path): logger.info("Lazy loading the revocation certificate from %s" % revocation_cert_path) with open(revocation_cert_path, 'r') as f: certpem = f.read() cert_key = crypto.x509_import_pubkey(certpem) if cert_key is None: logger.warning( "Unable to check signature of revocation message: %s not available" % revocation_cert_path) elif 'signature' not in body or body['signature'] == 'none': logger.warning("No signature on revocation message from server") elif not crypto.rsa_verify(cert_key, body['msg'].encode('utf-8'), body['signature'].encode('utf-8')): logger.error("Invalid revocation message siganture %s" % body) else: message = json.loads(body['msg']) logger.debug("Revocation signature validated for revocation: %s" % message) callback(message)
def main(argv=sys.argv): # if we are configured to auto-migrate the DB, check if there are any migrations to perform if config.has_option('registrar', 'auto_migrate_db') and config.getboolean( 'registrar', 'auto_migrate_db'): keylime.cmd.migrations_apply.apply('registrar') registrar_common.start(config.get('registrar', 'registrar_ip'), config.getint('registrar', 'registrar_tls_port'), config.getint('registrar', 'registrar_port'))
def await_notifications(callback, revocation_cert_path): # keep old typo "listen_notfications" around for a few versions assert config.getboolean( "cloud_agent", "listen_notifications", fallback=False) or config.getboolean( "cloud_agent", "listen_notfications", fallback=False) try: import zmq # pylint: disable=import-outside-toplevel except ImportError as error: raise Exception( "install PyZMQ for 'listen_notifications' option") from error global cert_key if revocation_cert_path is None: raise Exception("must specify revocation_cert_path") context = zmq.Context() mysock = context.socket(zmq.SUB) mysock.setsockopt(zmq.SUBSCRIBE, b"") mysock.connect(f"tcp://{config.get('general', 'receive_revocation_ip')}:" f"{config.getint('general', 'receive_revocation_port')}") logger.info( "Waiting for revocation messages on 0mq %s:%s", config.get("general", "receive_revocation_ip"), config.getint("general", "receive_revocation_port"), ) while True: rawbody = mysock.recv() body = json.loads(rawbody) if cert_key is None: # load up the CV signing public key if revocation_cert_path is not None and os.path.exists( revocation_cert_path): logger.info("Lazy loading the revocation certificate from %s", revocation_cert_path) with open(revocation_cert_path, "rb") as f: certpem = f.read() cert_key = crypto.x509_import_pubkey(certpem) if cert_key is None: logger.warning( "Unable to check signature of revocation message: %s not available", revocation_cert_path) elif "signature" not in body or body["signature"] == "none": logger.warning("No signature on revocation message from server") elif not crypto.rsa_verify(cert_key, body["msg"].encode("utf-8"), body["signature"].encode("utf-8")): logger.error("Invalid revocation message siganture %s", body) else: message = json.loads(body["msg"]) logger.debug("Revocation signature validated for revocation: %s", message) callback(message)
def test_010_reg_agent_post(self): """Test registrar's POST /agents/{UUID} Interface""" global keyblob, vtpm, tpm_instance, ek_tpm, aik_tpm contact_ip = "127.0.0.1" contact_port = 9002 tpm_instance = tpm_main.tpm() # Change CWD for TPM-related operations cwd = os.getcwd() config.ch_dir(config.WORK_DIR, None) _ = secure_mount.mount() # Initialize the TPM with AIK (ekcert, ek_tpm, aik_tpm) = tpm_instance.tpm_init( self_activate=False, config_pw=config.get('cloud_agent', 'tpm_ownerpassword')) vtpm = tpm_instance.is_vtpm() # Handle virtualized and emulated TPMs if ekcert is None: if vtpm: ekcert = 'virtual' elif tpm_instance.is_emulator(): ekcert = 'emulator' # Get back to our original CWD config.ch_dir(cwd, None) data = { 'ekcert': ekcert, 'aik_tpm': aik_tpm, 'ip': contact_ip, 'port': contact_port } if ekcert is None or ekcert == 'emulator': data['ek_tpm'] = ek_tpm test_010_reg_agent_post = RequestsClient( tenant_templ.registrar_base_url, tls_enabled=False) response = test_010_reg_agent_post.post( f'/v{self.api_version}/agents/{tenant_templ.agent_uuid}', data=json.dumps(data), cert="", verify=False) self.assertEqual(response.status_code, 200, "Non-successful Registrar agent Add return code!") json_response = response.json() # Ensure response is well-formed self.assertIn("results", json_response, "Malformed response body!") self.assertIn("blob", json_response["results"], "Malformed response body!") keyblob = json_response["results"]["blob"] self.assertIsNotNone(keyblob, "Malformed response body!")
def main(): # if we are configured to auto-migrate the DB, check if there are any migrations to perform if config.has_option("registrar", "auto_migrate_db") and config.getboolean( "registrar", "auto_migrate_db"): keylime.cmd.migrations_apply.apply("registrar") registrar_common.start( config.get("registrar", "registrar_ip"), config.getint("registrar", "registrar_tls_port"), config.getint("registrar", "registrar_port"), )
def read_mb_refstate(mb_path=None): if mb_path is None: mb_path = config.get('tenant', 'mb_refstate') mb_data = None # Purposefully die if path doesn't exist with open(mb_path, 'r') as f: mb_data = json.load(f) logger.debug(f"Loaded measured boot reference state from {mb_path}") return mb_data
def setUpClass(cls): """Prepare the keys and payload to give to the CV""" contents = "random garbage to test as payload" # contents = contents.encode('utf-8') ret = user_data_encrypt.encrypt(contents) cls.K = ret['k'] cls.U = ret['u'] cls.V = ret['v'] cls.payload = ret['ciphertext'] # Set up to register an agent cls.auth_tag = crypto.do_hmac(cls.K, tenant_templ.agent_uuid) # Prepare policies for agent cls.tpm_policy = config.get('tenant', 'tpm_policy') cls.vtpm_policy = config.get('tenant', 'vtpm_policy') cls.tpm_policy = tpm_abstract.TPM_Utilities.readPolicy(cls.tpm_policy) cls.vtpm_policy = tpm_abstract.TPM_Utilities.readPolicy(cls.vtpm_policy) # Allow targeting a specific API version (default latest) cls.api_version = config.API_VERSION
def read_mb_refstate(mb_path=None): if mb_path is None: mb_path = config.get("tenant", "mb_refstate") mb_data = None # Purposefully die if path doesn't exist with open(mb_path, encoding="utf-8") as f: mb_data = json.load(f) logger.debug("Loaded measured boot reference state from %s", mb_path) return mb_data
def mk_cacert(): csr = { "CN": config.get('ca', 'cert_ca_name'), "key": { "algo": "rsa", "size": config.getint('ca', 'cert_bits') }, "names": [{ "C": config.get('ca', 'cert_country'), "L": config.get('ca', 'cert_locality'), "O": config.get('ca', 'cert_organization'), "OU": config.get('ca', 'cert_org_unit'), "ST": config.get('ca', 'cert_state') }] } try: start_cfssl() body = post_cfssl('api/v1/cfssl/init_ca', csr) finally: stop_cfssl() if body['success']: pk_str = body['result']['private_key'] pk = EVP.load_key_string(body['result']['private_key'].encode('utf-8')) cert = X509.load_cert_string( body['result']['certificate'].encode('utf-8')) pkey = cert.get_pubkey() return pk_str, cert, pk, pkey raise Exception("Unable to create CA")
def __init__(self): """ Set up required values and TLS """ self.nonce = None self.agent_ip = None self.agent_port = config.get('cloud_agent', 'cloudagent_port') self.verifier_ip = config.get('tenant', 'cloudverifier_ip') self.verifier_port = config.get('tenant', 'cloudverifier_port') self.registrar_ip = config.get('tenant', 'registrar_ip') self.registrar_port = config.get('tenant', 'registrar_port') self.webapp_port = config.getint('webapp', 'webapp_port') if not config.REQUIRE_ROOT and self.webapp_port < 1024: self.webapp_port += 2000 self.webapp_ip = config.get('webapp', 'webapp_ip') self.my_cert, self.my_priv_key = self.get_tls_context() self.cert = (self.my_cert, self.my_priv_key) if config.getboolean('general', "enable_tls"): self.tls_enabled = True else: self.tls_enabled = False self.cert = "" logger.warning( "Warning: TLS is currently disabled, keys will be sent in the clear! This should only be used for testing." )
def make_engine(self, service): """ To use: engine = self.make_engine('cloud_verifier') """ self.service = service drivername = config.get(service, 'drivername') if drivername == 'sqlite': database = "%s/%s" % (config.WORK_DIR, config.get(service, 'database')) # Create the path to where the sqlite database will be store with a perm umask of 077 os.umask(0o077) kl_dir = os.path.dirname(os.path.abspath(database)) if not os.path.exists(kl_dir): os.makedirs(kl_dir, 0o700) url = URL(drivername=drivername, username=None, password=None, host=None, database=(database)) engine = create_engine( url, connect_args={'check_same_thread': False}, ) else: url = URL(drivername=drivername, username=config.get(service, 'username'), password=config.get(service, 'password'), host=config.get(service, 'host'), database=config.get(service, 'database')) engine = create_engine(url) return engine