Example #1
0
def setUpModule():
    try:
        env = os.environ.copy()
        env['PATH']=env['PATH']+":/usr/local/bin"
        # Run init_tpm_server and tpm_serverd (start fresh)
        its = subprocess.Popen(["init_tpm_server"], shell=False, env=env)
        its.wait()
        tsd = subprocess.Popen(["tpm_serverd"], shell=False, env=env)
        tsd.wait()
    except Exception as e:
        print("WARNING: Restarting TPM emulator failed!")
    # Note: the following is required as abrmd is failing to reconnect to MSSIM, once
    # MSSIM is killed and restarted. If this is an proved an actual bug and is
    # fixed upstream, the following dbus restart call can be removed.
    try:
        sysbus = dbus.SystemBus()
        systemd1 = sysbus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1')
        manager = dbus.Interface(systemd1, 'org.freedesktop.systemd1.Manager')
        # If the systemd service exists, let's restart it.
        for service in sysbus.list_names():
            if "com.intel.tss2.Tabrmd" in service:
                print("Found dbus service:", str(service))
                try:
                    print("Restarting tpm2-abrmd.service.")
                    job = manager.RestartUnit('tpm2-abrmd.service', 'fail')
                except dbus.exceptions.DBusException as e:
                    print(e)
    except Exception as e:
        print("Non systemd agent detected, no tpm2-abrmd restart required.")

    try:
        # Start with a clean slate for this test
        fileRemove(common.WORK_DIR + "/tpmdata.yaml")
        fileRemove(common.WORK_DIR + "/cv_data.sqlite")
        fileRemove(common.WORK_DIR + "/reg_data.sqlite")
        shutil.rmtree(common.WORK_DIR + "/cv_ca", True)
    except Exception as e:
        print("WARNING: Cleanup of TPM files failed!")

    # CV must be run first to create CA and certs!
    launch_cloudverifier()
    launch_registrar()
    #launch_cloudagent()

    # get the tpm object
    global tpm

    try:
        tpm = tpm_obj.getTPM(need_hw_tpm=True)
    except Exception as e:
        print("Error: %s" % e)

    # Make the Tenant do a lot of set-up work for us
    global tenant_templ
    tenant_templ = tenant.Tenant()
    tenant_templ.cloudagent_ip = "localhost"
    tenant_templ.agent_uuid = config.get('cloud_agent', 'agent_uuid')
    tenant_templ.registrar_boot_port = config.get('registrar', 'registrar_port')
    tenant_templ.registrar_tls_boot_port = config.get('registrar', 'registrar_tls_port')
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', "") == "":
        registrar_client.init_client_tls('cloud_verifier')
        registrar_keys = registrar_client.getKeys(
            config.get("cloud_verifier", "registrar_ip"),
            config.get("cloud_verifier", "registrar_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 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 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 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['allowlist'])
    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['allowlist'], 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
Example #3
0
import tempfile
from uuid import UUID

import simplejson as json

try:
    from yaml import CSafeDumper as SafeDumper
except ImportError:
    from yaml import SafeDumper

from keylime import config
from keylime import keylime_logging
from keylime.tpm import tpm_obj

# get the tpm object
tpm = tpm_obj.getTPM(need_hw_tpm=True)

sys.path.append(os.path.dirname(__file__))

# Logging boiler plate
logger = keylime_logging.init_logging('vtpmmgr')
logger.setLevel(logging.INFO)

# ./utils/encaik -ek ~/tmp/LLSRC-tci/scripts/llsrc-vtpm-host0_pubek.pem -ik ~/tmp/LLSRC-tci/scripts/llsrc-vtpm-host0_pubek.pem -ok key.blob -oak key.aes
# cd /home/rudd/tmp/tpm4720/libtpm

# VTPM Command Ordinals. Taken from Xen's stubdoms/vtpmmgr/vtpm_manager.h
VTPM_ORD_GROUP_LIST = 0x02000101
VTPM_ORD_GROUP_NEW = 0x02000102
VTPM_ORD_GROUP_DEL = 0x02000103
VTPM_ORD_GROUP_ACTIVATE = 0x02000104
Example #4
0
def main(argv=sys.argv):
    parser = argparse.ArgumentParser(argv[0])
    parser.add_argument(
        '-c',
        '--command',
        action='store',
        dest='command',
        default='add',
        help=
        "valid commands are add,delete,update,status,list,reactivate,regdelete. defaults to add"
    )
    parser.add_argument('-t',
                        '--targethost',
                        action='store',
                        dest='agent_ip',
                        help="the IP address of the host to provision")
    parser.add_argument('-tp',
                        '--targetport',
                        action='store',
                        dest='agent_port',
                        help="the Port of the host to provision")
    parser.add_argument(
        '--cv_targethost',
        action='store',
        default=None,
        dest='cv_agent_ip',
        help=
        'the IP address of the host to provision that the verifier will use (optional).  Use only if different than argument to option -t/--targethost'
    )
    parser.add_argument('-v',
                        '--cv',
                        action='store',
                        dest='verifier_ip',
                        help="the IP address of the cloud verifier")
    parser.add_argument('-u',
                        '--uuid',
                        action='store',
                        dest='agent_uuid',
                        help="UUID for the agent to provision")
    parser.add_argument(
        '-f',
        '--file',
        action='store',
        default=None,
        help='Deliver the specified plaintext to the provisioned agent')
    parser.add_argument(
        '--cert',
        action='store',
        dest='ca_dir',
        default=None,
        help=
        'Create and deliver a certificate using a CA created by ca-util. Pass in the CA directory or use "default" to use the standard dir'
    )
    parser.add_argument(
        '-k',
        '--key',
        action='store',
        dest='keyfile',
        help='an intermedia key file produced by user_data_encrypt')
    parser.add_argument(
        '-p',
        '--payload',
        action='store',
        default=None,
        help=
        'Specify the encrypted payload to deliver with encrypted keys specified by -k'
    )
    parser.add_argument(
        '--include',
        action='store',
        dest='incl_dir',
        default=None,
        help=
        "Include additional files in provided directory in certificate zip file.  Must be specified with --cert"
    )
    parser.add_argument('--whitelist',
                        action='store',
                        dest='ima_whitelist',
                        default=None,
                        help="Specify the location of an IMA whitelist")
    parser.add_argument('--exclude',
                        action='store',
                        dest='ima_exclude',
                        default=None,
                        help="Specify the location of an IMA exclude list")
    parser.add_argument(
        '--tpm_policy',
        action='store',
        dest='tpm_policy',
        default=None,
        help=
        "Specify a TPM policy in JSON format. e.g., {\"15\":\"0000000000000000000000000000000000000000\"}"
    )
    parser.add_argument('--vtpm_policy',
                        action='store',
                        dest='vtpm_policy',
                        default=None,
                        help="Specify a vTPM policy in JSON format")
    parser.add_argument(
        '--verify',
        action='store_true',
        default=False,
        help=
        'Block on cryptographically checked key derivation confirmation from the agent once it has been provisioned'
    )

    if common.DEVELOP_IN_ECLIPSE and len(argv) == 1:
        ca_util.setpassword('default')
        #tmp = ['-c','add','-t','127.0.0.1','-v', '127.0.0.1','-u','C432FBB3-D2F1-4A97-9EF7-75BD81C866E9','-p','content_payload.txt','-k','content_keys.txt']
        #tmp = ['-c','add','-t','127.0.0.1','-v','127.0.0.1','-u','C432FBB3-D2F1-4A97-9EF7-75BD81C866E9','-f','tenant.py']
        tmp = [
            '-c', 'add', '-t', '127.0.0.1', '-v', '127.0.0.1', '-u',
            'C432FBB3-D2F1-4A97-9EF7-75BD81C866E9', '--cert', 'ca/'
        ]
        #tmp = ['-c','delete','-t','127.0.0.1','-v','127.0.0.1','-u','C432FBB3-D2F1-4A97-9EF7-75BD81C866E9']
        #tmp = ['-c','reactivate','-t','127.0.0.1','-v','127.0.0.1','-u','C432FBB3-D2F1-4A97-9EF7-75BD81C866E9']
        #tmp = ['-c','list','-v', '127.0.0.1','-u','C432FBB3-D2F1-4A97-9EF7-75BD81C866E9']
        #tmp = ['-c','regdelete','-u','C432FBB3-D2F1-4A97-9EF7-75BD81C866E9']
    else:
        tmp = argv[1:]

    args = parser.parse_args(tmp)
    mytenant = Tenant()

    if args.command not in ['list', 'regdelete', 'delete'
                            ] and args.agent_ip is None:
        raise UserError(
            f"-t/--targethost is required for command {args.command}")

    if args.agent_uuid is not None:
        mytenant.agent_uuid = args.agent_uuid
        # if the uuid is actually a public key, then hash it
        if mytenant.agent_uuid.startswith('-----BEGIN PUBLIC KEY-----'):
            mytenant.agent_uuid = hashlib.sha256(
                mytenant.agent_uuid).hexdigest()
    else:
        logger.warning(
            "Using default UUID D432FBB3-D2F1-4A97-9EF7-75BD81C00000")
        mytenant.agent_uuid = "D432FBB3-D2F1-4A97-9EF7-75BD81C00000"

    if common.STUB_VTPM and common.TPM_CANNED_VALUES is not None:
        # Use canned values for agent UUID
        jsonIn = common.TPM_CANNED_VALUES
        if "add_vtpm_to_group" in jsonIn:
            mytenant.agent_uuid = jsonIn['add_vtpm_to_group']['retout']
        else:
            # Our command hasn't been canned!
            raise UserError("Command %s not found in canned JSON!" %
                            ("add_vtpm_to_group"))

    if args.verifier_ip is not None:
        mytenant.cloudverifier_ip = args.verifier_ip

    if args.command == 'add':
        mytenant.init_add(vars(args))
        mytenant.preloop()
        mytenant.do_cv()
        mytenant.do_quote()
        if args.verify:
            mytenant.do_verify()

        if common.DEVELOP_IN_ECLIPSE:
            time.sleep(2)
            mytenant.do_cvstatus()
            time.sleep(1)
            # invalidate it eventually
            logger.debug("invalidating PCR 15, forcing revocation")
            tpm = tpm_obj.getTPM(need_hw_tpm=True)
            tpm.extendPCR(15, tpm.hashdigest(b"garbage"))
            time.sleep(5)
            logger.debug("Deleting agent from verifier")
            mytenant.do_cvdelete()
    elif args.command == 'update':
        mytenant.init_add(vars(args))
        mytenant.do_cvdelete()
        mytenant.preloop()
        mytenant.do_cv()
        mytenant.do_quote()
        if args.verify:
            mytenant.do_verify()
    elif args.command == 'delete':
        mytenant.do_cvdelete()
    elif args.command == 'status':
        mytenant.do_cvstatus()
    elif args.command == 'list':
        mytenant.do_cvstatus(listing=True)
    elif args.command == 'reactivate':
        mytenant.do_cvreactivate()
    elif args.command == 'regdelete':
        mytenant.do_regdelete()
    else:
        raise UserError("Invalid command specified: %s" % (args.command))
Example #5
0
    def validate_tpm_quote(self, public_key, quote, tpm_version, hash_alg):
        registrar_client.init_client_tls(config, 'tenant')
        reg_keys = registrar_client.getKeys(self.registrar_ip,
                                            self.registrar_port,
                                            self.agent_uuid)
        if reg_keys is None:
            logger.warning("AIK not found in registrar, quote not validated")
            return False

        tpm = tpm_obj.getTPM(need_hw_tpm=False, tpm_version=tpm_version)
        if not tpm.check_quote(self.agent_uuid,
                               self.nonce,
                               public_key,
                               quote,
                               reg_keys['aik'],
                               hash_alg=hash_alg):
            if reg_keys['regcount'] > 1:
                logger.error(
                    "WARNING: This UUID had more than one ek-ekcert registered to it!  This might indicate that your system is misconfigured or a malicious host is present.  Run 'regdelete' for this agent and restart"
                )
                exit()
            return False

        if reg_keys['regcount'] > 1:
            logger.warn(
                "WARNING: This UUID had more than one ek-ekcert registered to it!  This might indicate that your system is misconfigured.  Run 'regdelete' for this agent and restart"
            )

        if not common.STUB_TPM and (
                not config.getboolean('tenant', 'require_ek_cert')
                and config.get('tenant', 'ek_check_script') == ""):
            logger.warn(
                "DANGER: EK cert checking is disabled and no additional checks on EKs have been specified with ek_check_script option. Keylime is not secure!!"
            )

        # check EK cert and make sure it matches EK
        if not self.check_ek(reg_keys['ek'], reg_keys['ekcert'], tpm):
            return False
        # if agent is virtual, check phyisical EK cert and make sure it matches phyiscal EK
        if 'provider_keys' in reg_keys:
            if not self.check_ek(reg_keys['provider_keys']['ek'],
                                 reg_keys['provider_keys']['ekcert'], tpm):
                return False

        # check all EKs with optional script:
        script = config.get('tenant', 'ek_check_script')
        if script != "":
            if script[0] != '/':
                script = "%s/%s" % (common.WORK_DIR, script)

            logger.info(f"Checking EK with script {script}")
            # now we need to exec the script with the ek and ek cert in vars
            env = os.environ.copy()
            env['AGENT_UUID'] = self.agent_uuid
            env['EK'] = reg_keys['ek']
            if reg_keys['ekcert'] is not None:
                env['EK_CERT'] = reg_keys['ekcert']
            else:
                env['EK_CERT'] = ""

            env['PROVKEYS'] = json.dumps(reg_keys.get('provider_keys', {}))
            proc = subprocess.Popen(script,
                                    env=env,
                                    shell=True,
                                    cwd=common.WORK_DIR,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.STDOUT)
            retval = proc.wait()

            if retval != 0:
                raise UserError("External check script failed to validate EK")
                while True:
                    line = proc.stdout.readline()
                    if line == "":
                        break
                    logger.debug(f"ek_check output: {line.strip()}")
                return False
            else:
                logger.debug(
                    "External check script successfully to validated EK")
                while True:
                    line = proc.stdout.readline()
                    if line == "":
                        break
                    logger.debug(f"ek_check output: {line.strip()}")
        return True
Example #6
0
    def do_PUT(self):
        """This method handles the PUT requests to add agents to the Registrar Server.

        Currently, only agents resources are available for PUTing, i.e. /agents. All other PUT uri's
        will return errors.
        """
        session = SessionManager().make_session(engine)
        rest_params = common.get_restful_params(self.path)
        if rest_params is None:
            common.echo_json_response(
                self, 405, "Not Implemented: Use /agents/ interface")
            return

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

        agent_id = rest_params["agents"]

        if agent_id is None:
            common.echo_json_response(self, 400, "agent id not found in uri")
            logger.warning(
                'PUT agent returning 400 response. agent 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 ' + agent_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']
                try:
                    agent = session.query(RegistrarMain).filter_by(
                        agent_id=agent_id).first()
                except SQLAlchemyError as e:
                    logger.error(f'SQLAlchemy Error: {e}')

                if agent is None:
                    raise Exception(
                        "attempting to activate agent before requesting registrar for %s"
                        % agent_id)

                if agent.virtual:
                    raise Exception(
                        "attempting to activate virtual AIK using physical interface for %s"
                        % agent_id)

                if common.STUB_TPM:
                    try:
                        session.query(RegistrarMain).filter(
                            agent_id == agent_id).update({'active': True})
                        session.commit()
                    except SQLAlchemyError as e:
                        logger.error(f'SQLAlchemy Error: {e}')
                else:
                    ex_mac = crypto.do_hmac(agent.key, agent_id)
                    if ex_mac == auth_tag:
                        try:
                            session.query(RegistrarMain).filter(
                                agent_id == agent_id).update({'active': True})
                            session.commit()
                        except SQLAlchemyError as e:
                            logger.error(f'SQLAlchemy Error: {e}')
                    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: ' + agent_id)
            elif "vactivate" in rest_params:
                deepquote = json_body.get('deepquote', None)
                try:
                    agent = session.query(RegistrarMain).filter_by(
                        agent_id=agent_id).first()
                except SQLAlchemyError as e:
                    logger.error(f'SQLAlchemy Error: {e}')
                if agent is None:
                    raise Exception(
                        "attempting to activate agent before requesting registrar for %s"
                        % agent_id)

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

                # get an physical AIK for this host
                registrar_client.init_client_tls(config, 'registrar')
                provider_keys = registrar_client.getKeys(
                    config.get('registrar', 'provider_registrar_ip'),
                    config.get('registrar', 'provider_registrar_tls_port'),
                    agent_id)
                # we already have the vaik
                tpm = tpm_obj.getTPM(need_hw_tpm=False,
                                     tpm_version=agent['tpm_version'])
                if not tpm.check_deep_quote(
                        agent_id,
                        hashlib.sha1(agent['key']).hexdigest(),
                        agent_id + agent['aik'] + agent['ek'], deepquote,
                        agent['aik'], provider_keys['aik']):
                    raise Exception("Deep quote invalid")
                try:
                    session.query(RegistrarMain).filter(
                        agent_id == agent_id).update({'active': True})
                except SQLAlchemyError as e:
                    logger.error(f'SQLAlchemy Error: {e}')
                try:
                    session.query(RegistrarMain).filter(
                        agent_id == agent_id).update(
                            {'provider_keys': provider_keys})
                except SQLAlchemyError as e:
                    logger.error(f'SQLAlchemy Error: {e}')

                common.echo_json_response(self, 200, "Success")
                logger.info('PUT activated: ' + agent_id)
            else:
                pass
        except Exception as e:
            common.echo_json_response(self, 400, "Error: %s" % e)
            logger.warning("PUT for " + agent_id +
                           " returning 400 response. Error: %s" % e)
            logger.exception(e)
            return
Example #7
0
    def do_POST(self):
        """This method handles the POST requests to add agents to the Registrar Server.

        Currently, only agents resources are available for POSTing, i.e. /agents. All other POST uri's
        will return errors. POST requests require an an agent_id identifying the agent to add, and json
        block sent in the body with 2 entries: ek and aik.
        """
        session = SessionManager().make_session(engine)
        rest_params = common.get_restful_params(self.path)
        if rest_params is None:
            common.echo_json_response(
                self, 405, "Not Implemented: Use /agents/ interface")
            return

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

        agent_id = rest_params["agents"]

        if agent_id is None:
            common.echo_json_response(self, 400, "agent id not found in uri")
            logger.warning(
                'POST agent returning 400 response. agent 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(
                    'POST for ' + agent_id +
                    ' returning 400 response. Expected non zero content length.'
                )
                return

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

            ek = json_body['ek']
            ek_tpm = json_body['ek_tpm']
            ekcert = json_body['ekcert']
            aik = json_body['aik']
            aik_name = json_body['aik_name']
            tpm_version = int(json_body['tpm_version'])

            # try to encrypt the AIK
            tpm = tpm_obj.getTPM(need_hw_tpm=False, tpm_version=tpm_version)
            (blob, key) = tpm.encryptAIK(agent_id, aik, ek, ek_tpm, aik_name)
            # special behavior if we've registered this uuid before
            regcount = 1
            try:
                agent = session.query(RegistrarMain).filter_by(
                    agent_id=agent_id).first()
            except SQLAlchemyError as e:
                logger.error(f'SQLAlchemy Error: {e}')

            if agent is not None:

                # keep track of how many ek-ekcerts have registered on this uuid
                regcount = agent.regcount
                if agent.ek != ek or agent.ekcert != ekcert:
                    logger.warning(
                        'WARNING: Overwriting previous registration for this UUID with new ek-ekcert pair!'
                    )
                    regcount += 1

                # force overwrite
                logger.info('Overwriting previous registration for this UUID.')
                try:
                    session.query(RegistrarMain).filter_by(
                        agent_id=agent_id).delete()
                    session.commit()
                except SQLAlchemyError as e:
                    logger.error(f'SQLAlchemy Error: {e}')

            # Add values to database
            d = {}
            d['agent_id'] = agent_id
            d['ek'] = ek
            d['aik'] = aik
            d['ekcert'] = ekcert
            d['virtual'] = int(ekcert == 'virtual')
            d['active'] = int(False)
            d['key'] = key
            d['provider_keys'] = {}
            d['regcount'] = regcount

            try:
                session.add(RegistrarMain(**d))
                session.commit()
            except SQLAlchemyError as e:
                logger.error(f'SQLAlchemy Error: {e}')

            response = {
                'blob': blob,
            }
            common.echo_json_response(self, 200, "Success", response)

            logger.info('POST returning key blob for agent_id: ' + agent_id)
            return
        except Exception as e:
            common.echo_json_response(self, 400, "Error: %s" % e)
            logger.warning("POST for " + agent_id +
                           " returning 400 response. Error: %s" % e)
            logger.exception(e)
            return