def get_auth_data(filename): with open(filename, 'rb') as objf: fingerprinter = fingerprint.Fingerprinter(objf) fingerprinter.EvalGeneric() results = fingerprinter.HashIt() signed_pecoffs = [ x for x in results if x['name'] == 'pecoff' and 'SignedData' in x ] if not signed_pecoffs: print('This PE/COFF binary has no signature. Exiting.') return signed_pecoff = signed_pecoffs[0] signed_datas = signed_pecoff['SignedData'] # There may be multiple of these, if the windows binary was signed multiple # times, e.g. by different entities. Each of them adds a complete SignedData # blob to the binary. # TODO(user): Process all instances signed_data = signed_datas[0] blob = pecoff_blob.PecoffBlob(signed_data) auth = auth_data.AuthData(blob.getCertificateBlob()) content_hasher_name = auth.digest_algorithm().name computed_content_hash = signed_pecoff[content_hasher_name] return auth, computed_content_hash
def testRunTestData(self): # Walk through one data file in the test_data folder, and compare output # with precomputed expected output. data_file = os.path.join('test_data', 'SoftwareUpdate.exe.res') with file(data_file, 'rb') as resf: exp_results = pickle.load(resf) # Make sure we have loaded the right data. expected_generic_sha1 = '8322f1c2c355d88432f1f03a1f231f63912186bd' loaded_generic_hashes = [ x for x in exp_results if x['name'] == 'generic' ] loaded_generic_sha1 = loaded_generic_hashes[0]['sha1'].encode('hex') self.assertEquals(expected_generic_sha1, loaded_generic_sha1) signed_pecoffs = [ x for x in exp_results if x['name'] == 'pecoff' and 'SignedData' in x ] # If the invoker of the fingerprinter specified multiple fingers for pecoff # hashing (possible, even if not sensible), then there can be more than one # entry in this list. Should not be the case for this sample. self.assertEquals(len(signed_pecoffs), 1) signed_pecoff = signed_pecoffs[0] # Make sure PE/COFF hashes match as well. Again, just a sanity check. expected_auth_sha1 = '978b90ace99c764841d2dd17d278fac4149962a3' loaded_auth_sha1 = signed_pecoff['sha1'].encode('hex') self.assertEquals(expected_auth_sha1, loaded_auth_sha1) signed_datas = signed_pecoff['SignedData'] # There may be multiple of these, if the windows binary was signed multiple # times, e.g. by different entities. Each of them adds a complete SignedData # blob to the binary. For our sample, there is only one blob. self.assertEquals(len(signed_datas), 1) signed_data = signed_datas[0] blob = pecoff_blob.PecoffBlob(signed_data) auth = auth_data.AuthData(blob.getCertificateBlob()) content_hasher_name = auth.digest_algorithm().name computed_content_hash = signed_pecoff[content_hasher_name] try: auth.ValidateAsn1() auth.ValidateHashes(computed_content_hash) auth.ValidateSignatures() auth.ValidateCertChains(time.gmtime()) except auth_data.Asn1Error: if auth.openssl_error: print('OpenSSL Errors:\n%s' % auth.openssl_error) raise print('Program: %s, URL: %s' % (auth.program_name, auth.program_url)) print('countersig: %d' % auth.has_countersignature) print('Timestamp: %s' % auth.counter_timestamp) self.assertEquals(auth.trailing_data.encode('hex'), '00')
def main(): data_file = sys.argv[1] with file(data_file, 'rb') as objf: fingerprinter = fingerprint.Fingerprinter(objf) is_pecoff = fingerprinter.EvalPecoff() fingerprinter.EvalGeneric() results = fingerprinter.HashIt() print('Generic hashes:') hashes = [x for x in results if x['name'] == 'generic'] if len(hashes) > 1: print('More than one generic finger? Only printing first one.') for hname in sorted(hashes[0].keys()): if hname != 'name': print('%s: %s' % (hname, hashes[0][hname].encode('hex'))) print if not is_pecoff: print('This is not a PE/COFF binary. Exiting.') return print('PE/COFF hashes:') hashes = [x for x in results if x['name'] == 'pecoff'] if len(hashes) > 1: print('More than one PE/COFF finger? Only printing first one.') for hname in sorted(hashes[0].keys()): if hname != 'name' and hname != 'SignedData': print('%s: %s' % (hname, hashes[0][hname].encode('hex'))) print signed_pecoffs = [ x for x in results if x['name'] == 'pecoff' and 'SignedData' in x ] if not signed_pecoffs: print('This PE/COFF binary has no signature. Exiting.') return signed_pecoff = signed_pecoffs[0] signed_datas = signed_pecoff['SignedData'] if len(signed_datas) > 1: raise Exception( "TODO Add support for printing more than one certificate") # There may be multiple of these, if the windows binary was signed multiple # times, e.g. by different entities. Each of them adds a complete SignedData # blob to the binary. # TODO(user): Process all instances signed_data = signed_datas[0] debugging_fd = open( '/tmp/%s_extracted_cert.p7b' % os.path.basename(data_file), 'wb') debugging_fd.write(signed_data[2]) debugging_fd.close() blob = pecoff_blob.PecoffBlob(signed_data) auth = auth_data.AuthData(blob.getCertificateBlob()) content_hasher_name = auth.digest_algorithm().name computed_content_hash = signed_pecoff[content_hasher_name] try: auth.ValidateAsn1() auth.ValidateHashes(computed_content_hash) auth.ValidateSignatures() auth.ValidateCertChains(time.gmtime()) except auth_data.Asn1Error: if auth.openssl_error: print('OpenSSL Errors:\n%s' % auth.openssl_error) raise print('Program: %s, URL: %s' % (repr(auth.program_name), auth.program_url)) if auth.has_countersignature: print('Countersignature is present. Timestamp: %s UTC' % time.asctime(time.gmtime(auth.counter_timestamp))) else: print('Countersignature is not present.') print('Binary is signed with cert issued by:') pprint.pprint(auth.signing_cert_id) print print('Cert chain head issued by:') pprint.pprint(auth.cert_chain_head[2]) print(' Chain not before: %s UTC' % (time.asctime(time.gmtime(auth.cert_chain_head[0])))) print(' Chain not after: %s UTC' % (time.asctime(time.gmtime(auth.cert_chain_head[1])))) print if auth.has_countersignature: print('Countersig chain head issued by:') pprint.pprint(auth.counter_chain_head[2]) print(' Countersig not before: %s UTC' % (time.asctime(time.gmtime(auth.counter_chain_head[0])))) print(' Countersig not after: %s UTC' % (time.asctime(time.gmtime(auth.counter_chain_head[1])))) print print('Certificates') for (issuer, serial), cert in auth.certificates.items(): print(' Issuer: %s' % issuer) print(' Serial: %s' % serial) subject = cert[0][0]['subject'] subject_dn = str(dn.DistinguishedName.TraverseRdn(subject[0])) print(' Subject: %s' % subject_dn) not_before = cert[0][0]['validity']['notBefore'] not_after = cert[0][0]['validity']['notAfter'] not_before_time = not_before.ToPythonEpochTime() not_after_time = not_after.ToPythonEpochTime() print(' Not Before: %s UTC (%s)' % (time.asctime(time.gmtime(not_before_time)), not_before[0])) print(' Not After: %s UTC (%s)' % (time.asctime(time.gmtime(not_after_time)), not_after[0])) bin_cert = der_encoder.encode(cert) print(' MD5: %s' % hashlib.md5(bin_cert).hexdigest()) print(' SHA1: %s' % hashlib.sha1(bin_cert).hexdigest()) print if auth.trailing_data: print('Signature Blob had trailing (unvalidated) data (%d bytes): %s' % (len(auth.trailing_data), auth.trailing_data.encode('hex')))