def _dnskey_to_dsa(key): # get T t, = struct.unpack(b'B', key[0]) offset = 1 # get Q new_offset = offset + 20 q = bn_to_mpi(hex_to_bn(binascii.hexlify(key[offset:new_offset]))) offset = new_offset # get P new_offset = offset + 64 + (t << 3) p = bn_to_mpi(hex_to_bn(binascii.hexlify(key[offset:new_offset]))) offset = new_offset # get G new_offset = offset + 64 + (t << 3) g = bn_to_mpi(hex_to_bn(binascii.hexlify(key[offset:new_offset]))) offset = new_offset # get Y new_offset = offset + 64 + (t << 3) y = bn_to_mpi(hex_to_bn(binascii.hexlify(key[offset:new_offset]))) offset = new_offset # create the DSA public key return DSA.pub_key_from_params(p, q, g, y)
def _dnskey_to_dsa(key): # get T t = key[0] # python3/python2 dual compatibility if not isinstance(t, int): t = ord(t) offset = 1 # get Q new_offset = offset + 20 q = bn_to_mpi(hex_to_bn(binascii.hexlify(key[offset:new_offset]))) offset = new_offset # get P new_offset = offset + 64 + (t << 3) p = bn_to_mpi(hex_to_bn(binascii.hexlify(key[offset:new_offset]))) offset = new_offset # get G new_offset = offset + 64 + (t << 3) g = bn_to_mpi(hex_to_bn(binascii.hexlify(key[offset:new_offset]))) offset = new_offset # get Y new_offset = offset + 64 + (t << 3) y = bn_to_mpi(hex_to_bn(binascii.hexlify(key[offset:new_offset]))) offset = new_offset # create the DSA public key return DSA.pub_key_from_params(p, q, g, y)
def _validate_rrsig_dsa(alg, sig, msg, key): pubkey = _dnskey_to_dsa(key) # get T t, = struct.unpack(b'B', sig[0]) offset = 1 # get R new_offset = offset + 20 r = b'' for c in sig[offset:new_offset]: r += b'%02x' % struct.unpack(b'B', c)[0] r = bn_to_mpi(hex_to_bn(r)) offset = new_offset # get S new_offset = offset + 20 s = b'' for c in sig[offset:new_offset]: s += b'%02x' % struct.unpack(b'B', c)[0] s = bn_to_mpi(hex_to_bn(s)) offset = new_offset md = EVP.MessageDigest('sha1') md.update(msg) digest = md.final() return pubkey.verify(digest, r, s) == 1
def _dnskey_to_rsa(key): try: # get the exponent length e_len, = struct.unpack(b'B',key[0]) except IndexError: return None offset = 1 if e_len == 0: e_len, = struct.unpack(b'!H',key[1:3]) offset = 3 # get the exponent e = b'' for c in key[offset:offset+e_len]: e += b'%02x' % struct.unpack(b'B',c)[0] e = bn_to_mpi(hex_to_bn(e)) offset += e_len # get the modulus n = b'' for c in key[offset:]: n += b'%02x' % struct.unpack(b'B',c)[0] n = bn_to_mpi(hex_to_bn(n)) # create the RSA public key rsa = RSA.new_pub_key((e,n)) pubkey = EVP.PKey() pubkey.assign_rsa(rsa) return pubkey
def _validate_rrsig_dsa(alg, sig, msg, key): pubkey = _dnskey_to_dsa(key) # get T t, = struct.unpack(b'B',sig[0]) offset = 1 # get R new_offset = offset+20 r = b'' for c in sig[offset:new_offset]: r += b'%02x' % struct.unpack(b'B',c)[0] r = bn_to_mpi(hex_to_bn(r)) offset = new_offset # get S new_offset = offset+20 s = b'' for c in sig[offset:new_offset]: s += b'%02x' % struct.unpack(b'B',c)[0] s = bn_to_mpi(hex_to_bn(s)) offset = new_offset md = EVP.MessageDigest('sha1') md.update(msg) digest = md.final() return pubkey.verify(digest, r, s) == 1
def _validate_rrsig_dsa(alg, sig, msg, key): pubkey = _dnskey_to_dsa(key) # get T t = sig[0] # python3/python2 dual compatibility if not isinstance(t, int): t = ord(t) offset = 1 # get R new_offset = offset + 20 r = bn_to_mpi(hex_to_bn(binascii.hexlify(sig[offset:new_offset]))) offset = new_offset # get S new_offset = offset + 20 s = bn_to_mpi(hex_to_bn(binascii.hexlify(sig[offset:new_offset]))) offset = new_offset md = EVP.MessageDigest('sha1') md.update(msg) digest = md.final() return pubkey.verify(digest, r, s) == 1
def _dnskey_to_rsa(key): try: # get the exponent length e_len = key[0] except IndexError: return None # python3/python2 dual compatibility if not isinstance(e_len, int): e_len = ord(e_len) offset = 1 if e_len == 0: e_len, = struct.unpack(b'!H', key[1:3]) offset = 3 # get the exponent e = bn_to_mpi(hex_to_bn(binascii.hexlify(key[offset:offset + e_len]))) offset += e_len # get the modulus n = bn_to_mpi(hex_to_bn(binascii.hexlify(key[offset:]))) # create the RSA public key rsa = RSA.new_pub_key((e, n)) pubkey = EVP.PKey() pubkey.assign_rsa(rsa) return pubkey
def _dnskey_to_rsa(key): try: # get the exponent length e_len, = struct.unpack(b'B', key[0]) except IndexError: return None offset = 1 if e_len == 0: e_len, = struct.unpack(b'!H', key[1:3]) offset = 3 # get the exponent e = b'' for c in key[offset:offset + e_len]: e += b'%02x' % struct.unpack(b'B', c)[0] e = bn_to_mpi(hex_to_bn(e)) offset += e_len # get the modulus n = b'' for c in key[offset:]: n += b'%02x' % struct.unpack(b'B', c)[0] n = bn_to_mpi(hex_to_bn(n)) # create the RSA public key rsa = RSA.new_pub_key((e, n)) pubkey = EVP.PKey() pubkey.assign_rsa(rsa) return pubkey
def _dnskey_to_dsa(key): # get T t, = struct.unpack(b'B',key[0]) offset = 1 # get Q new_offset = offset+20 q = bn_to_mpi(hex_to_bn(binascii.hexlify(key[offset:new_offset]))) offset = new_offset # get P new_offset = offset+64+(t<<3) p = bn_to_mpi(hex_to_bn(binascii.hexlify(key[offset:new_offset]))) offset = new_offset # get G new_offset = offset+64+(t<<3) g = bn_to_mpi(hex_to_bn(binascii.hexlify(key[offset:new_offset]))) offset = new_offset # get Y new_offset = offset+64+(t<<3) y = bn_to_mpi(hex_to_bn(binascii.hexlify(key[offset:new_offset]))) offset = new_offset # create the DSA public key return DSA.pub_key_from_params(p,q,g,y)
def verify_ek(self, ekcert, ekpem): """Verify that the provided EK certificate is signed by a trusted root :param ekcert: The Endorsement Key certificate in DER format :param ekpem: the endorsement public key in PEM format :returns: True if the certificate can be verified, false otherwise """ #openssl x509 -inform der -in certificate.cer -out certificate.pem try: pubekmod = base64.b64decode(self.__get_mod_from_pem(ekpem)) ek509 = M2Crypto.X509.load_cert_der_string(ekcert) # locate the region where the pub ek should be and then brute force looking for it. this is awful! # Sadly TPM ek certificates are corrupted in a way that openssl and most other utilities can't read them. # sigh TCG # # search for first 1.2.840.113549.1.1.5 (OID for sha1WithRSAEncryption (PKCS #1)) start = ekcert.index( codecs.decode('2a864886f70d010107', 'hex_codec')) # now locate the next 1.2.840.113549.1.1.7 (OID for rsaOAEP (PKCS #1)) afterwards end = ekcert.index(codecs.decode('2a864886f70d010105', 'hex_codec')) if str(pubekmod) not in str(ekcert[start:end]): logger.error("Public EK does not match EK certificate") return False for signer in trusted_certs: signcert = M2Crypto.X509.load_cert_string( trusted_certs[signer]) signkey = signcert.get_pubkey() if ek509.verify(signkey) == 1: logger.debug("EK cert matched signer %s" % signer) return True for key in atmel_trusted_keys: e = m2.bn_to_mpi( m2.hex_to_bn(atmel_trusted_keys[key]['exponent'])) n = m2.bn_to_mpi(m2.hex_to_bn(atmel_trusted_keys[key]['key'])) rsa = M2Crypto.RSA.new_pub_key((e, n)) pubkey = M2Crypto.EVP.PKey() pubkey.assign_rsa(rsa) if ek509.verify(pubkey) == 1: logger.debug("EK cert matched trusted key %s" % key) return True except Exception as e: # Log the exception so we don't lose the raw message logger.exception(e) raise Exception( "Error processing ek/ekcert. Does this TPM have a valid EK?" ).with_traceback(sys.exc_info()[2]) logger.error("No Root CA matched EK Certificate") return False
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 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 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
def verify_ek(ekcert, ekpem): """Verify that the provided EK certificate is signed by a trusted root :param ekcert: The Endorsement Key certificate in DER format :param ekpem: the endorsement public key in PEM format :returns: True if the certificate can be verified, false otherwise """ tmppath = None try: # write out key blob tmpfd, tmppath = tempfile.mkstemp() ekFile = open(tmppath, "wb") ekFile.write(ekpem) ekFile.close() os.close(tmpfd) pubekmod = base64.b64decode(get_mod_from_pem(tmppath)) finally: if tmppath is not None: os.remove(tmppath) ek509 = M2Crypto.X509.load_cert_der_string(ekcert) if str(pubekmod) not in str(ekcert): logger.error("Public EK does not match EK certificate") return False for signer in trusted_certs: signcert = M2Crypto.X509.load_cert_string(trusted_certs[signer]) signkey = signcert.get_pubkey() if ek509.verify(signkey) == 1: logger.debug("EK cert matched signer %s" % signer) return True for key in atmel_trusted_keys: e = m2.bn_to_mpi(m2.hex_to_bn(atmel_trusted_keys[key]['exponent'])) n = m2.bn_to_mpi(m2.hex_to_bn(atmel_trusted_keys[key]['key'])) rsa = M2Crypto.RSA.new_pub_key((e, n)) pubkey = M2Crypto.EVP.PKey() pubkey.assign_rsa(rsa) if ek509.verify(pubkey) == 1: logger.debug("EK cert matched trusted key %s" % key) return True logger.errror("No Root CA matched EK Certificate") return False
def _validate_rrsig_ec(alg, sig, msg, key): pubkey = _dnskey_to_ec(alg, key) # if the key is invalid, then the signature is also invalid if pubkey is None: return False if alg in (13, ): alg = 'sha256' sigsize = 64 elif alg in (14, ): alg = 'sha384' sigsize = 96 else: raise ValueError('EC hash algorithm unknown!') if sigsize != len(sig): return False offset = 0 # get R new_offset = offset + sigsize // 2 r = b'' for c in sig[offset:new_offset]: r += b'%02x' % struct.unpack(b'B', c)[0] r = bn_to_mpi(hex_to_bn(r)) offset = new_offset # get S new_offset = offset + sigsize // 2 s = b'' for c in sig[offset:new_offset]: s += b'%02x' % struct.unpack(b'B', c)[0] s = bn_to_mpi(hex_to_bn(s)) offset = new_offset md = EVP.MessageDigest(alg) md.update(msg) digest = md.final() return pubkey.verify_dsa(digest, r, s) == 1
def _validate_rrsig_ec(alg, sig, msg, key): pubkey = _dnskey_to_ec(alg, key) # if the key is invalid, then the signature is also invalid if pubkey is None: return False if alg in (13,): alg='sha256' sigsize = 64 elif alg in (14,): alg='sha384' sigsize = 96 else: raise ValueError('EC hash algorithm unknown!') if sigsize != len(sig): return False offset = 0 # get R new_offset = offset+sigsize//2 r = b'' for c in sig[offset:new_offset]: r += b'%02x' % struct.unpack(b'B',c)[0] r = bn_to_mpi(hex_to_bn(r)) offset = new_offset # get S new_offset = offset+sigsize//2 s = b'' for c in sig[offset:new_offset]: s += b'%02x' % struct.unpack(b'B',c)[0] s = bn_to_mpi(hex_to_bn(s)) offset = new_offset md = EVP.MessageDigest(alg) md.update(msg) digest = md.final() return pubkey.verify_dsa(digest, r, s) == 1
def handle14(self, msg): #print "r : %x" % msg.data["r"] #print "s : %x" % msg.data["s"] sync = msg.data["sync"] addr = msg.data["addr"] key = msg.data["key"] r=m2.bn_to_mpi(m2.hex_to_bn("%x" % msg.data["r"])) s=m2.bn_to_mpi(m2.hex_to_bn("%x" % msg.data["s"])) data= msg.data["data"] data_sha =hashlib.sha1(self.to_bytes(data,(data.bit_length()/8)+1,endianess='big')).digest() #print "Data sha :" #print hashlib.sha1(self.to_bytes(data,(data.bit_length()/8)+1,endianess='big')).hexdigest() text="Wrong signature !" if self.pub_key.verify_dsa(data_sha,r,s): text="Signature verified." self.last_key="%x" % key retstr = output_print.prefix(msg) retstr += "Type 14 : Signature with sync = %i and addr=%x . " %(sync, addr) retstr+=text self._print(retstr)
def _validate_rrsig_dsa(alg, sig, msg, key): pubkey = _dnskey_to_dsa(key) # get T t, = struct.unpack(b'B', sig[0]) offset = 1 # get R new_offset = offset + 20 r = bn_to_mpi(hex_to_bn(binascii.hexlify(sig[offset:new_offset]))) offset = new_offset # get S new_offset = offset + 20 s = bn_to_mpi(hex_to_bn(binascii.hexlify(sig[offset:new_offset]))) offset = new_offset md = EVP.MessageDigest('sha1') md.update(msg) digest = md.final() return pubkey.verify(digest, r, s) == 1
def _dnskey_to_dsa(key): # get T t, = struct.unpack(b'B',key[0]) offset = 1 # get Q new_offset = offset+20 q = b'' for c in key[offset:new_offset]: q += b'%02x' % struct.unpack(b'B',c)[0] q = bn_to_mpi(hex_to_bn(q)) offset = new_offset # get P new_offset = offset+64+(t<<3) p = b'' for c in key[offset:new_offset]: p += b'%02x' % struct.unpack(b'B',c)[0] p = bn_to_mpi(hex_to_bn(p)) offset = new_offset # get G new_offset = offset+64+(t<<3) g = b'' for c in key[offset:new_offset]: g += b'%02x' % struct.unpack(b'B',c)[0] g = bn_to_mpi(hex_to_bn(g)) offset = new_offset # get Y new_offset = offset+64+(t<<3) y = b'' for c in key[offset:new_offset]: y += b'%02x' % struct.unpack(b'B',c)[0] y = bn_to_mpi(hex_to_bn(y)) offset = new_offset # create the DSA public key return DSA.pub_key_from_params(p,q,g,y)
def _validate_rrsig_dsa(alg, sig, msg, key): pubkey = _dnskey_to_dsa(key) # get T t, = struct.unpack(b'B',sig[0]) offset = 1 # get R new_offset = offset+20 r = bn_to_mpi(hex_to_bn(binascii.hexlify(sig[offset:new_offset]))) offset = new_offset # get S new_offset = offset+20 s = bn_to_mpi(hex_to_bn(binascii.hexlify(sig[offset:new_offset]))) offset = new_offset md = EVP.MessageDigest('sha1') md.update(msg) digest = md.final() return pubkey.verify(digest, r, s) == 1
def _dnskey_to_dsa(key): # get T t, = struct.unpack(b'B', key[0]) offset = 1 # get Q new_offset = offset + 20 q = b'' for c in key[offset:new_offset]: q += b'%02x' % struct.unpack(b'B', c)[0] q = bn_to_mpi(hex_to_bn(q)) offset = new_offset # get P new_offset = offset + 64 + (t << 3) p = b'' for c in key[offset:new_offset]: p += b'%02x' % struct.unpack(b'B', c)[0] p = bn_to_mpi(hex_to_bn(p)) offset = new_offset # get G new_offset = offset + 64 + (t << 3) g = b'' for c in key[offset:new_offset]: g += b'%02x' % struct.unpack(b'B', c)[0] g = bn_to_mpi(hex_to_bn(g)) offset = new_offset # get Y new_offset = offset + 64 + (t << 3) y = b'' for c in key[offset:new_offset]: y += b'%02x' % struct.unpack(b'B', c)[0] y = bn_to_mpi(hex_to_bn(y)) offset = new_offset # create the DSA public key return DSA.pub_key_from_params(p, q, g, y)
def _validate_rrsig_ec(alg, sig, msg, key): pubkey = _dnskey_to_ec(alg, key) if alg in (13,): alg = "sha256" sigsize = 64 elif alg in (14,): alg = "sha384" sigsize = 96 else: raise ValueError("EC hash algorithm unknown!") if sigsize != len(sig): return False offset = 0 # get R new_offset = offset + sigsize / 2 r = "" for c in sig[offset:new_offset]: r += "%02x" % struct.unpack("B", c)[0] r = bn_to_mpi(hex_to_bn(r)) offset = new_offset # get S new_offset = offset + sigsize / 2 s = "" for c in sig[offset:new_offset]: s += "%02x" % struct.unpack("B", c)[0] s = bn_to_mpi(hex_to_bn(s)) offset = new_offset md = EVP.MessageDigest(alg) md.update(msg) digest = md.final() return pubkey.verify_dsa(digest, r, s) == 1
def verify_ek(context, ekcert): """Verify that the provided EK certificate is signed by a trusted root :param context: The TSS context to use :param ekcert: The Endorsement Key certificate :returns: True if the certificate can be verified, false otherwise """ ek509 = M2Crypto.X509.load_cert_der_string(ekcert) for signer in trusted_certs: signcert = M2Crypto.X509.load_cert_string(trusted_certs[signer]) signkey = signcert.get_pubkey() if ek509.verify(signkey) == 1: return True for key in trusted_keys: e = m2.bn_to_mpi(m2.hex_to_bn(trusted_keys[key]['exponent'])) n = m2.bn_to_mpi(m2.hex_to_bn(trusted_keys[key]['key'])) rsa = M2Crypto.RSA.new_pub_key((e, n)) pubkey = M2Crypto.EVP.PKey() pubkey.assign_rsa(rsa) if ek509.verify(pubkey) == 1: return True return False