def extractOwnerInfo(self, data): if not data.has_key('5F1F') or not data.has_key('5F5B'): raise Exception("Could not extract name/mrz") mrz = data['5F1F'][44:88] name = (data['5F5B']).split("<<") name = helper.getItem(name[0]) + " " + helper.getItem(name[1]) return (name,mrz)
def loadDG13(self, fields, data): if data.has_key("9F01"): fields['height'].set(getItem(data['9F01']) + " m") if data.has_key("9F02"): fields['eyesColour'].set(getItem(data['9F02'])) if data.has_key("9F03"): fields['residence'].set(getItem(data['9F03']))
def loadDG1(self, fields, data): if data.has_key('5F1F'): mrz = data['5F1F'] mrz = mrz[:44] + "\n" + mrz[44:] if len(data['5F1F']) > 88: mrz = mrz[:89] + "\n" + mrz[89:] fields['mrz'].set(mrz) if data.has_key('5F5B'): name = (data['5F5B']).split("<<") fields['name'].set(getItem(name[0])) fields['surname'].set(getItem(name[1])) if data.has_key('5F03'): fields['type'].set(getItem(data['5F03'])) if data.has_key('5F28'): fields['issueCountry'].set(getItem(data['5F28'])) if data.has_key('5A'): fields['passportNumber'].set(getItem(data['5A'])) if data.has_key('5F2C'): fields['nationality'].set(getItem(data['5F2C'])) if data.has_key('5F57'): fields['birthDate'].set(getItem(data['5F57'])) if data.has_key('5F35'): fields['sex'].set(getItem(data['5F35'])) if data.has_key('59'): fields['expiryDate'].set(getItem("20" + data['59'])) # 20 make a "real" date
def loadDG11(self, fields, data): if data.has_key("5F2B"): fields['birthDate'].set(getItem(data['5F2B'])) if data.has_key("5F11"): fields['birthPlace'].set(getItem(data['5F11'])) # This DG keep the accents, contrary to the DG1 # but beware some passports contain an empty or almost empty 5F0E (e.g. BE: 5F0E0120 or 5F0E00) if data.has_key("5F0E") and \ len(data['5F0E']) > len(fields['name'].get()) + len(fields['surname'].get()): if "<<" in data['5F0E']: tmpname = (data['5F0E']).split("<<") fields['name'].set(getItem(tmpname[0])) fields['surname'].set(getItem(tmpname[1])) else: # no specific separator between name(s) and surname(s) tmpname = (data['5F0E']).split(" ") namewords = len(fields['name'].get().split(" ")) fields['name'].set(getItem(' '.join(tmpname[:namewords]))) fields['surname'].set(getItem(' '.join(tmpname[namewords:]))) # French, nom d'usage, http://fr.wikipedia.org/wiki/Nom_d'usage_en_France if data.has_key("A0") and getItem(data['A0'])[0] != '\x02': # TODO: some Belgian passports contain # 5F0E 00 A0 06020101 5F0F 00 # is there a better way to discard their A0?? old = fields['name'].get() fields['name'].set(old + ", " + getItem(data['A0']))
def loadDG12(self, fields, data): if data.has_key("5F19"): fields['authority'].set(getItem(data['5F19'])) if data.has_key("5F26"): fields['issueDate'].set(getItem(data['5F26']))
def toPDF(data, filename): """ Export doc9303 instance to PDF @param doc: doc9303 @type doc: doc9303 instance (pyPassport) @param filename: output file @type filename: String @return: None """ doc = SimpleDocTemplate(filename, pagesize=letter, rightMargin=72, leftMargin=72, topMargin=72, bottomMargin=18) Story=[] styles=getSampleStyleSheet() # NAME name = (data["EP"]["DG1"]["5F5B"]).split("<<") Story.append(Paragraph(getItem(name[1].upper())+" "+getItem(name[0].upper()), styles["Heading1"])) # PICTURE tag = None if data["EP"]["DG2"]["A1"].has_key("5F2E"): tag = "5F2E" elif data["EP"]["DG2"]["A1"].has_key("7F2E"): tag = "7F2E" if tag != None: path = None raw = data["EP"]["DG2"]["A1"][tag] profile = writeImageToDisk(raw, "~picture") img_file = PIL.Image.open(profile) width, height = img_file.size ratio = float(width)/float(2*inch) h_img = float(height)/ratio im = Image(profile, 2*inch, h_img) Story.append(im) try: if data["EP"].has_key("DG7") and data["EP"]["DG7"].has_key("5F43"): raw = data["EP"]["DG7"]["5F43"][0] signature = writeImageToDisk(raw, "~signature") img_signature = PIL.Image.open(signature) width, height = img_signature.size ratio = float(width)/float(2*inch) h_img = float(height)/ratio sign = Image(signature, 2*inch, h_img) Story.append(sign) except Exception: pass # OVERVIEW Story.append(Paragraph("Overview", styles["Heading2"])) Story.append(Paragraph("<font size=12>Type: " + getItemByTag(data["EP"], 'DG1','5F03') + "</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Passport #: "+str(getItemByTag(data["EP"],'DG1','5A'))+"</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Country: "+str(getItemByTag(data["EP"],'DG1','5F28'))+"</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Authority: "+str(getItemByTag(data["EP"],'DG12','5F19'))+"</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Issue Date: "+str(getItemByTag(data["EP"],'DG12','5F26'))+"</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Expiry Place: "+str(getItemByTag(data["EP"],'DG1','59'))+"</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Nationality: "+str(getItemByTag(data["EP"],'DG1','5F2C'))+"</font>", styles["Normal"])) Story.append(Spacer(1, 12)) Story.append(Paragraph("<font size=12>Name: "+str(getItem(name[0]))+"</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Surname: "+str(getItem(name[1]))+"</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Birth Date: "+str(getItemByTag(data["EP"],'DG1','5F57'))+"</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Birth Place: "+str(getItemByTag(data["EP"],'DG11','5F11'))+"</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Sex: "+str(getItemByTag(data["EP"],'DG1','5F35'))+"</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Height: "+str(getItemByTag(data["EP"], 'DG13', '9F01'))+"</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Colour of eyes: "+str(getItemByTag(data["EP"], 'DG13', '9F02'))+"</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Residence: "+str(getItemByTag(data["EP"], 'DG13', '9F03'))+"</font>", styles["Normal"])) Story.append(Spacer(1, 12)) Story.append(Paragraph("Basic Access Control", styles["Heading2"])) Story.append(Paragraph("<font size=12>Basic Access Control: "+data["bac"]+"</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Reading time: "+str(data["ReadingTime"])+"</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Data Groups size:</font>", styles["Normal"])) for key, value in data["DGs"]: Story.append(Paragraph("<font size=12>  - " + str(key) + ": " + str(value) + " octets"+"</font>", styles["Normal"])) # PRESENT DATAGROUPS #Story.append(Paragraph("Present DataGroups", styles["Heading2"])) #k = map(toOrder, data["EP"].keys()) #k.sort() #k = map(toDG,k) #for dg in k: # Story.append(Paragraph("<font size=12> - "+str(dg)+"</font>", styles["Normal"])) #Story.append(Spacer(1, 20)) # DUMP Story.append(Paragraph("MRZ information", styles["Heading3"])) for item in data["EP"]["DG1"]: try: tag_name = tagToName[item] except Exception: tag_name = item Story.append(Paragraph("<font size=12> "+tag_name+": "+getItemRaw(data["EP"], 'DG1', item)+"</font>", styles["Normal"])) Story.append(Spacer(1, 12)) if data["EP"].has_key("DG11"): Story.append(Paragraph("Additional document holder details", styles["Heading3"])) for item in data["EP"]["DG11"]["5C"]: try: tag_name = tagToName[item] except Exception: tag_name = item Story.append(Paragraph("<font size=12> "+tag_name+": "+getItemRaw(data["EP"], 'DG11', item)+"</font>", styles["Normal"])) Story.append(Spacer(1, 12)) if data["EP"].has_key("DG12"): Story.append(Paragraph("Additional document information", styles["Heading3"])) for item in data["EP"]["DG12"]["5C"]: try: tag_name = tagToName[item] except Exception: tag_name = item Story.append(Paragraph("<font size=12> "+tag_name+": "+getItemRaw(data["EP"], 'DG12', item)+"</font>", styles["Normal"])) Story.append(Spacer(1, 12)) if data["EP"].has_key("DG13"): Story.append(Paragraph("Reserved for national specific data", styles["Heading3"])) for item in data["EP"]["DG13"]["5C"]: try: tag_name = tagToName[item] except Exception: tag_name = item Story.append(Paragraph("<font size=12> "+tag_name+": "+getItemRaw(data["EP"], 'DG13', item)+"</font>", styles["Normal"])) Story.append(Spacer(1, 12)) Story.append(Spacer(1, 12)) Story.append(Paragraph("Passive Authentication", styles["Heading2"])) Story.append(Paragraph("DG integrity:", styles["Heading3"])) for dgi in data["Integrity"]: if data["Integrity"][dgi] == True: v = "Verified" elif data["Integrity"][dgi] == False: v = "Not verified" elif data["Integrity"][dgi] == None: v = "No hash present in SOD for this EF" else: v = "N/A" Story.append(Paragraph("<font size=12> "+dgi+": "+v+"</font>", styles["Normal"])) Story.append(Paragraph("DG hashes:", styles["Heading3"])) for dgi in data["Hashes"]: Story.append(Paragraph("<font size=12> "+dgi + ": " + binToHexRep(data["Hashes"][dgi])+"</font>", styles["Normal"])) Story.append(Paragraph("SOD", styles["Heading3"])) Story.append(Paragraph("<font size=10>"+data["SOD"].replace("\n", "<br/>")+"</font>", styles["Normal"])) Story.append(Paragraph("Certificate", styles["Heading3"])) Story.append(Paragraph("<font size=12>Certificate Serial Number:"+data["certSerialNumber"]+"</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Certificate Fingerprint:"+data["certFingerPrint"]+"</font>", styles["Normal"])) Story.append(Paragraph("Document Signer", styles["Heading3"])) data["DSCertificate"] = data["DSCertificate"].replace("\n", "<br/>") data["DSCertificate"] = data["DSCertificate"].replace(" ", " ") Story.append(Paragraph("<font size=10>"+data["DSCertificate"]+"</font>", styles["Normal"])) Story.append(Spacer(1, 12)) Story.append(Paragraph("Active Authentication", styles["Heading2"])) Story.append(Paragraph("<font size=12>Active Authentication executed:"+data["activeAuth"]+"</font>", styles["Normal"])) Story.append(Paragraph("Public Key", styles["Heading3"])) data["pubKey"] = data["pubKey"].replace("\n", "<br/>") data["pubKey"] = data["pubKey"].replace(" ", " ") Story.append(Paragraph("<font size=10>"+data["pubKey"]+"</font>", styles["Normal"])) Story.append(Paragraph("Extended Access Control", styles["Heading2"])) Story.append(Paragraph("<font size=12>EAC has not been implemented yet.</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Here is of DG that the reader cannot access:</font>", styles["Normal"])) for fdg in data["failedToRead"]: Story.append(Paragraph("<font size=12> - " + fdg + "</font>", styles["Normal"])) if not data["failedToRead"]: Story.append(Paragraph("<font size=12> List empty: No EAC implemented in passport</font>", styles["Normal"])) Story.append(Spacer(1, 12)) Story.append(Paragraph("Security investigation", styles["Heading2"])) Story.append(Paragraph("Security measures", styles["Heading3"])) Story.append(Paragraph("<font size=12>Delay security measure after a wrong BAC: " + str(data["delaySecurity"]) + "</font>", styles["Normal"])) Story.append(Paragraph("<font size=12>Block the communication after a wrong BAC: " + str(data["blockAfterFail"]) + "</font>", styles["Normal"])) Story.append(Paragraph("Potential vulnerabilities", styles["Heading3"])) (vuln, ans) = data["activeAuthWithoutBac"] Story.append(Paragraph("<font size=12>Active Authentication before BAC: " + str(vuln) + "</font>", styles["Normal"])) if vuln: Story.append(Paragraph("<font size=12> * Vulnerable to AA Traceability</font>", styles["Normal"])) Story.append(Spacer(1, 12)) Story.append(Paragraph("<font size=12>Different response time for wrong message or MAC: " + str(data["macTraceability"]) + "</font>", styles["Normal"])) if data["macTraceability"]: Story.append(Paragraph("<font size=12> * Vulnerable to MAC traceability</font>", styles["Normal"])) Story.append(Paragraph("<font size=12> Note: If delay security measure implemented, this might be a false positive</font>", styles["Normal"])) Story.append(Spacer(1, 12)) (vuln, error) = data["getChallengeNull"] Story.append(Paragraph("<font size=12>Passport answers to a GET CHALLENGE with the Le set to '01': " + str(vuln) + "</font>", styles["Normal"])) if vuln: Story.append(Paragraph("<font size=12> * Vulnerable to lookup brute force</font>", styles["Normal"])) Story.append(Paragraph("Error Fingerprinting", styles["Heading3"])) for ins in data["Errors"]: Story.append(Paragraph('<font size=12>APDU "00" "' + ins + '" "00" "00" "" "" "00": ' + data["Errors"][ins] + "</font>", styles["Normal"])) doc.build(Story) if tag != None: os.remove(profile) try: os.remove(signature) except NameError: pass
def toPDF(data, filename): """ Export doc9303 instance to PDF @param doc: doc9303 @type doc: doc9303 instance (pyPassport) @param filename: output file @type filename: String @return: None """ doc = SimpleDocTemplate(filename, pagesize=letter, rightMargin=72, leftMargin=72, topMargin=72, bottomMargin=18) Story = [] styles = getSampleStyleSheet() # NAME name = (data["EP"]["DG1"]["5F5B"]).split("<<") Story.append( Paragraph( getItem(name[1].upper()) + " " + getItem(name[0].upper()), styles["Heading1"])) # PICTURE tag = None if data["EP"]["DG2"]["A1"].has_key("5F2E"): tag = "5F2E" elif data["EP"]["DG2"]["A1"].has_key("7F2E"): tag = "7F2E" if tag != None: path = None raw = data["EP"]["DG2"]["A1"][tag] profile = writeImageToDisk(raw, "~picture") img_file = PIL.Image.open(profile) width, height = img_file.size ratio = float(width) / float(2 * inch) h_img = float(height) / ratio im = Image(profile, 2 * inch, h_img) Story.append(im) try: if data["EP"].has_key("DG7") and data["EP"]["DG7"].has_key("5F43"): raw = data["EP"]["DG7"]["5F43"][0] signature = writeImageToDisk(raw, "~signature") img_signature = PIL.Image.open(signature) width, height = img_signature.size ratio = float(width) / float(2 * inch) h_img = float(height) / ratio sign = Image(signature, 2 * inch, h_img) Story.append(sign) except Exception: pass # OVERVIEW Story.append(Paragraph("Overview", styles["Heading2"])) Story.append( Paragraph( "<font size=12>Type: " + getItemByTag(data["EP"], 'DG1', '5F03') + "</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Passport #: " + str(getItemByTag(data["EP"], 'DG1', '5A')) + "</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Country: " + str(getItemByTag(data["EP"], 'DG1', '5F28')) + "</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Authority: " + str(getItemByTag(data["EP"], 'DG12', '5F19')) + "</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Issue Date: " + str(getItemByTag(data["EP"], 'DG12', '5F26')) + "</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Expiry Place: " + str(getItemByTag(data["EP"], 'DG1', '59')) + "</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Nationality: " + str(getItemByTag(data["EP"], 'DG1', '5F2C')) + "</font>", styles["Normal"])) Story.append(Spacer(1, 12)) Story.append( Paragraph("<font size=12>Name: " + str(getItem(name[0])) + "</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Surname: " + str(getItem(name[1])) + "</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Birth Date: " + str(getItemByTag(data["EP"], 'DG1', '5F57')) + "</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Birth Place: " + str(getItemByTag(data["EP"], 'DG11', '5F11')) + "</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Sex: " + str(getItemByTag(data["EP"], 'DG1', '5F35')) + "</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Height: " + str(getItemByTag(data["EP"], 'DG13', '9F01')) + "</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Colour of eyes: " + str(getItemByTag(data["EP"], 'DG13', '9F02')) + "</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Residence: " + str(getItemByTag(data["EP"], 'DG13', '9F03')) + "</font>", styles["Normal"])) Story.append(Spacer(1, 12)) Story.append(Paragraph("Basic Access Control", styles["Heading2"])) Story.append( Paragraph( "<font size=12>Basic Access Control: " + data["bac"] + "</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Reading time: " + str(data["ReadingTime"]) + "</font>", styles["Normal"])) Story.append( Paragraph("<font size=12>Data Groups size:</font>", styles["Normal"])) for key, value in data["DGs"]: Story.append( Paragraph( "<font size=12>  - " + str(key) + ": " + str(value) + " octets" + "</font>", styles["Normal"])) # PRESENT DATAGROUPS #Story.append(Paragraph("Present DataGroups", styles["Heading2"])) #k = map(toOrder, data["EP"].keys()) #k.sort() #k = map(toDG,k) #for dg in k: # Story.append(Paragraph("<font size=12> - "+str(dg)+"</font>", styles["Normal"])) #Story.append(Spacer(1, 20)) # DUMP Story.append(Paragraph("MRZ information", styles["Heading3"])) for item in data["EP"]["DG1"]: try: tag_name = tagToName[item] except Exception: tag_name = item Story.append( Paragraph( "<font size=12> " + tag_name + ": " + getItemRaw(data["EP"], 'DG1', item) + "</font>", styles["Normal"])) Story.append(Spacer(1, 12)) if data["EP"].has_key("DG11"): Story.append( Paragraph("Additional document holder details", styles["Heading3"])) for item in data["EP"]["DG11"]["5C"]: try: tag_name = tagToName[item] except Exception: tag_name = item Story.append( Paragraph( "<font size=12> " + tag_name + ": " + getItemRaw(data["EP"], 'DG11', item) + "</font>", styles["Normal"])) Story.append(Spacer(1, 12)) if data["EP"].has_key("DG12"): Story.append( Paragraph("Additional document information", styles["Heading3"])) for item in data["EP"]["DG12"]["5C"]: try: tag_name = tagToName[item] except Exception: tag_name = item Story.append( Paragraph( "<font size=12> " + tag_name + ": " + getItemRaw(data["EP"], 'DG12', item) + "</font>", styles["Normal"])) Story.append(Spacer(1, 12)) if data["EP"].has_key("DG13"): Story.append( Paragraph("Reserved for national specific data", styles["Heading3"])) for item in data["EP"]["DG13"]["5C"]: try: tag_name = tagToName[item] except Exception: tag_name = item Story.append( Paragraph( "<font size=12> " + tag_name + ": " + getItemRaw(data["EP"], 'DG13', item) + "</font>", styles["Normal"])) Story.append(Spacer(1, 12)) Story.append(Spacer(1, 12)) Story.append(Paragraph("Passive Authentication", styles["Heading2"])) Story.append(Paragraph("DG integrity:", styles["Heading3"])) for dgi in data["Integrity"]: if data["Integrity"][dgi] == True: v = "Verified" elif data["Integrity"][dgi] == False: v = "Not verified" elif data["Integrity"][dgi] == None: v = "No hash present in SOD for this EF" else: v = "N/A" Story.append( Paragraph("<font size=12> " + dgi + ": " + v + "</font>", styles["Normal"])) Story.append(Paragraph("DG hashes:", styles["Heading3"])) for dgi in data["Hashes"]: Story.append( Paragraph( "<font size=12> " + dgi + ": " + binToHexRep(data["Hashes"][dgi]) + "</font>", styles["Normal"])) Story.append(Paragraph("SOD", styles["Heading3"])) Story.append( Paragraph( "<font size=10>" + data["SOD"].replace("\n", "<br/>") + "</font>", styles["Normal"])) Story.append(Paragraph("Certificate", styles["Heading3"])) Story.append( Paragraph( "<font size=12>Certificate Serial Number:" + data["certSerialNumber"] + "</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Certificate Fingerprint:" + data["certFingerPrint"] + "</font>", styles["Normal"])) Story.append(Paragraph("Document Signer", styles["Heading3"])) data["DSCertificate"] = data["DSCertificate"].replace("\n", "<br/>") data["DSCertificate"] = data["DSCertificate"].replace(" ", " ") Story.append( Paragraph("<font size=10>" + data["DSCertificate"] + "</font>", styles["Normal"])) Story.append(Spacer(1, 12)) Story.append(Paragraph("Active Authentication", styles["Heading2"])) Story.append( Paragraph( "<font size=12>Active Authentication executed:" + data["activeAuth"] + "</font>", styles["Normal"])) Story.append(Paragraph("Public Key", styles["Heading3"])) data["pubKey"] = data["pubKey"].replace("\n", "<br/>") data["pubKey"] = data["pubKey"].replace(" ", " ") Story.append( Paragraph("<font size=10>" + data["pubKey"] + "</font>", styles["Normal"])) Story.append(Paragraph("Extended Access Control", styles["Heading2"])) Story.append( Paragraph("<font size=12>EAC has not been implemented yet.</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Here is of DG that the reader cannot access:</font>", styles["Normal"])) for fdg in data["failedToRead"]: Story.append( Paragraph("<font size=12> - " + fdg + "</font>", styles["Normal"])) if not data["failedToRead"]: Story.append( Paragraph( "<font size=12> List empty: No EAC implemented in passport</font>", styles["Normal"])) Story.append(Spacer(1, 12)) Story.append(Paragraph("Security investigation", styles["Heading2"])) Story.append(Paragraph("Security measures", styles["Heading3"])) Story.append( Paragraph( "<font size=12>Delay security measure after a wrong BAC: " + str(data["delaySecurity"]) + "</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12>Block the communication after a wrong BAC: " + str(data["blockAfterFail"]) + "</font>", styles["Normal"])) Story.append(Paragraph("Potential vulnerabilities", styles["Heading3"])) (vuln, ans) = data["activeAuthWithoutBac"] Story.append( Paragraph( "<font size=12>Active Authentication before BAC: " + str(vuln) + "</font>", styles["Normal"])) if vuln: Story.append( Paragraph( "<font size=12> * Vulnerable to AA Traceability</font>", styles["Normal"])) Story.append(Spacer(1, 12)) Story.append( Paragraph( "<font size=12>Different response time for wrong message or MAC: " + str(data["macTraceability"]) + "</font>", styles["Normal"])) if data["macTraceability"]: Story.append( Paragraph( "<font size=12> * Vulnerable to MAC traceability</font>", styles["Normal"])) Story.append( Paragraph( "<font size=12> Note: If delay security measure implemented, this might be a false positive</font>", styles["Normal"])) Story.append(Spacer(1, 12)) (vuln, error) = data["getChallengeNull"] Story.append( Paragraph( "<font size=12>Passport answers to a GET CHALLENGE with the Le set to '01': " + str(vuln) + "</font>", styles["Normal"])) if vuln: Story.append( Paragraph( "<font size=12> * Vulnerable to lookup brute force</font>", styles["Normal"])) Story.append(Paragraph("Error Fingerprinting", styles["Heading3"])) for ins in data["Errors"]: Story.append( Paragraph( '<font size=12>APDU "00" "' + ins + '" "00" "00" "" "" "00": ' + data["Errors"][ins] + "</font>", styles["Normal"])) doc.build(Story) if tag != None: os.remove(profile) try: os.remove(signature) except NameError: pass