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)
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)
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