def create_quote(nonce, data=None, pcrmask=EMPTYMASK): quote = "" with tempfile.NamedTemporaryFile() as quotepath: keyhandle = tpm_initialize.get_tpm_metadata('aik_handle') aik_pw = tpm_initialize.get_tpm_metadata('aik_pw') if pcrmask is None: pcrmask = EMPTYMASK with tpm_exec.tpmutilLock: if data is not None: # add PCR 16 to pcrmask pcrmask = "0x%X" % (int(pcrmask, 0) + (1 << common.TPM_DATA_PCR)) tpm_exec.run("pcrreset -ix %d" % common.TPM_DATA_PCR, lock=False) tpm_exec.run( "extend -ix %d -ic %s" % (common.TPM_DATA_PCR, hashlib.sha1(data).hexdigest()), lock=False) command = "tpmquote -hk %s -pwdk %s -bm %s -nonce %s -noverify -oq %s" % ( keyhandle, aik_pw, pcrmask, nonce, quotepath.name) (retout, code, quoteraw) = tpm_exec.run(command, lock=False, outputpath=quotepath.name) quote = base64.b64encode(quoteraw.encode("zlib")) return 'r' + quote
def tpmconv(inmod): """ convert a raw modulus file into a pem file """ tmppath = None try: #make a temp file for the output tmpfd,tmppath = tempfile.mkstemp() #make temp file for the input infd, intemp = tempfile.mkstemp() inFile = open(intemp,"wb") inFile.write(inmod) inFile.close() os.close(infd) command = "tpmconv -ik %s -ok %s" % (inFile.name,tmppath) tpm_exec.run(command,lock=False) # read in the pem f = open(tmppath,"rb") pem = f.read() f.close() os.close(tmpfd) finally: if tmppath is not None: os.remove(tmppath) if inFile is not None: os.remove(inFile.name) return pem
def encryptAIK(uuid, pubaik, pubek): pubaikFile = None pubekFile = None keyblob = None blobpath = None keypath = None try: # write out pubaik pfd, ptemp = tempfile.mkstemp() pubaikFile = open(ptemp, "wb") pubaikFile.write(pubaik) pubaikFile.close() os.close(pfd) # write out the public EK efd, etemp = tempfile.mkstemp() pubekFile = open(etemp, "wb") pubekFile.write(pubek) pubekFile.close() os.close(efd) #create temp files for the blob blobfd, blobpath = tempfile.mkstemp() keyfd, keypath = tempfile.mkstemp() tpm_exec.run("encaik -ik %s -ek %s -ok %s -oak %s" % (pubaikFile.name, pubekFile.name, blobpath, keypath), lock=False) logger.info("Encrypting AIK for UUID %s" % uuid) # read in the blob f = open(blobpath, "rb") keyblob = base64.b64encode(f.read()) f.close() os.close(blobfd) # read in the aes key f = open(keypath, "rb") key = base64.b64encode(f.read()) f.close() os.close(keyfd) except Exception as e: logger.error("Error encrypting AIK: " + str(e)) logger.error(traceback.format_exc()) return False finally: if pubaikFile is not None: os.remove(pubaikFile.name) if pubekFile is not None: os.remove(pubekFile.name) if blobpath is not None: os.remove(blobpath) if keypath is not None: os.remove(keypath) pass return (keyblob, key)
def convert_crl_to_pem(derfile, pemfile): if config.get('general', 'ca_implementation') == 'openssl': with open(pemfile, 'w') as f: f.write("") else: tpm_exec.run("openssl crl -in %s -inform der -out %s" % (derfile, pemfile), lock=False)
def flush_keys(): logger.debug("Flushing keys from TPM...") retout = tpm_exec.run("listkeys")[0] for line in retout: tokens = line.split() if len(tokens)==4 and tokens[0]=='Key' and tokens[1]=='handle': handle = tokens[3].upper() #logger.debug("Flushing key handle %s"%handle) tpm_exec.run("flushspecific -ha %s -rt 1"%handle)
def write_key_nvram(key): owner_pw = tpm_initialize.get_tpm_metadata('owner_pw') # write out quote with tempfile.NamedTemporaryFile() as keyFile: keyFile.write(key) keyFile.flush() tpm_exec.run( "nv_definespace -pwdo %s -in 1 -sz %d -pwdd %s -per 40004" % (owner_pw, common.BOOTSTRAP_KEY_SIZE, owner_pw)) tpm_exec.run("nv_writevalue -pwdd %s -in 1 -if %s" % (owner_pw, keyFile.name)) return
def activate_identity(keyblob): if common.STUB_TPM: return base64.b64encode(common.TEST_AES_REG_KEY) owner_pw = get_tpm_metadata('owner_pw') keyblobFile = None secpath = None try: # write out key blob kfd, ktemp = tempfile.mkstemp() keyblobFile = open(ktemp, "wb") keyblobFile.write(base64.b64decode(keyblob)) keyblobFile.close() os.close(kfd) keyhandle = load_aik() keyfd, keypath = tempfile.mkstemp() # read in the key f = open(keypath, "rb") key = f.read() f.close() os.close(keyfd) # ok lets write out the key now secdir = secure_mount.mount( ) # confirm that storage is still securely mounted secfd, secpath = tempfile.mkstemp(dir=secdir) tpm_exec.run("activateidentity -hk %s -pwdo %s -if %s -ok %s" % (keyhandle, owner_pw, keyblobFile.name, secpath)) logger.info("AIK activated.") f = open(secpath, 'rb') key = base64.b64encode(f.read()) f.close() os.close(secfd) os.remove(secpath) except Exception as e: logger.error("Error decrypting AIK: " + str(e)) logger.error(traceback.format_exc()) return False finally: if keyblobFile is not None: os.remove(keyblobFile.name) if secpath is not None and os.path.exists(secpath): os.remove(secpath) return key
def mount(): if not common.MOUNT_SECURE: return "." secdir = common.WORK_DIR+"/secure" if not check_mounted(secdir): # ok now we know it isn't already mounted, go ahead and create and mount if not os.path.exists(secdir): os.makedirs(secdir,0o700) os.chown(secdir, 0, 0) size = config.get('cloud_node','secure_size') logger.info("mounting secure storage location %s on tmpfs"%secdir) tpm_exec.run("mount -t tmpfs -o size=%s,mode=0700 tmpfs %s" %(size,secdir),lock=False) return secdir
def read_ekcert_nvram(): if common.STUB_TPM: return common.TEST_EK_CERT nvpath = None try: owner_pw = tpm_initialize.get_tpm_metadata('owner_pw') #make a temp file for the quote nvfd,nvpath = tempfile.mkstemp() (output,code) = tpm_exec.run("nv_readvalue -pwdo %s -in 1000f000 -cert -of %s"%(owner_pw,nvpath),raiseOnError=False) if code!=tpm_exec.EXIT_SUCESS and len(output)>0 and output[0].startswith("Error Illegal index from NV_ReadValue"): logger.warn("No EK certificate found in TPM NVRAM") return None elif code!=tpm_exec.EXIT_SUCESS: raise Exception("nv_readvalue for ekcert failed with code "+str(code)+": "+str(output)) # read in the cert f = open(nvpath,"rb") ekcert = f.read() f.close() os.close(nvfd) finally: if nvpath is not None: os.remove(nvpath) return base64.b64encode(ekcert)
def check_expiration(): logger.info("checking CRL for expiration every hour") while True: try: if os.path.exists('%s/cacrl.der' % workingdir): retout = tpm_exec.run( "openssl crl -inform der -in %s/cacrl.der -text -noout" % workingdir, lock=False)[0] for line in retout: line = line.strip() if line.startswith("Next Update:"): expire = datetime.datetime.strptime( line[13:], "%b %d %H:%M:%S %Y %Z") # check expiration within 6 hours in1hour = datetime.datetime.utcnow( ) + datetime.timedelta(hours=6) if expire <= in1hour: logger.info( "Certificate to expire soon %s, re-issuing" % expire) cmd_regencrl(workingdir) # check a little less than every hour time.sleep(3540) except KeyboardInterrupt: logger.info("TERM Signal received, shutting down...") #server.shutdown() break
def load_aik(): # dont' even try to see if the key is already loaded. we're flushing them now # # is the key already there? # modFromFile = get_tpm_metadata('aikmod') # # retout = tpm_exec.run("listkeys")[0] # for line in retout: # tokens = line.split() # if len(tokens)==4 and tokens[0]=='Key' and tokens[1]=='handle': # handle = tokens[3] # modFromTPM = get_mod_from_tpm(handle) # if modFromTPM == modFromFile: # logger.debug("Located AIK at key handle %s"%handle) # return handle # # # we didn't find the key logger.debug("Loading AIK private key into TPM") # write out private key with tempfile.NamedTemporaryFile() as inFile: inFile.write(base64.b64decode(get_tpm_metadata('aikpriv'))) inFile.flush() retout = tpm_exec.run("loadkey -hp 40000000 -ik %s"%(inFile.name))[0] if len(retout)>0 and len(retout[0].split())>=4: handle = retout[0].split()[4] else: raise Exception("unable to process output of loadkey %s"%(retout)) return handle.upper()
def main(argv=sys.argv): if tpm_initialize.get_tpm_manufacturer() != 'IBM': raise Exception( "This stub should only be used with the IBM TPM emulator") # initialize position in ML pos = 0 # check if pcr is clean output = tpm_exec.run("pcrread -ix %s" % common.IMA_PCR)[0] pcrval = output[0].split()[5] if pcrval != ima.START_HASH.encode('hex'): print "Warning: IMA PCR is not empty, trying to find the last updated file in the measurement list..." pos = ml_extend(common.IMA_ML, 0, pcrval) print "Monitoring %s" % (common.IMA_ML) poll_object = select.poll() fd_object = file(common.IMA_ML, "r") number = fd_object.fileno() poll_object.register(fd_object, select.POLLIN | select.POLLPRI) while True: results = poll_object.poll() for result in results: if result[0] != number: continue pos = ml_extend(common.IMA_ML, pos) #print "new POS %d"%pos time.sleep(0.2) sys.exit(1)
def is_tpm_owned(): retout = tpm_exec.run("getcapability -cap 5 -scap 111")[0] tokens = retout[0].split() if tokens[-1]=='TRUE': return True else: return False
def get_tpm_manufacturer(): retout = tpm_exec.run("getcapability -cap 1a")[0] for line in retout: tokens = line.split() if len(tokens)== 3 and tokens[0]=='VendorID' and tokens[1]==':': #logger.debug("TPM vendor id: %s",tokens[2]) return tokens[2] return None
def get_pub_ek(): # assumes that owner_pw is correct at this point owner_pw = get_tpm_metadata('owner_pw') #make a temp file for the output with tempfile.NamedTemporaryFile() as tmppath: (output,code,ek) = tpm_exec.run("getpubek -pwdo %s -ok %s"%(owner_pw,tmppath.name),raiseOnError=False,outputpath=tmppath.name) # generates pubek.pem if code!=tpm_exec.EXIT_SUCESS: raise Exception("getpubek failed with code "+str(code)+": "+str(output)) set_tpm_metadata('ek',ek)
def ml_extend(ml, position, searchHash=None): f = open(ml, 'r') f.seek(position) rest = f.read() lines = rest.split('\n') runninghash = ima.START_HASH for line in lines: line = line.strip() tokens = line.split() if line == '': continue if len(tokens) < 5: print "ERROR: invalid measurement list file line: -%s-" % (line) return position # get the filename roughly path = str(line[line.rfind(tokens[3]) + len(tokens[3]) + 1:]) template_hash = tokens[1].decode('hex') # this is some IMA weirdness if template_hash == ima.START_HASH: template_hash = ima.FF_HASH template_hash = template_hash.encode('hex') if searchHash is None: print "extending hash %s for %s" % (template_hash, path) tpm_exec.run("extend -ix %s -ih %s" % (common.IMA_PCR, template_hash)) else: runninghash = hashlib.sha1(runninghash + template_hash.decode('hex')).digest() if runninghash.encode('hex') == searchHash: position = rest.index(line) + len(line) print "Located last IMA file updated: %s" % (path) return position if searchHash is not None: raise Exception( "Unable to find current measurement list position, Resetting the TPM emulator may be neccesary" ) return position + len(rest)
def test_ownerpw(owner_pw,reentry=False): #make a temp file for the output with tempfile.NamedTemporaryFile() as tmppath: (output,code,fileout) = tpm_exec.run("getpubek -pwdo %s -ok %s"%(owner_pw,tmppath.name),raiseOnError=False,outputpath=tmppath.name) if code!=tpm_exec.EXIT_SUCESS: if len(output)>0 and output[0].startswith("Error Authentication failed (Incorrect Password) from TPM_OwnerReadPubek"): return False elif len(output)>0 and output[0].startswith("Error Defend lock running from TPM_OwnerReadPubek"): if reentry: logger.error("Unable to unlock TPM") return False # tpm got locked. lets try to unlock it logger.error("TPM is locked from too many invalid owner password attempts, attempting to unlock with password: %s"%owner_pw) # i have no idea why, but runnig this twice seems to actually work tpm_exec.run("resetlockvalue -pwdo %s"%owner_pw,raiseOnError=False) tpm_exec.run("resetlockvalue -pwdo %s"%owner_pw,raiseOnError=False) return test_ownerpw(owner_pw,True) else: raise Exception("test ownerpw, getpubek failed with code "+str(code)+": "+str(output)) return True
def create_ek(): # this function is intended to be idempotent (output,code,fileout) = tpm_exec.run("createek",raiseOnError=False) if code!=tpm_exec.EXIT_SUCESS: if len(output)>0 and output[0].startswith("Error Target command disabled from TPM_CreateEndorsementKeyPair"): logger.debug("TPM EK already created.") elif len(output)>0 and output[0].startswith("Error Defend lock running from TPM_CreateEndorsementKeyPair"): logger.debug("createek failed. TPM locked, will attempt unlock during while taking ownership. To manually repair run resetlockvalue -pwdo [owner_password]") else: raise Exception("createek failed with code "+str(code)+": "+str(output)) return
def take_ownership(config_pw): owner_pw = get_tpm_metadata("owner_pw") ownerpw_known = False if not is_tpm_owned(): # if no ownerpassword if config_pw == 'generate': logger.info("Generating random TPM owner password") owner_pw = random_password(20, useTPM=True) else: logger.info( "Taking ownership with config provided TPM owner password: %s" % config_pw) owner_pw = config_pw logger.info("Taking ownership of TPM") tpm_exec.run("takeown -pwdo %s -nopubsrk" % owner_pw) ownerpw_known = True else: logger.debug("TPM ownership already taken") # tpm owner_pw still not known, and non provided? bail if owner_pw is None and config_pw == 'generate': raise Exception( "TPM is owned, but owner password has not been provided. Set config option tpm_ownerpassword to the existing password if known. If not know, TPM reset is required." ) # now we have owner_pw from tpmdata.json and a config_pw. if not ownerpw_known: if owner_pw is None or not test_ownerpw(owner_pw): logger.info( "Owner password: %s from tpmdata.json invalid. Trying config provided TPM owner password: %s" % (owner_pw, config_pw)) owner_pw = config_pw if not test_ownerpw(owner_pw): raise Exception( "Config provided owner password %s invalid. Set config option tpm_ownerpassword to the existing password if known. If not know, TPM reset is required." % owner_pw) if get_tpm_metadata('owner_pw') is not owner_pw: set_tpm_metadata('owner_pw', owner_pw)
def create_ek(): # this function is intended to be idempotent (output, code) = tpm_exec.run("createek", raiseOnError=False) if code != tpm_exec.EXIT_SUCESS and len( output ) > 0 and output[0].startswith( "Error Target command disabled from TPM_CreateEndorsementKeyPair"): logger.debug("TPM EK already created.") elif code != tpm_exec.EXIT_SUCESS: raise Exception("createek failed with code " + str(code) + ": " + str(output)) return
def create_quote(nonce,data=None,pcrmask=EMPTYMASK): # if not using TPM, just return a canned quote if common.STUB_TPM: time.sleep(common.TEST_CREATE_QUOTE_DELAY) return common.TEST_QUOTE quotepath = None try: keyhandle = tpm_initialize.load_aik() if pcrmask is None: pcrmask = EMPTYMASK with tpm_exec.tpmutilLock: if data is not None: # add PCR 16 to pcrmask pcrmask = "0x%X"%(int(pcrmask,0) + (1 << common.TPM_DATA_PCR)) tpm_exec.run("pcrreset -ix %d"%common.TPM_DATA_PCR,lock=False) tpm_exec.run("extend -ix %d -ic %s"%(common.TPM_DATA_PCR,hashlib.sha1(data).hexdigest()),lock=False) #make a temp file for the quote quotefd,quotepath = tempfile.mkstemp() tpm_exec.run("tpmquote -hk %s -bm %s -nonce %s -noverify -oq %s"%(keyhandle,pcrmask,nonce,quotepath),lock=False) # read in the quote f = open(quotepath,"rb") quote = base64.b64encode(f.read().encode("zlib")) f.close() os.close(quotefd) finally: if quotepath is not None: os.remove(quotepath) return quote
def write_key_nvram(key): if common.STUB_TPM: storage = open("tpm_nvram","wb") storage.write(key) storage.close() return owner_pw = tpm_initialize.get_tpm_metadata('owner_pw') keyFile = None try: # write out quote keyfd,keypath = tempfile.mkstemp() keyFile = open(keypath,"wb") keyFile.write(key) keyFile.close() os.close(keyfd) tpm_exec.run("nv_definespace -pwdo %s -in 1 -sz %d -pwdd %s -per 40004"%(owner_pw,common.BOOTSTRAP_KEY_SIZE,owner_pw)) tpm_exec.run("nv_writevalue -pwdd %s -in 1 -if %s"%(owner_pw,keyFile.name)) finally: if keyFile is not None: os.remove(keyFile.name) return
def check_quote(aikFile, quoteFile, extData): #print('Executing "%s"' % ("checkquote -aik %s -quote %s -nonce %s"%(aikFile, quoteFile, extData),)) if common.USE_CLIME: import _cLime retout = _cLime.checkquote('-aik', aikFile, '-quote', quoteFile, '-nonce', extData) retout = [line + '\n' for line in retout.split('\n')] # Try and be transparent to tpm_quote.py return retout else: retout = tpm_exec.run("checkquote -aik %s -quote %s -nonce %s" % (aikFile, quoteFile, extData))[0] return retout
def load_aik(): # is the key already there? modFromFile = get_tpm_metadata('aikmod') retout = tpm_exec.run("listkeys")[0] for line in retout: tokens = line.split() if len(tokens) == 4 and tokens[0] == 'Key' and tokens[1] == 'handle': handle = tokens[3] modFromTPM = get_mod_from_tpm(handle) if modFromTPM == modFromFile: #logger.debug("Located AIK at key handle %s"%handle) return handle # we didn't find the key logger.debug("Loading AIK private key into TPM") inFile = None try: # write out private key infd, intemp = tempfile.mkstemp() inFile = open(intemp, "wb") inFile.write(base64.b64decode(get_tpm_metadata('aikpriv'))) inFile.close() os.close(infd) retout = tpm_exec.run("loadkey -hp 40000000 -ik %s" % inFile.name)[0] if len(retout) > 0 and len(retout[0].split()) >= 4: handle = retout[0].split()[4] else: raise Exception("unable to process output of loadkey %s" % (retout)) finally: if inFile is not None: os.remove(inFile.name) return handle
def get_tpm_rand_block(): global warned randpath = None try: #make a temp file for the output randfd, randpath = tempfile.mkstemp() command = "getrandom -size %d -out %s" % (4096, randpath) tpm_exec.run(command) # read in the quote f = open(randpath, "rb") rand = f.read() f.close() os.close(randfd) except Exception as e: if not warned: logger.warn("WARNING: TPM randomness not available: %s" % e) warned = True return [] finally: if randpath is not None: os.remove(randpath) return rand
def get_mod_from_tpm(keyhandle): retout = tpm_exec.run("getpubkey -ha %s" % keyhandle)[0] # now to parse things! inMod = False public_modulus = [] for line in retout: if line.startswith("Modulus"): inMod = True continue if inMod: tokens = line.split() for token in tokens: public_modulus.append(string.atol(token, base=16)) return base64.b64encode(bytearray(public_modulus))
def create_aik(activate): # if no AIK created, then create one if get_tpm_metadata('aik') is not None and get_tpm_metadata( 'aikpriv') is not None and get_tpm_metadata('aikmod') is not None: logger.debug("AIK already created") return logger.debug("Creating a new AIK identity") extra = "" if activate: extra = "-ac" owner_pw = get_tpm_metadata('owner_pw') tmppath = None try: #make a temp file for the output tmppath = tempfile.mkstemp()[1] tpm_exec.run("identity -la aik -ok %s -pwdo %s %s" % (tmppath, owner_pw, extra)) # read in the output with open(tmppath + ".pem", "rb") as f: pem = f.read() mod = get_mod_from_pem(tmppath + '.pem') with open(tmppath + ".key", 'rb') as f: key = base64.b64encode(f.read()) finally: if tmppath is not None: os.remove(tmppath + ".pem") os.remove(tmppath + ".key") if activate: logger.debug("Self-activated AIK identity in test mode") # persist results set_tpm_metadata('aik', pem) set_tpm_metadata('aikpriv', key) set_tpm_metadata('aikmod', mod)
def get_tpm_rand_block(size=4096): global warned #make a temp file for the output rand = None with tempfile.NamedTemporaryFile() as randpath: try: command = "getrandom -size %d -out %s" % (size, randpath.name) (retout, code, rand) = tpm_exec.run(command, outputpath=randpath.name) except Exception as e: if not warned: logger.warn("TPM randomness not available: %s" % e) warned = True return [] return rand
def create_deep_quote(nonce, data=None, vpcrmask=EMPTYMASK, pcrmask=EMPTYMASK): quote = "" with tempfile.NamedTemporaryFile() as quotepath: # read in the vTPM key handle keyhandle = tpm_initialize.get_tpm_metadata('aik_handle') owner_pw = tpm_initialize.get_tpm_metadata('owner_pw') aik_pw = tpm_initialize.get_tpm_metadata('aik_pw') if pcrmask is None: pcrmask = EMPTYMASK if vpcrmask is None: vpcrmask = EMPTYMASK # need to hold the lock while we reset and extend the pcr and then do the quote with tpm_exec.tpmutilLock: if data is not None: # add PCR 16 to pcrmask vpcrmask = "0x%X" % (int(vpcrmask, 0) + (1 << common.TPM_DATA_PCR)) tpm_exec.run("pcrreset -ix %d" % common.TPM_DATA_PCR, lock=False) tpm_exec.run( "extend -ix %d -ic %s" % (common.TPM_DATA_PCR, hashlib.sha1(data).hexdigest()), lock=False) command = "deepquote -vk %s -hm %s -vm %s -nonce %s -pwdo %s -pwdk %s -oq %s" % ( keyhandle, pcrmask, vpcrmask, nonce, owner_pw, aik_pw, quotepath.name) #print("Executing %s"%(command)) (retout, code, quoteraw) = tpm_exec.run(command, lock=False, outputpath=quotepath.name) quote = base64.b64encode(quoteraw.encode("zlib")) return 'd' + quote
def get_mod_from_tpm(keyhandle): (retout,code,fileout) = tpm_exec.run("getpubkey -ha %s -pwdk %s"%(keyhandle,get_tpm_metadata('aik_pw')),raiseOnError=False) if code!=tpm_exec.EXIT_SUCESS and len(retout)>0 and retout[0].startswith("Error Authentication failed (Incorrect Password) from TPM_GetPubKey"): return None # now to parse things! inMod = False public_modulus = [] for line in retout: if line.startswith("Modulus"): inMod = True continue if inMod: tokens = line.split() for token in tokens: public_modulus.append(string.atol(token,base=16)) return base64.b64encode(bytearray(public_modulus))