def test_012_reg_instance_vactivate_put(self):
        """Test registrar's PUT /v2/instances/{UUID}/vactivate Interface"""
        global keyblob, aik, ek

        self.assertIsNotNone(
            keyblob, "Required value not set.  Previous step may have failed?")
        self.assertIsNotNone(
            aik, "Required value not set.  Previous step may have failed?")
        self.assertIsNotNone(
            ek, "Required value not set.  Previous step may have failed?")

        key = tpm_initialize.activate_identity(keyblob)
        deepquote = tpm_quote.create_deep_quote(
            hashlib.sha1(key).hexdigest(), tenant_templ.node_uuid + aik + ek)
        data = {
            'deepquote': deepquote,
        }
        v_json_message = json.dumps(data)

        response = tornado_requests.request(
            "PUT",
            "http://%s:%s/v2/instances/%s/vactivate" %
            (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 vActivate return code!")
        response_body = response.json()

        # Ensure response is well-formed
        self.assertIn("results", response_body, "Malformed response body!")
 def do_GET(self):
     """This method services the GET request typically from either the Tenant or the Cloud Verifier.
     
     Only tenant and cloudverifier uri's are supported. Both requests require a nonce parameter.  
     The Cloud verifier requires an additional mask paramter.  If the uri or parameters are incorrect, a 400 response is returned.
     """
     
     logger.info('GET invoked from ' + str(self.client_address)  + ' with uri:' + self.path)
     
     rest_params = common.get_restful_params(self.path)
     if rest_params is None:
         common.echo_json_response(self, 405, "Not Implemented: Use /v2/keys/ or /v2/quotes/ interfaces")
         return
     
     if "keys" in rest_params and rest_params['keys']=='verify':
         if self.server.K is None:
             logger.info('GET key challenge returning 400 response. bootstrap key not available')
             common.echo_json_response(self, 400, "Bootstrap key not yet available.")
             return
         challenge = rest_params['challenge']
         response={}
         response['hmac'] = crypto.do_hmac(self.server.K, challenge)            
         common.echo_json_response(self, 200, "Success", response)
         logger.info('GET key challenge returning 200 response.')
         
     # If node pubkey requested
     elif "keys" in rest_params and rest_params["keys"] == "pubkey":
         response = {}
         response['pubkey'] = self.server.rsapublickey_exportable
         
         common.echo_json_response(self, 200, "Success", response)
         logger.info('GET pubkey returning 200 response.')
         return
     
     elif "quotes" in rest_params:
         nonce = rest_params['nonce']
         pcrmask = rest_params['mask'] if 'mask' in rest_params else None
         vpcrmask = rest_params['vmask'] if 'vmask' in rest_params else None
         
         # if the query is not messed up
         if nonce is None:
             logger.warning('GET quote returning 400 response. nonce not provided as an HTTP parameter in request')
             common.echo_json_response(self, 400, "nonce not provided as an HTTP parameter in request")
             return
         
         # Sanitization assurance (for tpm_exec.run() tasks below) 
         if not (nonce.isalnum() and (pcrmask is None or pcrmask.isalnum()) and (vpcrmask is None or vpcrmask.isalnum())):
             logger.warning('GET quote returning 400 response. parameters should be strictly alphanumeric')
             common.echo_json_response(self, 400, "parameters should be strictly alphanumeric")
             return
         
         # identity quotes are always shallow
         if not tpm_initialize.is_vtpm() or rest_params["quotes"]=='identity':
             quote = tpm_quote.create_quote(nonce, self.server.rsapublickey_exportable,pcrmask)
             imaMask = pcrmask
         else:
             quote = tpm_quote.create_deep_quote(nonce, self.server.rsapublickey_exportable, vpcrmask, pcrmask)
             imaMask = vpcrmask
         
         # Allow for a partial quote response (without pubkey) 
         if "partial" in rest_params and (rest_params["partial"] is None or int(rest_params["partial"],0) == 1):
             response = { 
                 'quote': quote, 
                 }
         else:
             response = {
                 'quote': quote, 
                 'pubkey': self.server.rsapublickey_exportable, 
             }
         
         # return a measurement list if available
         if tpm_quote.check_mask(imaMask, common.IMA_PCR):
             if not os.path.exists(common.IMA_ML):
                 logger.warn("IMA measurement list not available: %s"%(common.IMA_ML))
             else:
                 with open(common.IMA_ML,'r') as f:
                     ml = f.read()
                 response['ima_measurement_list']=ml
         
         common.echo_json_response(self, 200, "Success", response)
         logger.info('GET %s quote returning 200 response.'%(rest_params["quotes"]))
         return
     
     else:
         logger.warning('GET returning 400 response. uri not supported: ' + self.path)
         common.echo_json_response(self, 400, "uri not supported")
         return
def main(argv=sys.argv):
    if os.getuid()!=0 and common.REQUIRE_ROOT:
        logger.critical("This process must be run as root.")
        return

    # get params for initialization
    registrar_ip = config.get('general', 'registrar_ip')
    registrar_port = config.get('general', 'registrar_port')
    
    # initialize the tmpfs partition to store keys if it isn't already available
    secdir = secure_mount.mount()

    # change dir to working dir
    common.ch_dir(common.WORK_DIR,logger)
    
    #initialize tpm 
    (ek,ekcert,aik) = tpm_initialize.init(self_activate=False,config_pw=config.get('cloud_node','tpm_ownerpassword')) # this tells initialize not to self activate the AIK
    virtual_node = tpm_initialize.is_vtpm()
    
    # try to get some TPM randomness into the system entropy pool
    tpm_random.init_system_rand()
        
    if ekcert is None:
        if virtual_node:
            ekcert = 'virtual'
        elif tpm_initialize.is_emulator():
            ekcert = 'emulator'
        
    # now we need the UUID
    try:
        node_uuid = config.get('cloud_node','node_uuid')
    except ConfigParser.NoOptionError:
        node_uuid = None
    if node_uuid == 'openstack':
        node_uuid = openstack.get_openstack_uuid()
    elif node_uuid == 'hash_ek':
        node_uuid = hashlib.sha256(ek).hexdigest()
    elif node_uuid == 'generate' or node_uuid is None:
        node_uuid = str(uuid.uuid4())
    if common.DEVELOP_IN_ECLIPSE:
        node_uuid = "C432FBB3-D2F1-4A97-9EF7-75BD81C866E9"
    if common.STUB_VTPM and common.TPM_CANNED_VALUES is not None:
        # Use canned values for stubbing 
        jsonIn = common.TPM_CANNED_VALUES
        if "add_vtpm_to_group" in jsonIn:
            # The value we're looking for has been canned! 
            node_uuid = jsonIn['add_vtpm_to_group']['retout']
        else:
            # Our command hasn't been canned!
            raise Exception("Command %s not found in canned JSON!"%("add_vtpm_to_group"))
    
    logger.info("Node UUID: %s"%node_uuid)
    
    # register it and get back a blob
    keyblob = registrar_client.doRegisterNode(registrar_ip,registrar_port,node_uuid,ek,ekcert,aik)
    
    if keyblob is None:
        raise Exception("Registration failed")
    
    # get the ephemeral registrar key
    key = tpm_initialize.activate_identity(keyblob)
    
    # tell the registrar server we know the key
    retval=False
    if virtual_node:
        deepquote = tpm_quote.create_deep_quote(hashlib.sha1(key).hexdigest(),node_uuid+aik+ek)
        retval = registrar_client.doActivateVirtualNode(registrar_ip, registrar_port, node_uuid, deepquote)
    else:
        retval = registrar_client.doActivateNode(registrar_ip,registrar_port,node_uuid,key)

    if not retval:
        raise Exception("Registration failed on activate")
    
    serveraddr = ('', config.getint('general', 'cloudnode_port'))
    server = CloudNodeHTTPServer(serveraddr,Handler,node_uuid)
    serverthread = threading.Thread(target=server.serve_forever)

    logger.info( 'Starting Cloud Node on port %s use <Ctrl-C> to stop'%serveraddr[1])
    serverthread.start()
    
    # want to listen for revocations?
    if config.getboolean('cloud_node','listen_notfications'):
        cert_path = config.get('cloud_node','revocation_cert')
        if cert_path == "default":
            cert_path = '%s/unzipped/RevocationNotifier-cert.crt'%(secdir)
        elif cert_path[0]!='/':
            # if it is a relative, convert to absolute in work_dir
            cert_path = os.path.abspath('%s/%s'%(common.WORK_DIR,cert_path))
            
        def perform_actions(revocation):
            actionlist = config.get('cloud_node','revocation_actions')
            if actionlist.strip() == "":
                logger.debug("No revocation actions specified")
                return
            if actionlist =='default':
                # load actions from unzipped
                with open("%s/unzipped/action_list"%secdir,'r') as f:
                    actionlist = f.read()
 
                actionlist = actionlist.strip().split(',')
                uzpath = "%s/unzipped"%secdir
                if uzpath not in sys.path:
                    sys.path.append(uzpath)
            else:
                # load the actions from inside the keylime module
                actionlist = actionlist.split(',')
                actionlist = ["revocation_actions.%s"%i for i in actionlist]
            
            for action in actionlist:
                module = importlib.import_module(action)
                execute = getattr(module,'execute')
                try:
                    execute(revocation)
                except Exception as e:
                    logger.warn("Exception during exeuction of revocation action %s: %s"%(action,e))
        try:
            while True:
                try:
                    revocation_notifier.await_notifications(perform_actions,revocation_cert_path=cert_path)
                except Exception as e:
                    logger.exception(e)
                    logger.warn("No connection to revocation server, retrying in 10s...")
                    time.sleep(10)
        except KeyboardInterrupt:
            logger.info("TERM Signal received, shutting down...")
            tpm_initialize.flush_keys()
            server.shutdown()
    else:  
        try:
            while True:
                time.sleep(1)
        except KeyboardInterrupt:
            logger.info("TERM Signal received, shutting down...")
            tpm_initialize.flush_keys()
            server.shutdown()
Beispiel #4
0
    def do_GET(self):
        """This method services the GET request typically from either the Tenant or the Cloud Verifier.
        
        Only tenant and cloudverifier uri's are supported. Both requests require a nonce parameter.  
        The Cloud verifier requires an additional mask paramter.  If the uri or parameters are incorrect, a 400 response is returned.
        """

        logger.info('GET invoked from ' + str(self.client_address) +
                    ' with uri:' + self.path)

        if not self.is_quote():
            logger.warning('GET returning 400 response. uri not supported: ' +
                           self.path)
            self.send_response(400)
            self.end_headers()
            return

        nonce = self.get_query_tag_value(self.path, 'nonce')
        pcrmask = self.get_query_tag_value(self.path, 'mask')
        vpcrmask = self.get_query_tag_value(self.path, 'vmask')

        # if the query is not messed up
        if nonce is None:
            logger.warning(
                'GET quote returning 400 response. nonce not provided as an HTTP parameter in request'
            )
            self.send_response(400)
            self.end_headers()
            return

        if self.is_tenant_quote():
            #always need share when talking to the tenant
            need_share = True
        elif self.is_cloudverifier_quote():
            # if we already have a K, then no need to ask for V again
            if self.server.K is not None and self.get_query_tag_value(
                    self.path, 'need_pubkey') != 'True':
                need_share = False
            else:
                need_share = True
        else:
            logger.warning('GET returning 400 response. uri not supported: ' +
                           self.path)
            self.send_response(400)
            self.end_headers()
            return

        if vpcrmask is None:
            quote = tpm_quote.create_quote(nonce,
                                           self.server.rsapublickey_exportable,
                                           pcrmask)
            imaMask = pcrmask
        else:
            quote = tpm_quote.create_deep_quote(
                nonce, self.server.rsapublickey_exportable, vpcrmask, pcrmask)
            imaMask = vpcrmask

        response = {'quote': quote}

        if need_share:
            response['pubkey'] = self.server.rsapublickey_exportable

        # return a measurement list if available
        if tpm_quote.check_mask(imaMask, common.IMA_PCR):
            if not os.path.exists(common.IMA_ML):
                logger.warn("IMA measurement list not available: %s" %
                            (common.IMA_ML))
            else:
                with open(common.IMA_ML, 'r') as f:
                    ml = f.read()
                response['ima_measurement_list'] = ml

        json_response = json.dumps(response)

        self.send_response(200)
        self.end_headers()
        self.wfile.write(json_response)
        logger.info('GET %s quote returning 200 response.' %
                    ('tenant', 'verifier')[self.is_cloudverifier_quote()])
        return
Beispiel #5
0
def main(argv=sys.argv):
    if os.getuid() != 0 and not common.DEVELOP_IN_ECLIPSE:
        logger.critical("This process must be run as root.")
        return

    # get params for initialization
    registrar_ip = config.get('general', 'registrar_ip')
    registrar_port = config.get('general', 'registrar_port')

    # initialize the tmpfs partition to store keys if it isn't already available
    secure_mount.mount()

    # change dir to working dir
    common.ch_dir()

    #initialize tpm
    (ek, ekcert, aik) = tpm_initialize.init(
        self_activate=False,
        config_pw=config.get('cloud_node', 'tpm_ownerpassword')
    )  # this tells initialize not to self activate the AIK
    virtual_node = tpm_initialize.is_vtpm()

    if common.STUB_TPM:
        ekcert = common.TEST_EK_CERT

    if virtual_node and (ekcert is None or common.STUB_TPM):
        ekcert = 'virtual'

    # now we need the UUID
    try:
        node_uuid = config.get('cloud_node', 'node_uuid')
    except ConfigParser.NoOptionError:
        node_uuid = None
    if node_uuid == 'openstack':
        node_uuid = openstack.get_openstack_uuid()
    elif node_uuid == 'hash_ek':
        node_uuid = hashlib.sha256(ek).hexdigest()
    elif node_uuid == 'generate' or node_uuid is None:
        node_uuid = str(uuid.uuid4())
    if common.DEVELOP_IN_ECLIPSE:
        node_uuid = "C432FBB3-D2F1-4A97-9EF7-75BD81C866E9"

    # use an TLS context with no certificate checking
    registrar_client.noAuthTLSContext(config)

    # register it and get back a blob
    keyblob = registrar_client.doRegisterNode(registrar_ip, registrar_port,
                                              node_uuid, ek, ekcert, aik)

    if keyblob is None:
        raise Exception("Registration failed")

    # get the ephemeral registrar key
    key = tpm_initialize.activate_identity(keyblob)

    # tell the registrar server we know the key
    if virtual_node:
        deepquote = tpm_quote.create_deep_quote(
            hashlib.sha1(key).hexdigest(), node_uuid + aik + ek)
        registrar_client.doActivateVirtualNode(registrar_ip, registrar_port,
                                               node_uuid, deepquote)
    else:
        registrar_client.doActivateNode(registrar_ip, registrar_port,
                                        node_uuid, key)

    serveraddr = ('', config.getint('general', 'cloudnode_port'))
    server = CloudNodeHTTPServer(serveraddr, Handler, node_uuid)

    thread = threading.Thread(target=server.serve_forever)

    threads = []
    servers = []

    threads.append(thread)
    servers.append(server)

    # start the server
    logger.info('Starting Cloud Node on port %s use <Ctrl-C> to stop' %
                serveraddr[1])
    for thread in threads:
        thread.start()

    def signal_handler(signal, frame):
        do_shutdown(servers)
        sys.exit(0)

    # Catch these signals.  Note that a SIGKILL cannot be caught, so
    # killing this process with "kill -9" may result in improper shutdown
    signal.signal(signal.SIGTERM, signal_handler)
    signal.signal(signal.SIGQUIT, signal_handler)
    signal.signal(signal.SIGINT, signal_handler)

    # keep the main thread active, so it can process the signals and gracefully shutdown
    while True:
        if not any([thread.isAlive() for thread in threads]):
            # All threads have stopped
            break
        else:
            # Some threads are still going
            time.sleep(1)

    for thread in threads:
        thread.join()