Ejemplo n.º 1
0
def generate_challenge(context, ekcert, aikpub, secret, ek=None):
    """ Generate a challenge to verify that the AIK is under the control of
    the TPM we're talking to.

    :param context: The TSS context to use
    :param ekcert: The Endorsement Key certificate
    :param aikpub: The public Attestation Identity Key blob
    :param secret: The secret to challenge the TPM with
    :param ek: TspiKey representing ek. ekcert is ignored if ek is provided.

    :returns: a tuple containing the asymmetric and symmetric components of
    the challenge
    """

    aeskey = bytearray(os.urandom(16))
    iv = bytearray(os.urandom(16))

    if ek is None:
        # Replace rsaesOaep OID with rsaEncryption
        ekcert = ekcert.replace(b'\x2a\x86\x48\x86\xf7\x0d\x01\x01\x07',
                                b'\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01')

        x509 = M2Crypto.X509.load_cert_string(ekcert, M2Crypto.X509.FORMAT_DER)
        pubkey = x509.get_pubkey()
        rsakey = pubkey.get_rsa()
    else:
        pubkey = ek.get_pubkey()
        n = m2.bin_to_bn(pubkey)
        n = m2.bn_to_mpi(n)
        e = m2.hex_to_bn("010001")
        e = m2.bn_to_mpi(e)
        rsakey = M2Crypto.RSA.new_pub_key((e, n))

    # TPM_ALG_AES, TPM_ES_SYM_CBC_PKCS5PAD, key length
    asymplain = bytearray([0x00, 0x00, 0x00, 0x06, 0x00, 0xff, 0x00, 0x10])
    asymplain += aeskey

    m = hashlib.sha1()
    m.update(aikpub)
    asymplain += m.digest()

    # Pad with the TCG varient of OAEP
    asymplain = tpm_oaep(asymplain, len(rsakey)//8)

    # Generate the EKpub-encrypted asymmetric buffer containing the aes key
    asymenc = bytearray(rsakey.public_encrypt(asymplain,
                                              M2Crypto.RSA.no_padding))

    # And symmetrically encrypt the secret with AES
    cipher = M2Crypto.EVP.Cipher('aes_128_cbc', aeskey, iv, 1)
    symenc = cipher.update(secret)
    symenc = symenc + cipher.final()

    symheader = struct.pack('!llhhllll', len(symenc) + len(iv),
                            TPM_ALG_AES, TPM_ES_SYM_CBC_PKCS5PAD,
                            TPM_SS_NONE, 12, 128, len(iv), 0)

    symenc = symheader + iv + symenc

    return (asymenc, symenc)
Ejemplo n.º 2
0
def generate_challenge(context, ekcert, aikpub, secret, ek=None):
    """ Generate a challenge to verify that the AIK is under the control of
    the TPM we're talking to.

    :param context: The TSS context to use
    :param ekcert: The Endorsement Key certificate
    :param aikpub: The public Attestation Identity Key blob
    :param secret: The secret to challenge the TPM with
    :param ek: TspiKey representing ek. ekcert is ignored if ek is provided.

    :returns: a tuple containing the asymmetric and symmetric components of
    the challenge
    """

    aeskey = bytearray(os.urandom(16))
    iv = bytearray(os.urandom(16))

    if ek is None:
        # Replace rsaesOaep OID with rsaEncryption
        ekcert = ekcert.replace('\x2a\x86\x48\x86\xf7\x0d\x01\x01\x07',
                                '\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01')

        x509 = M2Crypto.X509.load_cert_string(ekcert, M2Crypto.X509.FORMAT_DER)
        pubkey = x509.get_pubkey()
        rsakey = pubkey.get_rsa()
    else:
        pubkey = ek.get_pubkey()
        n = m2.bin_to_bn(pubkey)
        n = m2.bn_to_mpi(n)
        e = m2.hex_to_bn("010001")
        e = m2.bn_to_mpi(e)
        rsakey = M2Crypto.RSA.new_pub_key((e, n))

    # TPM_ALG_AES, TPM_ES_SYM_CBC_PKCS5PAD, key length
    asymplain = bytearray([0x00, 0x00, 0x00, 0x06, 0x00, 0xff, 0x00, 0x10])
    asymplain += aeskey

    m = hashlib.sha1()
    m.update(aikpub)
    asymplain += m.digest()

    # Pad with the TCG varient of OAEP
    asymplain = tpm_oaep(asymplain, len(rsakey)/8)

    # Generate the EKpub-encrypted asymmetric buffer containing the aes key
    asymenc = bytearray(rsakey.public_encrypt(asymplain,
                                              M2Crypto.RSA.no_padding))

    # And symmetrically encrypt the secret with AES
    cipher = M2Crypto.EVP.Cipher('aes_128_cbc', aeskey, iv, 1)
    cipher.update(secret)
    symenc = cipher.final()

    symheader = struct.pack('!llhhllll', len(symenc) + len(iv),
                            TPM_ALG_AES, TPM_ES_SYM_CBC_PKCS5PAD,
                            TPM_SS_NONE, 12, 128, len(iv), 0)

    symenc = symheader + iv + symenc

    return (asymenc, symenc)
Ejemplo n.º 3
0
def quote_verify(data, validation, aik, pcrvalues):
    """Verify that a generated quote came from a trusted TPM and matches the
    previously obtained PCR values

    :param data: The TPM_QUOTE_INFO structure provided by the TPM
    :param validation: The validation information provided by the TPM
    :param aik: The object representing the Attestation Identity Key
    :param pcrvalues: A dictionary containing the PCRs read from the TPM
    :returns: True if the quote can be verified, False otherwise
    """
    select = 0
    maxpcr = 0

    # Verify that the validation blob was generated by a trusted TPM
    pubkey = aik.get_pubkey()

    n = m2.bin_to_bn(pubkey)
    n = m2.bn_to_mpi(n)
    e = m2.hex_to_bn("010001")
    e = m2.bn_to_mpi(e)
    rsa = M2Crypto.RSA.new_pub_key((e, n))

    m = hashlib.sha1()
    m.update(data)
    md = m.digest()

    try:
        ret = rsa.verify(md, str(validation), algo='sha1')
    except M2Crypto.RSA.RSAError:
        return False

    # And then verify that the validation blob corresponds to the PCR
    # values we have
    values = bytearray()

    for pcr in sorted(pcrvalues):
        values += pcrvalues[pcr]
        select |= (1 << pcr)
        maxpcr = pcr

    if maxpcr < 16:
        header = struct.pack('!H', 2)
        header += struct.pack('@H', select)
        header += struct.pack('!I', len(values))
    else:
        header = struct.pack('!H', 4)
        header += struct.pack('@I', select)
        header += struct.pack('!I', len(values))

    pcr_blob = header + values

    m = hashlib.sha1()
    m.update(pcr_blob)
    pcr_hash = m.digest()

    if pcr_hash == data[8:28]:
        return True
    else:
        return False
Ejemplo n.º 4
0
def quote_verify(data, validation, aik, pcrvalues):
    """Verify that a generated quote came from a trusted TPM and matches the
    previously obtained PCR values

    :param data: The TPM_QUOTE_INFO structure provided by the TPM
    :param validation: The validation information provided by the TPM
    :param aik: The object representing the Attestation Identity Key
    :param pcrvalues: A dictionary containing the PCRs read from the TPM
    :returns: True if the quote can be verified, False otherwise
    """
    select = 0
    maxpcr = 0

    # Verify that the validation blob was generated by a trusted TPM
    pubkey = aik.get_pubkey()

    n = m2.bin_to_bn(pubkey)
    n = m2.bn_to_mpi(n)
    e = m2.hex_to_bn("010001")
    e = m2.bn_to_mpi(e)
    rsa = M2Crypto.RSA.new_pub_key((e, n))

    m = hashlib.sha1()
    m.update(data)
    md = m.digest()

    try:
        ret = rsa.verify(md, str(validation), algo='sha1')
    except M2Crypto.RSA.RSAError:
        return False

    # And then verify that the validation blob corresponds to the PCR
    # values we have
    values = bytearray()

    for pcr in sorted(pcrvalues):
        values += pcrvalues[pcr]
        select |= (1 << pcr)
        maxpcr = pcr

    if maxpcr < 16:
        header = struct.pack('!H', 2)
        header += struct.pack('@H', select)
        header += struct.pack('!I', len(values))
    else:
        header = struct.pack('!H', 4)
        header += struct.pack('@I', select)
        header += struct.pack('!I', len(values))

    pcr_blob = header + values

    m = hashlib.sha1()
    m.update(pcr_blob)
    pcr_hash = m.digest()

    if pcr_hash == data[8:28]:
        return True
    else:
        return False