Exemple #1
0
def change_process_owner(user):
    """ change the process owner to the given one """
    if not user.isnumeric():
        try:
            passwd = pwd.getpwnam(user)
        except KeyError:
            logerr(LOGFILE, "Error: User '%s' does not exist.\n" % user)
            return 1

        try:
            os.initgroups(passwd.pw_name, passwd.pw_gid)
        except PermissionError as err:
            logerr(LOGFILE, "Error: initgroups() failed: %s\n" % str(err))
            return 1
        gid = passwd.pw_gid
        uid = passwd.pw_uid
    else:
        if int(user) > 0xffffffff:
            logerr(LOGFILE, "Error: uid %s outside valid range.\n" % user)
        gid = int(user)
        uid = int(user)

    try:
        os.setgid(gid)
    except PermissionError as err:
        logerr(LOGFILE, "Error: setgid(%d) failed: %s\n" % (gid, str(err)))
        return 1

    try:
        os.setuid(uid)
    except PermissionError as err:
        logerr(LOGFILE, "Error: setuid(%d) failed: %s\n" % (uid, str(err)))
        return 1

    return 0
Exemple #2
0
def tpm_get_specs_and_attributes(swtpm):
    """ Get the TPM specification and attribute parameters """

    res, ret = swtpm.ctrl_get_tpm_specs_and_attrs()
    if ret != 0:
        logerr(LOGFILE,
               "Could not get the TPM spec and attribute parameters.\n")
        return [], 1

    res = res.replace(":00,", ":0,")  # needed for libtpms <= 0.7.x
    try:
        tpm_param = json.loads(res)
    except json.decoder.JSONDecodeError as err:
        logerr(
            LOGFILE, "Internal error: Could not parse '%s' as JSON: %s\n" %
            (res, str(err)))
        return [], 1

    params = [
        "--tpm-spec-family", tpm_param["TPMSpecification"]["family"],
        "--tpm-spec-level",
        str(tpm_param["TPMSpecification"]["level"]), "--tpm-spec-revision",
        str(tpm_param["TPMSpecification"]["revision"]), "--tpm-manufacturer",
        str(tpm_param["TPMAttributes"]["manufacturer"]), "--tpm-model",
        str(tpm_param["TPMAttributes"]["model"]), "--tpm-version",
        str(tpm_param["TPMAttributes"]["version"])
    ]
    return params, 0
Exemple #3
0
def tpm2_create_ek_and_cert(flags, config_file, certsdir, vmid, rsa_keysize, swtpm):
    """ Create either an RSA or ECC EK and certificate """

    if flags & SETUP_CREATE_EK_F:
        ekparam, ret = swtpm.create_ek(flags & SETUP_TPM2_ECC_F, rsa_keysize,
                                       flags & SETUP_ALLOW_SIGNING_F, flags & SETUP_DECRYPTION_F,
                                       flags & SETUP_LOCK_NVRAM_F)
        if ret != 0:
            return ret

    if flags & (SETUP_EK_CERT_F | SETUP_PLATFORM_CERT_F):
        ret = call_create_certs(flags, config_file, certsdir, ekparam, vmid, swtpm)
        if ret != 0:
            return ret

        for entry in [(SETUP_EK_CERT_F, "ek.cert"), (SETUP_PLATFORM_CERT_F, "platform.cert")]:
            if flags & entry[0]:
                certfile = os.path.join(certsdir, entry[1])
                data, ret = read_file(certfile)
                if ret != 0:
                    logerr(LOGFILE, "%s file could not be read\n" % certfile)
                    return ret
                if entry[0] == SETUP_EK_CERT_F:
                    ret = swtpm.write_ek_cert_nvram(flags & SETUP_TPM2_ECC_F, rsa_keysize,
                                                    flags & SETUP_LOCK_NVRAM_F, data)
                else:
                    ret = swtpm.write_platform_cert_nvram(flags & SETUP_LOCK_NVRAM_F, data)
                remove_file(certfile)
                if ret != 0:
                    return ret

    return 0
Exemple #4
0
def tpm12_create_certs(flags, config_file, certsdir, ekparam, vmid, swtpm):
    """ Create certificates for the TPM 1.2 and write them into NVRAM """
    ret = call_create_certs(flags, config_file, certsdir, ekparam, vmid, swtpm)
    if ret != 0:
        return 1

    for entry in [(SETUP_EK_CERT_F, "ek.cert"), (SETUP_PLATFORM_CERT_F, "platform.cert")]:
        if flags & entry[0]:
            certfile = os.path.join(certsdir, entry[1])
            data, ret = read_file(certfile)
            if ret != 0:
                logerr(LOGFILE, "%s file could not be read\n" % certfile)
                return 1
            if entry[0] == SETUP_EK_CERT_F:
                ret = swtpm.write_ek_cert_nvram(data)
                if ret == 0:
                    logit(LOGFILE, "Successfully created NVRAM area for EK certificate.\n")
            else:
                ret = swtpm.write_platform_cert_nvram(data)
                if ret == 0:
                    logit(LOGFILE, "Successfully created NVRAM area for Platform certificate.\n")
            remove_file(certfile)
            if ret != 0:
                return 1

    return 0
Exemple #5
0
    def write_ek_cert_nvram(self, isecc, rsa_keysize, lock_nvram, ekcert):
        """ Write the given ekcert into an NVRAM area appropriate for the key type and size """

        if not isecc:
            if rsa_keysize == 2048:
                nvindex = TPM2_NV_INDEX_RSA2048_EKCERT
            elif rsa_keysize == 3072:
                nvindex = TPM2_NV_INDEX_RSA3072_HI_EKCERT
            keytype = "RSA %d" % rsa_keysize
        else:
            nvindex = TPM2_NV_INDEX_ECC_SECP384R1_HI_EKCERT
            keytype = "ECC"

        nvindexattrs = TPMA_NV_PLATFORMCREATE | \
            TPMA_NV_AUTHREAD | \
            TPMA_NV_OWNERREAD | \
            TPMA_NV_PPREAD | \
            TPMA_NV_PPWRITE | \
            TPMA_NV_NO_DA | \
            TPMA_NV_WRITEDEFINE
        ret = self.write_nvram(nvindex, nvindexattrs, ekcert, lock_nvram,
                               "EK Certificate")
        if ret == 0:
            logit(
                self.logfile,
                "Successfully created NVRAM area 0x%x for %s EK certificate.\n"
                % (nvindex, keytype))
        else:
            logerr(
                self.logfile,
                "Could not create NVRAM area 0x%x for %s EK certificate.\n" %
                (nvindex, keytype))
        return ret
Exemple #6
0
def remove_file(filename):
    """ remove a file """
    try:
        os.remove(filename)
        return 0
    except Exception as err:
        logerr(LOGFILE, "Could not remove file %s: %s\n" % \
               (filename, str(err)))
        return 1
Exemple #7
0
    def set_active_pcr_banks(self, pcr_banks, all_pcr_banks):
        """ Set the list of active PCR banks to the one the user wants """

        pcrselects = "".encode()
        count = 0
        active = []

        # enable the ones the user wants
        for pcr_bank in pcr_banks:
            if pcr_bank not in all_pcr_banks:
                # Skip if not even available
                continue
            try:
                hashalg = BANK_NAMES_TO_ALGID[pcr_bank]
            except KeyError:
                continue

            active.insert(0, pcr_bank)
            pcrselects += struct.pack('>H BBBB', hashalg, 3, 0xff, 0xff, 0xff)

            #print("activate hashalg = %d\n" % hashalg)
            count += 1

        if len(active) == 0:
            logerr(
                self.logfile,
                "No PCR banks could be allocated. None of the selected algorithms are "
                "supported.\n")
            return [], 1

        # disable the rest
        for pcr_bank in all_pcr_banks:
            if pcr_bank in pcr_banks:
                # Skip if to activate
                continue

            try:
                hashalg = BANK_NAMES_TO_ALGID[pcr_bank]
            except KeyError:
                continue

            #print("deactivate hashalg = %d\n" % hashalg)
            pcrselects += struct.pack('>H BBBB', hashalg, 3, 0, 0, 0)
            count += 1

        authblock = struct.pack('>I HBH', TPM2_RS_PW, 0, 0, 0)
        fmt = '>HII I I%ds I %ds' % (len(authblock), len(pcrselects))
        req = struct.pack(fmt, TPM2_ST_SESSIONS, struct.calcsize(fmt),
                          TPM2_CC_PCR_ALLOCATE, TPM2_RH_PLATFORM,
                          len(authblock), authblock, count, pcrselects)

        _, ret = self.transfer(req, "TPM2_PCR_Allocate")

        return active, ret
Exemple #8
0
def read_file(filename):
    """ read contents from a file """
    try:
        fobj = open(filename, mode='rb')
        result = fobj.read()
        fobj.close()
        return result, 0
    except Exception as err:
        logerr(LOGFILE, "Could not read from file %s: %s\n" % \
               (filename, str(err)))
        return "", 1
Exemple #9
0
def read_file_lines(filename):
    """ Read the lines from a file and return a list of the lines """
    try:
        fobj = open(filename, 'r')
        lines = fobj.readlines()
        fobj.close()
        return lines, 0
    except Exception as err:
        logerr(LOGFILE, "Could not access %s to get name of certificate tool "
               "to invoke: %s\n" % (filename, str(err)))
        return [], 1
Exemple #10
0
def delete_state(flags, tpm_state_path):
    """ Delete the TPM's state file """
    if flags & SETUP_TPM2_F:
        statefile = "tpm2-00.permall"
    else:
        statefile = "tpm-00.permall"

    filepath = os.path.join(tpm_state_path, statefile)
    try:
        os.unlink(os.path.join(tpm_state_path, statefile))
    except Exception as err:
        logerr(LOGFILE, "Could not remove state file %s: %s\n" % \
               (filepath, str(err)))
Exemple #11
0
    def create_ek(self, isecc, rsa_keysize, allowsigning, decryption,
                  lock_nvram):
        """ Create an ECC or RSA EK """

        if isecc:
            tpm2_ek_handle = TPM2_EK_ECC_SECP384R1_HANDLE
            keytype = "ECC"
            nvindex = TPM2_NV_INDEX_ECC_SECP384R1_HI_EKTEMPLATE
        else:
            if rsa_keysize == 2048:
                tpm2_ek_handle = TPM2_EK_RSA_HANDLE
                nvindex = TPM2_NV_INDEX_RSA2048_EKTEMPLATE
            elif rsa_keysize == 3072:
                tpm2_ek_handle = TPM2_EK_RSA3072_HANDLE
                nvindex = TPM2_NV_INDEX_RSA3072_HI_EKTEMPLATE
            keytype = "RSA %d" % rsa_keysize

        if isecc:
            ek_template, ekparam, handle, ret = \
                self.createprimary_ek_ecc_nist_p384(allowsigning, decryption)
        else:
            ek_template, ekparam, handle, ret = \
                self.createprimary_ek_rsa(rsa_keysize, allowsigning, decryption)

        if ret == 0:
            ret = self.evictcontrol(handle, tpm2_ek_handle)
        if ret != 0:
            logerr(self.logfile, "create_ek failed\n")
            return "", 1

        logit(
            self.logfile, "Successfully created %s EK with handle 0x%x.\n" %
            (keytype, tpm2_ek_handle))

        if allowsigning:
            nvindexattrs = TPMA_NV_PLATFORMCREATE | \
  TPMA_NV_AUTHREAD | \
  TPMA_NV_OWNERREAD | \
  TPMA_NV_PPREAD | \
  TPMA_NV_PPWRITE | \
  TPMA_NV_NO_DA | \
  TPMA_NV_WRITEDEFINE
            ret = self.write_nvram(nvindex, nvindexattrs, ek_template,
                                   lock_nvram, "EK template")
            if ret == 0:
                logit(
                    self.logfile,
                    "Successfully created NVRAM area 0x%x for %s EK template.\n"
                    % (nvindex, keytype))

        return ekparam, ret
Exemple #12
0
    def _createprimary_ecc(self, primaryhandle, keyflags, symkeydata,
                           authpolicy, curveid, hashalg, nonce, off):
        """ Create an ECC key with the given parameters """

        authblock = struct.pack('>IHBH', TPM2_RS_PW, 0, 0, 0)

        fmt = '>HHI H%ds %ds HH H %ds%ds' % \
              (len(authpolicy), len(symkeydata), len(nonce), len(nonce))
        public = struct.pack(fmt, TPM2_ALG_ECC, hashalg, keyflags,
                             len(authpolicy), authpolicy, symkeydata,
                             TPM2_ALG_NULL, curveid, TPM2_ALG_NULL, nonce,
                             nonce)
        ek_template = public

        fmt = '>HII I I%ds HI H%ds IH' % (len(authblock), len(public))
        req = struct.pack(fmt, TPM2_ST_SESSIONS, struct.calcsize(fmt),
                          TPM2_CC_CREATEPRIMARY, primaryhandle, len(authblock),
                          authblock, 4, 0, len(public), public, 0, 0)
        rsp, ret = self.transfer(req, "TPM2_CreatePrimary")
        if ret != 0:
            return b'', "", 0, 1

        handle = struct.unpack('>I', rsp[10:14])[0]

        if curveid == TPM2_ECC_NIST_P384:
            exp_ksize = 48
            cid = "secp384r1"
        else:
            logerr(self.logfile, "Unknown curveid 0x%x\n" % curveid)
            return b'', "", 0, 1

        ksize1 = struct.unpack('>H', rsp[off:off + 2])[0]
        off2 = off + 2 + ksize1
        ksize2 = struct.unpack('>H', rsp[off2:off2 + 2])[0]

        if ksize1 != exp_ksize or ksize2 != exp_ksize:
            logerr(self.logfile,
                   "ECC: Getting key parameters from wrong offset\n")
            return b'', "", 0, 1

        off += 2
        xparam = struct.unpack(">%ds" % ksize1, rsp[off:off + ksize1])[0]
        off2 += 2
        yparam = struct.unpack(">%ds" % ksize2, rsp[off2:off2 + ksize2])[0]

        ekparam = "x=%s,y=%s,id=%s" % (xparam.hex(), yparam.hex(), cid)

        return ek_template, ekparam, handle, 0
Exemple #13
0
def check_state_overwrite(flags, tpm_state_path):
    """ Check whether we are allowed to overwrite existing state """
    if flags & SETUP_TPM2_F:
        statefile = "tpm2-00.permall"
    else:
        statefile = "tpm-00.permall"

    if os.access(os.path.join(tpm_state_path, statefile), os.R_OK|os.W_OK):
        if flags & SETUP_STATE_NOT_OVERWRITE_F:
            logit(LOGFILE, "Not overwriting existing state file.\n")
            return 2
        if flags & SETUP_STATE_OVERWRITE_F:
            return 0
        logerr(LOGFILE, "Found existing TPM state file %s.\n" % statefile)
        return 1

    return 0
Exemple #14
0
    def _createprimary_rsa(self, primaryhandle, keyflags, symkeydata,
                           authpolicy, rsa_keysize, havenonce, off):
        """ Create an RSA key with the given parameters """

        if rsa_keysize == 2048:
            nonce = NONCE_RSA2048
            hashalg = TPM2_ALG_SHA256
        elif rsa_keysize == 3072:
            if not havenonce:
                nonce = NONCE_EMPTY
            else:
                nonce = NONCE_RSA3072
            hashalg = TPM2_ALG_SHA384
        else:
            logerr(self.logfile, "Unsupported keysize %d\n" % rsa_keysize)
            return b'', "", 0, 1

        authblock = struct.pack('>IHBH', TPM2_RS_PW, 0, 0, 0)

        fmt = '>HHI H%ds %ds HH I %ds' % \
              (len(authpolicy), len(symkeydata), len(nonce))
        public = struct.pack(fmt, TPM2_ALG_RSA, hashalg, keyflags,
                             len(authpolicy), authpolicy, symkeydata,
                             TPM2_ALG_NULL, rsa_keysize, 0, nonce)
        ek_template = public

        fmt = ">HII I I%ds HI H%ds IH" % (len(authblock), len(public))
        req = struct.pack(fmt, TPM2_ST_SESSIONS, struct.calcsize(fmt),
                          TPM2_CC_CREATEPRIMARY, primaryhandle, len(authblock),
                          authblock, 4, 0, len(public), public, 0, 0)
        rsp, ret = self.transfer(req, "TPM2_CreatePrimary")
        if ret != 0:
            return b'', "", 0, 1

        handle = struct.unpack(">I", rsp[10:14])[0]

        modlen = struct.unpack(">H", rsp[off:off + 2])[0]
        if modlen != rsa_keysize >> 3:
            logerr(self.logfile,
                   "RSA key: Getting modulus from wrong offset %d\n" % off)
            return b'', "", 0, 1
        off += 2
        ekparam = struct.unpack(">%ds" % modlen,
                                rsp[off:off + modlen])[0].hex()

        return ek_template, ekparam, handle, 0
Exemple #15
0
    def create_endorsement_key_pair(self):
        """ Create an endorsement key for the TPM 1.2 """

        req = b'\x00\xc1\x00\x00\x00\x36\x00\x00\x00\x78\x38\xf0\x30\x81\x07\x2b' \
        b'\x0c\xa9\x10\x98\x08\xc0\x4B\x05\x11\xc9\x50\x23\x52\xc4\x00\x00' \
        b'\x00\x01\x00\x03\x00\x02\x00\x00\x00\x0c\x00\x00\x08\x00\x00\x00' \
        b'\x00\x02\x00\x00\x00\x00'

        rsp, ret = self.transfer(req, "TPM_CreateEndorsementKeyPair")
        if ret != 0:
            return b'', 1

        length = struct.unpack(">I", rsp[34:38])[0]
        if length != 256:
            logerr(self.logfile, "Offset to EK Public key is wrong.\n")
            return b'', 1

        pubek = struct.unpack("256s", rsp[38:38 + 256])[0]

        return pubek, 0
Exemple #16
0
    def transfer(self, req, cmdname, use_ctrl=False):
        """ Send a command to swtpm and receive a response """

        if use_ctrl:
            sock = self.ctrl_client_socket
            offset = 0
        else:
            sock = self.data_client_socket
            offset = 6

        try:
            sock.sendall(req)
            rsp = sock.recv(4096)
        except Exception as err:
            logerr(self.logfile, "transfer error: %s\n" % str(err))
            return None, 1

        if not use_ctrl:
            if len(rsp) < 10:
                logerr(
                    self.logfile, "Response for %s has only %d bytes.\n" %
                    (cmdname, len(rsp)))
                return None, 1

        returncode = struct.unpack(">I", rsp[offset:offset + 4])[0]
        if returncode != 0:
            logerr(self.logfile, "%s failed: 0x%x\n" % (cmdname, returncode))
            return None, 1

        return rsp, 0
Exemple #17
0
def get_rsa_keysizes(flags, swtpm_prg_l):
    """ Get the support RSA key sizes
        @return This function returns a list of ints like the following
        - [ 1024, 2048, 3072 ]
        - [] (empty list, indicating only 2048 bit RSA keys are supported)
    """
    res = []

    if flags & SETUP_TPM2_F:
        cmdarray = swtpm_prg_l.copy()
        cmdarray.extend(["--tpm2", "--print-capabilities"])
        try:
            process = subprocess.Popen(cmdarray, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            stdout, _ = process.communicate()
            try:
                instr = stdout.decode()
                j = json.loads(instr)
                for entry in j["features"]:
                    if entry.startswith("rsa-keysize-"):
                        try:
                            res.append(int(entry[12:]))
                        except ValueError as err:
                            logerr(LOGFILE, "Internal error: Could not parse '%s' as int: %s\n" %
                                   (entry[12:], str(err)))
                            return [], 1
            except json.decoder.JSONDecodeError as err:
                logerr(LOGFILE, "Internal error: Could not parse '%s' as JSON: %s\n" %
                       (instr, str(err)))
                return [], 1
        except Exception as err:
            logerr(LOGFILE, "Could not start swtpm '%s': %s\n" % (" ".join(swtpm_prg_l), str(err)))
            return res, 1

    return res, 0
Exemple #18
0
    def write_nvram(self, nvindex, nvindexattrs, data, lock_nvram, purpose):
        """ Define NVRAM space, write data to it and lock it if wanted """

        ret = self.nv_definespace(nvindex, nvindexattrs, len(data))
        if ret != 0:
            logerr(
                self.logfile, "Could not create NVRAM area 0x%x for %s.\n" %
                (nvindex, purpose))
            return 1

        ret = self.nv_write(nvindex, data)
        if ret != 0:
            logerr(
                self.logfile, "Could not write %s into NVRAM area 0x%x.\n" %
                (purpose, nvindex))
            return 1

        if lock_nvram:
            ret = self.nv_writelock(nvindex)
            if ret != 0:
                logerr(
                    self.logfile,
                    "Could not lock EK template NVRAM area 0x%x.\n" % nvindex)
                return 1

        return ret
Exemple #19
0
def init_tpm(flags, swtpm_prg_l, config_file, tpm_state_path, ownerpass,
             srkpass, vmid, swtpm_keyopt, fds_to_pass):
    """ Initialize a TPM 1.2: create keys and certificate and take ownership """
    certsdir = tpm_state_path

    swtpm = Swtpm12(swtpm_prg_l.copy(), tpm_state_path, swtpm_keyopt, LOGFILE,
                    fds_to_pass)

    ret = swtpm.start()
    if ret != 0:
        logerr(LOGFILE, "Could not start the TPM 2.\n")
        return 1
    # We will have to call swtpm.destroy() at the end

    if ret == 0:
        ret = swtpm.run_swtpm_bios()

    if ret == 0 and flags & SETUP_CREATE_EK_F:
        pubek, ret = swtpm.create_endorsement_key_pair()
        if ret == 0:
            logit(LOGFILE, "Successfully created EK.\n")

    if ret == 0 and flags & SETUP_TAKEOWN_F:
        ret = tpm12_take_ownership(flags, ownerpass, srkpass, pubek, swtpm)
        if ret == 0:
            logit(LOGFILE, "Successfully took ownership of the TPM.\n")

    if ret == 0 and flags & SETUP_EK_CERT_F:
        ekparam = pubek.hex()
        ret = tpm12_create_certs(flags, config_file, certsdir, ekparam, vmid,
                                 swtpm)

    if ret == 0 and flags & SETUP_LOCK_NVRAM_F:
        ret = swtpm.nv_lock()
        if ret == 0:
            logit(LOGFILE, "Successfully locked NVRAM access.\n")

    swtpm.destroy()

    return ret
Exemple #20
0
def init_tpm2(flags, swtpm_prg_l, config_file, tpm2_state_path, vmid,
              pcr_banks, swtpm_keyopt, fds_to_pass, rsa_keysize):
    """ Initialize a TPM 2.0: create keys and certificate """
    certsdir = tpm2_state_path

    swtpm = Swtpm2(swtpm_prg_l.copy(), tpm2_state_path, swtpm_keyopt, LOGFILE,
                   fds_to_pass)

    ret = swtpm.start()
    if ret != 0:
        logerr(LOGFILE, "Could not start the TPM 2.\n")
        return 1

    if ret == 0:
        ret = swtpm.run_swtpm_bios()

    if ret == 0 and flags & SETUP_CREATE_SPK_F:
        ret = swtpm.create_spk(flags & SETUP_TPM2_ECC_F, rsa_keysize)

    if ret == 0:
        ret = tpm2_create_eks_and_certs(flags, config_file, certsdir, vmid,
                                        rsa_keysize, swtpm)

    if ret == 0 and pcr_banks != "-":
        all_pcr_banks, ret = swtpm.get_all_pcr_banks()
        if ret == 0:
            active_pcr_banks, ret = swtpm.set_active_pcr_banks(
                pcr_banks.split(","), all_pcr_banks)
        if ret == 0:
            logit(
                LOGFILE, "Successfully activated PCR banks %s among %s.\n" %
                (",".join(active_pcr_banks), ",".join(all_pcr_banks)))

    if ret == 0:
        swtpm.shutdown()

    swtpm.destroy()

    return ret
Exemple #21
0
    def createprimary_ek_ecc_nist_p384(self, allowsigning, decryption):
        """ Create en ECC EK key that may be allowed to sign and/or decrypt """

        if allowsigning and decryption:
            # keyflags: fixedTPM, fixedParent, sensitiveDatOrigin,
            # userWithAuth, adminWithPolicy, sign, decrypt
            keyflags = 0x000600f2
            # symmetric: TPM_ALG_NULL
            symkeydata = struct.pack(">H", TPM2_ALG_NULL)
            off = 86
        elif allowsigning:
            # keyflags: fixedTPM, fixedParent, sensitiveDatOrigin,
            # userWithAuth, adminWithPolicy, sign
            keyflags = 0x000400f2
            # symmetric: TPM_ALG_NULL
            symkeydata = struct.pack(">H", TPM2_ALG_NULL)
            off = 86
        else:
            # keyflags: fixedTPM, fixedParent, sensitiveDatOrigin,
            # userWithAuth, adminWithPolicy, restricted, decrypt
            keyflags = 0x000300f2
            # symmetric: TPM_ALG_AES, 256bit, TPM_ALG_CFB
            symkeydata = struct.pack(">HHH", TPM2_ALG_AES, 256, TPM2_ALG_CFB)
            off = 90

# authPolicy from Ek Credential Profile; Spec v 2.1; rev12; p. 43
        authpolicy = b'\xB2\x6E\x7D\x28\xD1\x1A\x50\xBC\x53\xD8\x82\xBC' \
        b'\xF5\xFD\x3A\x1A\x07\x41\x48\xBB\x35\xD3\xB4\xE4' \
        b'\xCB\x1C\x0A\xD9\xBD\xE4\x19\xCA\xCB\x47\xBA\x09' \
        b'\x69\x96\x46\x15\x0F\x9F\xC0\x00\xF3\xF8\x0E\x12'

        ek_template, ekparam, handle, ret = \
            self._createprimary_ecc(TPM2_RH_ENDORSEMENT, keyflags, symkeydata, authpolicy,
                                    TPM2_ECC_NIST_P384, TPM2_ALG_SHA384, NONCE_EMPTY, off)
        if ret != 0:
            logerr(self.logfile, "create_spk_ecc failed\n")

        return ek_template, ekparam, handle, ret
Exemple #22
0
    def write_platform_cert_nvram(self, lock_nvram, platformcert):
        """ Write the platform certificate into an NVRAM area """

        nvindex = TPM2_NV_INDEX_PLATFORMCERT
        nvindexattrs = TPMA_NV_PLATFORMCREATE | \
            TPMA_NV_AUTHREAD | \
            TPMA_NV_OWNERREAD | \
            TPMA_NV_PPREAD | \
            TPMA_NV_PPWRITE | \
            TPMA_NV_NO_DA | \
            TPMA_NV_WRITEDEFINE
        ret = self.write_nvram(nvindex, nvindexattrs, platformcert, lock_nvram,
                               "Platform Certificate")
        if ret == 0:
            logit(
                self.logfile,
                "Successfully created NVRAM area 0x%x for platform certificate.\n"
                % nvindex)
        else:
            logerr(
                self.logfile,
                "Could not create NVRAM area 0x%x for platform certificate.\n"
                % nvindex)
        return ret
Exemple #23
0
def call_create_certs(flags, config_file, certsdir, ekparam, vmid, swtpm):
    """ Call an external tool to create the certificates """

    params, ret = tpm_get_specs_and_attributes(swtpm)
    if ret != 0:
        return 1

    lines, ret = read_file_lines(config_file)
    if ret != 0:
        return ret

    create_certs_tool = get_config_value(lines, "create_certs_tool")
    create_certs_tool_config = get_config_value(lines, "create_certs_tool_config")
    create_certs_tool_options = get_config_value(lines, "create_certs_tool_options")

    ret = 0

    if create_certs_tool:
        ret = 1
        if flags & SETUP_TPM2_F:
            params.extend(["--tpm2"])

        cmd = [create_certs_tool,
               "--type", "_",
               "--ek", ekparam,
               "--dir", certsdir]
        if len(LOGFILE) > 0:
            cmd.extend(["--logfile", LOGFILE])
        if len(vmid) > 0:
            cmd.extend(["--vmid", vmid])
        cmd.extend(params)
        if create_certs_tool_config:
            cmd.extend(["--configfile", create_certs_tool_config])
        if create_certs_tool_options:
            cmd.extend(["--optsfile", create_certs_tool_options])

        try:
            i = create_certs_tool.rindex(os.sep)
            prgname = create_certs_tool[i + 1:]
        except ValueError:
            prgname = create_certs_tool

        for entry in [(SETUP_EK_CERT_F, "ek"), (SETUP_PLATFORM_CERT_F, "platform")]:
            if flags & entry[0]:
                try:
                    cmd[2] = entry[1]
                    logit(LOGFILE, "  Invoking %s\n" % (" ".join(cmd)))
                    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
                    stdout, _ = proc.communicate(timeout=30)
                    for line in stdout.decode().split("\n"):
                        if len(line) > 0:
                            logit(LOGFILE, "%s: %s\n" % (prgname, line))
                    ret = proc.returncode
                    if ret != 0:
                        logerr(LOGFILE, "Error returned from command\n")
                        return 1
                except FileNotFoundError as err:
                    logerr(LOGFILE, "Could not execute %s: %s\n" % (create_certs_tool, str(err)))
                    return 1
                except subprocess.TimeoutExpired as err:
                    logerr(LOGFILE, "%s did not finish in time: %s\n" %
                           (create_certs_tool, str(err)))
                    return 1
                except Exception as err:
                    logerr(LOGFILE, "An error occurred running %s: %s\n" %
                           (create_certs_tool, str(err)))

    return ret
Exemple #24
0
def main():
    """ main function - parses command line parameters and low level dealing with them """
    global LOGFILE # pylint: disable=W0603

    swtpm_prg = distutils.spawn.find_executable("swtpm")
    if swtpm_prg:
        swtpm_prg += " socket"

    try:
        opts, _ = getopt.getopt(sys.argv[1:], "h?",
                                ["tpm-state=", "tpmstate=",
                                 "tpm=",
                                 "swtpm_ioctl=",
                                 "tpm2",
                                 "ecc",
                                 "createek",
                                 "create-spk",
                                 "take-ownership",
                                 "ownerpass="******"owner-well-known",
                                 "srkpass="******"srk-well-known",
                                 "create-ek-cert",
                                 "create-platform-cert",
                                 "lock-nvram",
                                 "display",
                                 "config=",
                                 "vmid=",
                                 "keyfile=",
                                 "keyfile-fd=",
                                 "pwdfile=",
                                 "pwdfile-fd=",
                                 "cipher=",
                                 "runas=",
                                 "logfile=",
                                 "overwrite",
                                 "not-overwrite",
                                 "allow-signing",
                                 "decryption",
                                 "pcr-banks=",
                                 "rsa-keysize=",
                                 "tcsd-system-ps-file",
                                 "version",
                                 "print-capabilities",
                                 "help"])
    except getopt.GetoptError as err:
        print(err)
        usage(sys.argv[0])
        sys.exit(1)

    flags = 0
    tpm_state_path = ""
    config_file = DEFAULT_CONFIG_FILE
    ownerpass = None
    got_ownerpass = False
    srkpass = None
    got_srkpass = False
    vmid = ""
    pcr_banks = ""
    printcapabilities = False
    keyfile = ""
    keyfile_fd = ""
    pwdfile = ""
    pwdfile_fd = ""
    cipher = "aes-128-cbc"
    rsa_keysize_str = "%d" % DEFAULT_RSA_KEYSIZE
    swtpm_keyopt = ""
    fds_to_pass = []
    runas = ""

    for opt, arg in opts:
        if opt in ['--tpm-state', '--tpmstate']:
            tpm_state_path = arg
        elif opt == '--tpm':
            swtpm_prg = arg
        elif opt == '--swtpm_ioctl':
            print("Warning: --swtpm_ioctl is deprecated and has no effect.")
        elif opt == '--tpm2':
            flags |= SETUP_TPM2_F
        elif opt == '--ecc':
            flags |= SETUP_TPM2_ECC_F
        elif opt == '--createek':
            flags |= SETUP_CREATE_EK_F
        elif opt == '--create-spk':
            flags |= SETUP_CREATE_SPK_F
        elif opt == '--take-ownership':
            flags |= SETUP_CREATE_EK_F | SETUP_TAKEOWN_F
        elif opt == '--ownerpass':
            ownerpass = arg
            got_ownerpass = True
        elif opt == '--owner-well-known':
            flags |= SETUP_OWNERPASS_ZEROS_F
        elif opt == '--srkpass':
            srkpass = arg
            got_srkpass = True
        elif opt == '--srk-well-known':
            flags |= SETUP_SRKPASS_ZEROS_F
        elif opt == '--create-ek-cert':
            flags |= SETUP_CREATE_EK_F | SETUP_EK_CERT_F
        elif opt == '--create-platform-cert':
            flags |= SETUP_CREATE_EK_F | SETUP_PLATFORM_CERT_F
        elif opt == '--lock-nvram':
            flags |= SETUP_LOCK_NVRAM_F
        elif opt == '--display':
            flags |= SETUP_DISPLAY_RESULTS_F
        elif opt == '--config':
            config_file = arg
        elif opt == '--vmid':
            vmid = arg
        elif opt == '--keyfile':
            keyfile = arg
        elif opt == '--keyfile-fd':
            keyfile_fd = arg
        elif opt == '--pwdfile':
            pwdfile = arg
        elif opt == '--pwdfile-fd':
            pwdfile_fd = arg
        elif opt == '--cipher':
            cipher = arg
        elif opt == '--runas':
            runas = arg
        elif opt == '--logfile':
            LOGFILE = arg
        elif opt == '--overwrite':
            flags |= SETUP_STATE_OVERWRITE_F
        elif opt == '--not-overwrite':
            flags |= SETUP_STATE_NOT_OVERWRITE_F
        elif opt == '--allow-signing':
            flags |= SETUP_ALLOW_SIGNING_F
        elif opt == '--decryption':
            flags |= SETUP_DECRYPTION_F
        elif opt == '--pcr-banks':
            pcr_banks = pcr_banks + "," + arg
        elif opt == '--rsa-keysize':
            rsa_keysize_str = arg
        elif opt == '--tcsd-system-ps-file':
            print("Warning: --tcsd-system-ps-file is deprecated and has no effect.")
        elif opt == '--version':
            versioninfo()
            sys.exit(0)
        elif opt == '--print-capabilities':
            printcapabilities = True
        elif opt in ['--help', '-h', '-?']:
            usage(sys.argv[0])
            sys.exit(0)
        else:
            sys.stderr.write("Unknown option %s\n" % opt)
            usage(sys.argv[0])
            sys.exit(1)

    if not swtpm_prg:
        logerr(LOGFILE,
               "Default TPM 'swtpm' could not be found and was not provided using --tpm\n.")
        sys.exit(1)
    swtpm_prg_l = swtpm_prg.split()
    if not distutils.spawn.find_executable(swtpm_prg_l[0]):
        logerr(LOGFILE, "TPM at %s is not an executable.\n" % (" ".join(swtpm_prg_l)))
        sys.exit(1)

    if printcapabilities:
        ret = print_capabilities(swtpm_prg_l)
        sys.exit(ret)

    if runas:
        ret = change_process_owner(runas)
        if ret != 0:
            sys.exit(1)

    if not got_ownerpass:
        flags |= SETUP_OWNERPASS_ZEROS_F
    if not got_srkpass:
        flags |= SETUP_SRKPASS_ZEROS_F

    # sequeeze ',' and remove leading and trailing ','
    pcr_banks = re.sub(r',$', '',
                       re.sub(r'^,', '',
                              re.sub(r',,+', ',', pcr_banks)))
    if len(pcr_banks) == 0:
        pcr_banks = DEFAULT_PCR_BANKS

    # set owner password to default if user didn't provide any password wish
    # and wants to take ownership
    if flags & SETUP_TAKEOWN_F and \
        flags & SETUP_OWNERPASS_ZEROS_F and \
        not got_srkpass:
        srkpass = DEFAULT_SRK_PASSWORD

    if len(LOGFILE) > 0:
        if os.path.islink(LOGFILE):
            sys.stderr.write("Logfile must not be a symlink.\n")
            sys.exit(1)
        try:
            fobj = open(LOGFILE, "a") # do not truncate
            fobj.close()
        except PermissionError:
            sys.stderr.write("Cannot write to logfile %s.\n", LOGFILE)
            sys.exit(1)

    # Check tpm_state_path directory and access rights
    if len(tpm_state_path) == 0:
        logerr(LOGFILE, "--tpm-state must be provided\n")
        sys.exit(1)
    if not os.path.isdir(tpm_state_path):
        logerr(LOGFILE,
               "User %s cannot access directory %s. Make sure it exists and is a directory.\n" %
               (getpass.getuser(), tpm_state_path))
        sys.exit(1)
    if not os.access(tpm_state_path, os.R_OK):
        logerr(LOGFILE, "Need read rights on directory %s for user %s.\n" %
               (tpm_state_path, getpass.getuser()))
        sys.exit(1)
    if not os.access(tpm_state_path, os.W_OK):
        logerr(LOGFILE, "Need write rights on directory %s for user %s.\n" %
               (tpm_state_path, getpass.getuser()))
        sys.exit(1)

    if flags & SETUP_TPM2_F:
        if flags & SETUP_TAKEOWN_F:
            logerr(LOGFILE, "Taking ownership is not supported for TPM 2.\n")
            sys.exit(1)
    else:
        if flags & SETUP_TPM2_ECC_F:
            logerr(LOGFILE, "--ecc requires --tpm2.\n")
            sys.exit(1)
        if flags & SETUP_CREATE_SPK_F:
            logerr(LOGFILE, "--create-spk requires --tpm2.\n")
            sys.exit(1)

    ret = check_state_overwrite(flags, tpm_state_path)
    if ret == 1:
        sys.exit(1)
    elif ret == 2:
        sys.exit(0)

    files = glob.glob(os.path.join(tpm_state_path, "*permall"))
    files.extend(glob.glob(os.path.join(tpm_state_path, "*volatilestate")))
    files.extend(glob.glob(os.path.join(tpm_state_path, "*savestate")))

    try:
        for fil in files:
            os.remove(fil)
    except Exception as err:
        logerr(LOGFILE, "Could not remove previous state files. Need execute access rights on the "
               "directory %s.\n" % tpm_state_path)
        sys.exit(1)

    lockfile = os.path.join(tpm_state_path, ".lock")
    if os.path.exists(lockfile) and not os.access(lockfile, os.W_OK | os.R_OK):
        logerr(LOGFILE, "User %s cannot read/write %s.\n" % (getpass.getuser(), lockfile))
        sys.exit(1)

    if not os.access(config_file, os.R_OK):
        logerr(LOGFILE, "User %s cannot read %s.\n" % (getpass.getuser(), config_file))
        sys.exit(1)

    if len(cipher) > 0:
        if cipher not in ['aes-128-cbc', 'aes-cbc', 'aes-256-cbc']:
            logerr(LOGFILE, "Unsupported cipher %s.\n" % cipher)
            sys.exit(1)
        cipher = ",mode=%s" % cipher

    if len(keyfile) > 0:
        if not os.access(keyfile, os.R_OK):
            logerr(LOGFILE, "User %s cannot read keyfile %s.\n" % (getpass.getuser(), keyfile))
            sys.exit(1)
        swtpm_keyopt = "file=%s%s" % (keyfile, cipher)
        logit(LOGFILE, "  The TPM's state will be encrypted with a provided key.\n")
    elif len(pwdfile) > 0:
        if not os.access(pwdfile, os.R_OK):
            logerr(LOGFILE, "User %s canot read passphrase file %s.\n" % \
                   (getpass.getuser(), keyfile))
            sys.exit(1)
        swtpm_keyopt = "pwdfile=%s%s" % (pwdfile, cipher)
        logit(LOGFILE,
              "  The TPM's state will be encrypted using a key derived from a passphrase.\n")
    elif len(keyfile_fd) > 0:
        if not keyfile_fd.isnumeric():
            logerr(LOGFILE,
                   "--keyfile-fd parameter $keyfile_fd is not a valid file descriptor.\n")
            sys.exit(1)
        fds_to_pass.append(int(keyfile_fd))
        swtpm_keyopt = "fd=%s%s" % (keyfile_fd, cipher)
        logit(LOGFILE,
              "  The TPM's state will be encrypted with a provided key (fd).\n")
    elif len(pwdfile_fd) > 0:
        if not pwdfile_fd.isnumeric():
            logerr(LOGFILE,
                   "--pwdfile-fd parameter $pwdfile_fd is not a valid file descriptor.\n")
            sys.exit(1)
        fds_to_pass.append(int(pwdfile_fd))
        swtpm_keyopt = "pwdfd=%s%s" % (pwdfile_fd, cipher)
        logit(LOGFILE,
              "  The TPM's state will be encrypted using a key derived from a passphrase (fd).\n")

    if rsa_keysize_str == "max":
        keysizes, ret = get_rsa_keysizes(flags, swtpm_prg_l)
        if ret != 0:
            sys.exit(1)
        if len(keysizes) > 0:
            rsa_keysize_str = keysizes[-1]
        else:
            rsa_keysize_str = "2048"
    if rsa_keysize_str in ["2048", "3072"]:
        rsa_keysize = int(rsa_keysize_str)
        supported_keysizes, ret = get_rsa_keysizes(flags, swtpm_prg_l)
        if ret != 0:
            sys.exit(1)
        if rsa_keysize not in supported_keysizes and rsa_keysize != 2048:
            logerr(LOGFILE, "%s bit RSA keys are not supported by libtpms.\n" % rsa_keysize_str)
            sys.exit(1)
    else:
        logerr(LOGFILE, "Unsupported RSA key size %s.\n" % rsa_keysize_str)
        sys.exit(1)

    user = getpass.getuser()
    try:
        group = grp.getgrnam(user)[0]
    except KeyError:
        group = "<unknown>"
    tzinfo = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo
    logit(LOGFILE, "Starting vTPM manufacturing as %s:%s @ %s\n" %
          (user, group,
           datetime.datetime.now(tz=tzinfo).strftime("%a %d %h %Y %I:%M:%S %p %Z")))

    if not flags & SETUP_TPM2_F:
        ret = init_tpm(flags, swtpm_prg_l, config_file, tpm_state_path, ownerpass, srkpass, vmid,
                       swtpm_keyopt, fds_to_pass)
    else:
        ret = init_tpm2(flags, swtpm_prg_l, config_file, tpm_state_path, vmid, pcr_banks,
                        swtpm_keyopt, fds_to_pass, rsa_keysize)

    if ret == 0:
        logit(LOGFILE, "Successfully authored TPM state.\n")
    else:
        logerr(LOGFILE, "An error occurred. Authoring the TPM state failed.\n")
        delete_state(flags, tpm_state_path)

    logit(LOGFILE, "Ending vTPM manufacturing @ %s\n" %
          datetime.datetime.now(tz=tzinfo).strftime("%a %d %h %Y %I:%M:%S %p %Z"))

    sys.exit(ret)
Exemple #25
0
    def start(self):
        """ The start method starts the TPM 2 """

        self.pidfile = os.path.join(self.state_path, ".swtpm_setup.pidfile")
        cmdline = self.swtpm_exec_l.copy()

        if self.is_tpm2:
            cmdline.extend(["--tpm2"])

        if self.keyopt:
            cmdline.extend(["--key", self.keyopt])

        cmdline.extend([
            "--flags", "not-need-init", "--tpmstate",
            "dir=%s" % self.state_path, "--pid",
            "file=%s" % self.pidfile
        ])
        # cmdline.extend(["--log", "file=/tmp/log,level=20"])

        ctr = 0
        while ctr < 100:
            self.data_client_socket, self.data_swtpm_socket = socket.socketpair(
                socket.AF_UNIX, socket.SOCK_STREAM)
            os.set_inheritable(self.data_swtpm_socket.fileno(), True)

            self.ctrl_client_socket, self.ctrl_swtpm_socket = socket.socketpair(
                socket.AF_UNIX, socket.SOCK_STREAM)
            os.set_inheritable(self.ctrl_swtpm_socket.fileno(), True)

            r_cmdline = cmdline.copy()
            r_cmdline.extend([
                "--server",
                "type=tcp,fd=%d" % self.data_swtpm_socket.fileno(), "--ctrl",
                "type=unixio,clientfd=%d" % self.ctrl_swtpm_socket.fileno()
            ])

            self.remove_pidfile()

            # print("starting swtpm: %s\n" % r_cmdline)
            try:
                pass_fds = [
                    self.data_swtpm_socket.fileno(),
                    self.ctrl_swtpm_socket.fileno()
                ]
                pass_fds.extend(self.fds_to_pass)

                self.swtpm_proc = subprocess.Popen(r_cmdline,
                                                   stdout=subprocess.PIPE,
                                                   stderr=subprocess.STDOUT,
                                                   pass_fds=pass_fds)
            except Exception as err:
                logerr(
                    self.logfile, "Failed to start swtpm %s: %s\n" %
                    (" ".join(self.swtpm_exec_l), str(err)))

            ctr += 1

            ctr2 = 0
            while True:
                # Is it still running?
                if self.swtpm_proc.poll():
                    stderr = self.swtpm_proc.communicate()[0]
                    print("TPM died? %s\n" % stderr)
                    self.stop()
                    break

                if os.path.exists(self.pidfile):
                    print("TPM is listening on Unix socket.")
                    return 0

                ctr2 += 1
                time.sleep(0.05)

                if ctr2 == 40:
                    self.stop()
                    break

        return 1