Esempio n. 1
0
class CardGenerator(object):
    """This class is used to generate the SAM and filesystem for the
    different supported card types. It is also able used for persistent storage
    (in encrypted form) of the card on disks. """

    def __init__(self, card_type=None, sam=None, mf=None):
        self.type = card_type
        self.mf = mf
        self.sam = sam
        self.password = None
        self.datagroups = {}

    def __generate_iso_card(self):
        default_pin = "1234"
        default_cardno = "1234567890"

        logging.warning("Using default SAM parameters. PIN=%s, Card Nr=%s"
                        % (default_pin, default_cardno))
        # TODO: Use user provided data
        self.sam = SAM(default_pin, default_cardno)

        self.mf = MF(filedescriptor=FDB["DF"])
        self.sam.set_MF(self.mf)

    def __generate_ePass(self):
        """Generate the MF and SAM of an ICAO passport. This method is
        responsible for generating the filesystem and filling it with content.
        Therefore it must interact with the user by prompting for the MRZ and
        optionally for the path to a photo."""
        from PIL import Image
        from virtualsmartcard.cards.ePass import PassportSAM

        # TODO: Sanity checks
        MRZ = raw_input("Please enter the MRZ as one string: ")

        readline.set_completer_delims("")
        readline.parse_and_bind("tab: complete")

        picturepath = raw_input("Please enter the path to an image: ")
        picturepath = picturepath.strip()

        # MRZ1 = "P<UTOERIKSSON<<ANNA<MARIX<<<<<<<<<<<<<<<<<<<"
        # MRZ2 = "L898902C<3UTO6908061F9406236ZE184226B<<<<<14"
        # MRZ = MRZ1 + MRZ2

        try:
            im = Image.open(picturepath)
            pic_width, pic_height = im.size
            fd = open(picturepath, "rb")
            picture = fd.read()
            fd.close()
        except IOError:
            logging.warning("Failed to open file: " + picturepath)
            pic_width = 0
            pic_height = 0
            picture = None

        mf = MF()

        # We need a MF with Application DF \xa0\x00\x00\x02G\x10\x01
        df = DF(parent=mf, fid=4, dfname='\xa0\x00\x00\x02G\x10\x01',
                bertlv_data=[])

        # EF.COM
        COM = pack([(0x5F01, 4, "0107"), (0x5F36, 6, "040000"),
                    (0x5C, 2, "6175")])
        COM = pack(((0x60, len(COM), COM),))
        df.append(TransparentStructureEF(parent=df, fid=0x011E,
                  filedescriptor=0, data=COM))

        # EF.DG1
        DG1 = pack([(0x5F1F, len(MRZ), MRZ)])
        DG1 = pack([(0x61, len(DG1), DG1)])
        df.append(TransparentStructureEF(parent=df, fid=0x0101,
                  filedescriptor=0, data=DG1))

        # EF.DG2
        if picture is not None:
            IIB = "\x00\x01" + inttostring(pic_width, 2) +\
                    inttostring(pic_height, 2) + 6 * "\x00"
            length = 32 + len(picture)  # 32 is the length of IIB + FIB
            FIB = inttostring(length, 4) + 16 * "\x00"
            FRH = "FAC" + "\x00" + "010" + "\x00" +\
                  inttostring(14 + length, 4) + inttostring(1, 2)
            picture = FRH + FIB + IIB + picture
            DG2 = pack([(0xA1, 8, "\x87\x02\x01\x01\x88\x02\x05\x01"),
                       (0x5F2E, len(picture), picture)])
            DG2 = pack([(0x02, 1, "\x01"), (0x7F60, len(DG2), DG2)])
            DG2 = pack([(0x7F61, len(DG2), DG2)])
        else:
            DG2 = ""
        df.append(TransparentStructureEF(parent=df, fid=0x0102,
                  filedescriptor=0, data=DG2))

        # EF.SOD
        df.append(TransparentStructureEF(parent=df, fid=0x010D,
                  filedescriptor=0, data=""))

        mf.append(df)

        self.mf = mf
        self.sam = PassportSAM(self.mf)

    def __generate_nPA(self):
        from virtualsmartcard.cards.nPA import nPA_SAM
        mappings = [
            ('\x04\x00\x7f\x00\x07\x02\x02\x04', range(1, 5), range(1, 5),
             "PACE"),
            ('\x04\x00\x7f\x00\x07\x02\x02\x02', range(1, 3), range(1, 6),
             "TA"),
            ('\x04\x00\x7f\x00\x07\x02\x02\x02', [1], [6], "TA"),
            ('\x04\x00\x7f\x00\x07\x02\x02\x03', range(1, 3), range(1, 5),
             "CA"),
            ('\x04\x00\x7f\x00\x07\x02\x02\x05', range(1, 3), range(1, 6),
             "RI"),
        ]
        for oid_base, x_list, y_list, algo in mappings:
            for oid in [oid_base + chr(x) + chr(y) for x in x_list for y in
                        y_list]:
                ALGO_MAPPING[oid] = algo
        ALGO_MAPPING["\x04\x00\x7f\x00\x07\x03\x01\x04\x03"] = "CommunityID"
        ALGO_MAPPING["\x04\x00\x7f\x00\x07\x03\x01\x04\x02"] = "DateOfExpiry"
        ALGO_MAPPING["\x04\x00\x7f\x00\x07\x03\x01\x04\x01"] = "DateOfBirth"

        self.mf = MF()

        card_access = "\x31\x81\xb3\x30\x0d\x06\x08\x04\x00\x7f\x00\x07\x02"\
                      "\x02\x02\x02\x01\x02\x30\x12\x06\x0a\x04\x00\x7f\x00"\
                      "\x07\x02\x02\x03\x02\x02\x02\x01\x02\x02\x01\x41\x30"\
                      "\x12\x06\x0a\x04\x00\x7f\x00\x07\x02\x02\x03\x02\x02"\
                      "\x02\x01\x02\x02\x01\x45\x30\x12\x06\x0a\x04\x00\x7f"\
                      "\x00\x07\x02\x02\x04\x02\x02\x02\x01\x02\x02\x01\x0d"\
                      "\x30\x1c\x06\x09\x04\x00\x7f\x00\x07\x02\x02\x03\x02"\
                      "\x30\x0c\x06\x07\x04\x00\x7f\x00\x07\x01\x02\x02\x01"\
                      "\x0d\x02\x01\x41\x30\x1c\x06\x09\x04\x00\x7f\x00\x07"\
                      "\x02\x02\x03\x02\x30\x0c\x06\x07\x04\x00\x7f\x00\x07"\
                      "\x01\x02\x02\x01\x0d\x02\x01\x45\x30\x2a\x06\x08\x04"\
                      "\x00\x7f\x00\x07\x02\x02\x06\x16\x1e\x68\x74\x74\x70"\
                      "\x3a\x2f\x2f\x62\x73\x69\x2e\x62\x75\x6e\x64\x2e\x64"\
                      "\x65\x2f\x63\x69\x66\x2f\x6e\x70\x61\x2e\x78\x6d\x6c"
        self.mf.append(TransparentStructureEF(parent=self.mf, fid=0x011c,
                       shortfid=0x1c, data=card_access))
        card_security = "\x30\x82\x05\xA0\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01"\
                        "\x07\x02\xA0\x82\x05\x91\x30\x82\x05\x8D\x02\x01\x03"\
                        "\x31\x0F\x30\x0D\x06\x09\x60\x86\x48\x01\x65\x03\x04"\
                        "\x02\x01\x05\x00\x30\x82\x01\x48\x06\x08\x04\x00\x7F"\
                        "\x00\x07\x03\x02\x01\xA0\x82\x01\x3A\x04\x82\x01\x36"\
                        "\x31\x82\x01\x32\x30\x0D\x06\x08\x04\x00\x7F\x00\x07"\
                        "\x02\x02\x02\x02\x01\x02\x30\x12\x06\x0A\x04\x00\x7F"\
                        "\x00\x07\x02\x02\x03\x02\x02\x02\x01\x02\x02\x01\x41"\
                        "\x30\x12\x06\x0A\x04\x00\x7F\x00\x07\x02\x02\x04\x02"\
                        "\x02\x02\x01\x02\x02\x01\x0D\x30\x17\x06\x0A\x04\x00"\
                        "\x7F\x00\x07\x02\x02\x05\x02\x03\x30\x09\x02\x01\x01"\
                        "\x02\x01\x43\x01\x01\xFF\x30\x17\x06\x0A\x04\x00\x7F"\
                        "\x00\x07\x02\x02\x05\x02\x03\x30\x09\x02\x01\x01\x02"\
                        "\x01\x44\x01\x01\x00\x30\x19\x06\x09\x04\x00\x7F\x00"\
                        "\x07\x02\x02\x05\x02\x30\x0C\x06\x07\x04\x00\x7F\x00"\
                        "\x07\x01\x02\x02\x01\x0D\x30\x1C\x06\x09\x04\x00\x7F"\
                        "\x00\x07\x02\x02\x03\x02\x30\x0C\x06\x07\x04\x00\x7F"\
                        "\x00\x07\x01\x02\x02\x01\x0D\x02\x01\x41\x30\x2A\x06"\
                        "\x08\x04\x00\x7F\x00\x07\x02\x02\x06\x16\x1E\x68\x74"\
                        "\x74\x70\x3A\x2F\x2F\x62\x73\x69\x2E\x62\x75\x6E\x64"\
                        "\x2E\x64\x65\x2F\x63\x69\x66\x2F\x6E\x70\x61\x2E\x78"\
                        "\x6D\x6C\x30\x62\x06\x09\x04\x00\x7F\x00\x07\x02\x02"\
                        "\x01\x02\x30\x52\x30\x0C\x06\x07\x04\x00\x7F\x00\x07"\
                        "\x01\x02\x02\x01\x0D\x03\x42\x00\x04\x92\x5D\xB4\xE1"\
                        "\x7A\xDE\x58\x20\x9F\x96\xFA\xA0\x7F\x1F\x8A\x22\x3F"\
                        "\x82\x3F\x96\xCC\x5D\x78\xCB\xEF\x5D\x17\x42\x20\x88"\
                        "\xFD\xD5\x8E\x56\xBC\x42\x50\xDE\x33\x46\xB3\xC8\x32"\
                        "\xCA\xE4\x86\x35\xFB\x6C\x43\x78\x9D\xE8\xB3\x10\x2F"\
                        "\x43\x93\xB4\x18\xE2\x4A\x13\xD9\x02\x01\x41\xA0\x82"\
                        "\x03\x1C\x30\x82\x03\x18\x30\x82\x02\xBC\xA0\x03\x02"\
                        "\x01\x02\x02\x02\x01\x5C\x30\x0C\x06\x08\x2A\x86\x48"\
                        "\xCE\x3D\x04\x03\x02\x05\x00\x30\x4F\x31\x0B\x30\x09"\
                        "\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x0D\x30\x0B"\
                        "\x06\x03\x55\x04\x0A\x0C\x04\x62\x75\x6E\x64\x31\x0C"\
                        "\x30\x0A\x06\x03\x55\x04\x0B\x0C\x03\x62\x73\x69\x31"\
                        "\x0C\x30\x0A\x06\x03\x55\x04\x05\x13\x03\x30\x31\x33"\
                        "\x31\x15\x30\x13\x06\x03\x55\x04\x03\x0C\x0C\x63\x73"\
                        "\x63\x61\x2D\x67\x65\x72\x6D\x61\x6E\x79\x30\x1E\x17"\
                        "\x0D\x31\x30\x31\x30\x30\x35\x31\x31\x30\x37\x35\x32"\
                        "\x5A\x17\x0D\x32\x31\x30\x34\x30\x35\x30\x38\x33\x39"\
                        "\x34\x37\x5A\x30\x47\x31\x0B\x30\x09\x06\x03\x55\x04"\
                        "\x06\x13\x02\x44\x45\x31\x1D\x30\x1B\x06\x03\x55\x04"\
                        "\x0A\x0C\x14\x42\x75\x6E\x64\x65\x73\x64\x72\x75\x63"\
                        "\x6B\x65\x72\x65\x69\x20\x47\x6D\x62\x48\x31\x0C\x30"\
                        "\x0A\x06\x03\x55\x04\x05\x13\x03\x30\x37\x34\x31\x0B"\
                        "\x30\x09\x06\x03\x55\x04\x03\x0C\x02\x44\x53\x30\x82"\
                        "\x01\x13\x30\x81\xD4\x06\x07\x2A\x86\x48\xCE\x3D\x02"\
                        "\x01\x30\x81\xC8\x02\x01\x01\x30\x28\x06\x07\x2A\x86"\
                        "\x48\xCE\x3D\x01\x01\x02\x1D\x00\xD7\xC1\x34\xAA\x26"\
                        "\x43\x66\x86\x2A\x18\x30\x25\x75\xD1\xD7\x87\xB0\x9F"\
                        "\x07\x57\x97\xDA\x89\xF5\x7E\xC8\xC0\xFF\x30\x3C\x04"\
                        "\x1C\x68\xA5\xE6\x2C\xA9\xCE\x6C\x1C\x29\x98\x03\xA6"\
                        "\xC1\x53\x0B\x51\x4E\x18\x2A\xD8\xB0\x04\x2A\x59\xCA"\
                        "\xD2\x9F\x43\x04\x1C\x25\x80\xF6\x3C\xCF\xE4\x41\x38"\
                        "\x87\x07\x13\xB1\xA9\x23\x69\xE3\x3E\x21\x35\xD2\x66"\
                        "\xDB\xB3\x72\x38\x6C\x40\x0B\x04\x39\x04\x0D\x90\x29"\
                        "\xAD\x2C\x7E\x5C\xF4\x34\x08\x23\xB2\xA8\x7D\xC6\x8C"\
                        "\x9E\x4C\xE3\x17\x4C\x1E\x6E\xFD\xEE\x12\xC0\x7D\x58"\
                        "\xAA\x56\xF7\x72\xC0\x72\x6F\x24\xC6\xB8\x9E\x4E\xCD"\
                        "\xAC\x24\x35\x4B\x9E\x99\xCA\xA3\xF6\xD3\x76\x14\x02"\
                        "\xCD\x02\x1D\x00\xD7\xC1\x34\xAA\x26\x43\x66\x86\x2A"\
                        "\x18\x30\x25\x75\xD0\xFB\x98\xD1\x16\xBC\x4B\x6D\xDE"\
                        "\xBC\xA3\xA5\xA7\x93\x9F\x02\x01\x01\x03\x3A\x00\x04"\
                        "\x3D\x6A\x7C\x2A\x6F\x20\x5F\x83\x9B\x04\x14\xEC\x58"\
                        "\xC6\xC7\x1B\x75\xF5\x15\xDE\xC3\xAE\x73\x3B\x5F\x47"\
                        "\x88\xDD\xC8\x15\xF0\x5B\xC1\xF6\x53\x8F\xD9\x69\x54"\
                        "\xE1\xF8\x40\xA2\xE2\x18\x99\x62\xCC\xAA\x14\x90\x08"\
                        "\x24\xC7\xDD\xB9\xA3\x81\xD1\x30\x81\xCE\x30\x0E\x06"\
                        "\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x07\x80"\
                        "\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14"\
                        "\x60\x44\xF2\x45\xF2\xE0\x71\xD4\xD5\x64\xF4\xE5\x77"\
                        "\xD6\x36\x69\xDB\xEB\x18\x59\x30\x41\x06\x03\x55\x1D"\
                        "\x20\x04\x3A\x30\x38\x30\x36\x06\x09\x04\x00\x7F\x00"\
                        "\x07\x03\x01\x01\x01\x30\x29\x30\x27\x06\x08\x2B\x06"\
                        "\x01\x05\x05\x07\x02\x01\x16\x1B\x68\x74\x74\x70\x3A"\
                        "\x2F\x2F\x77\x77\x77\x2E\x62\x73\x69\x2E\x62\x75\x6E"\
                        "\x64\x2E\x64\x65\x2F\x63\x73\x63\x61\x30\x2B\x06\x09"\
                        "\x2A\x86\x48\x86\xF7\x0D\x01\x09\x15\x04\x1E\x04\x1C"\
                        "\x31\x2E\x32\x2E\x32\x37\x36\x2E\x30\x2E\x38\x30\x2E"\
                        "\x31\x2E\x31\x32\x2E\x30\x2E\x32\x30\x2E\x35\x2E\x31"\
                        "\x2E\x30\x30\x2B\x06\x03\x55\x1D\x10\x04\x24\x30\x22"\
                        "\x80\x0F\x32\x30\x31\x30\x31\x30\x30\x35\x31\x31\x30"\
                        "\x37\x35\x32\x5A\x81\x0F\x32\x30\x31\x31\x30\x32\x30"\
                        "\x35\x30\x39\x33\x39\x34\x37\x5A\x30\x0C\x06\x08\x2A"\
                        "\x86\x48\xCE\x3D\x04\x03\x02\x05\x00\x03\x48\x00\x30"\
                        "\x45\x02\x20\x13\xE9\xE1\x7A\x9E\xFE\x8B\xD7\xD7\x27"\
                        "\x62\x92\x30\x5B\xCC\xC3\x2B\x70\xC2\xB7\x60\x40\xF4"\
                        "\x88\x30\x66\x62\x26\xCD\x6A\x4B\xF4\x02\x21\x00\x87"\
                        "\xF4\x71\xE2\x44\x35\xB4\xC3\x4A\xF3\x57\x30\x94\xFB"\
                        "\x1F\x1C\x2A\x48\xB1\x3E\xE5\xED\x67\xF1\x72\x6D\xCF"\
                        "\x56\xE3\x84\xE3\x6F\x31\x82\x01\x09\x30\x82\x01\x05"\
                        "\x02\x01\x01\x30\x55\x30\x4F\x31\x0B\x30\x09\x06\x03"\
                        "\x55\x04\x06\x13\x02\x44\x45\x31\x0D\x30\x0B\x06\x03"\
                        "\x55\x04\x0A\x0C\x04\x62\x75\x6E\x64\x31\x0C\x30\x0A"\
                        "\x06\x03\x55\x04\x0B\x0C\x03\x62\x73\x69\x31\x0C\x30"\
                        "\x0A\x06\x03\x55\x04\x05\x13\x03\x30\x31\x33\x31\x15"\
                        "\x30\x13\x06\x03\x55\x04\x03\x0C\x0C\x63\x73\x63\x61"\
                        "\x2D\x67\x65\x72\x6D\x61\x6E\x79\x02\x02\x01\x5C\x30"\
                        "\x0D\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05"\
                        "\x00\xA0\x4A\x30\x17\x06\x09\x2A\x86\x48\x86\xF7\x0D"\
                        "\x01\x09\x03\x31\x0A\x06\x08\x04\x00\x7F\x00\x07\x03"\
                        "\x02\x01\x30\x2F\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01"\
                        "\x09\x04\x31\x22\x04\x20\xEF\x0F\xDA\x94\x2E\x5A\x0F"\
                        "\x6F\xC9\xC5\x46\xEE\x01\xF9\x10\x31\x43\x64\x30\xF7"\
                        "\x5E\x9D\x36\x54\xD3\x69\x30\x9E\x8B\xE7\x17\x48\x30"\
                        "\x0C\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x02\x05\x00"\
                        "\x04\x40\x30\x3E\x02\x1D\x00\x89\x75\x92\x5B\xE1\x31"\
                        "\xB7\x7C\x95\x8C\x3E\xCB\x2A\x5C\x67\xFC\x5C\xE3\x1C"\
                        "\xBD\x01\x41\xE3\x4B\xC7\xF0\xA4\x47\x02\x1D\x00\xCC"\
                        "\x65\xE6\x2D\xDC\xF2\x93\x96\x4B\x22\xD7\xB5\x10\xD7"\
                        "\x81\x88\x07\xC8\x95\x96\xBD\x34\xD8\xF9\xBB\x4C\x05"\
                        "\x27"
        self.mf.append(TransparentStructureEF(parent=self.mf, fid=0x011d,
                       shortfid=0x1d, data=card_security))
        ef_dir = "\x61\x32\x4F\x0F\xE8\x28\xBD\x08\x0F\xA0\x00\x00\x01\x67"\
                 "\x45\x53\x49\x47\x4E\x50\x0F\x43\x49\x41\x20\x7A\x75\x20"\
                 "\x44\x46\x2E\x65\x53\x69\x67\x6E\x51\x00\x73\x0C\x4F\x0A"\
                 "\xA0\x00\x00\x01\x67\x45\x53\x49\x47\x4E\x61\x09\x4F\x07"\
                 "\xA0\x00\x00\x02\x47\x10\x01\x61\x0B\x4F\x09\xE8\x07\x04"\
                 "\x00\x7F\x00\x07\x03\x02\x61\x0C\x4F\x0A\xA0\x00\x00\x01"\
                 "\x67\x45\x53\x49\x47\x4E"
        self.mf.append(TransparentStructureEF(parent=self.mf, fid=0x2f00,
                       shortfid=30, data=ef_dir))

        eid = DF(parent=self.mf, fid=0xffff,
                 dfname='\xe8\x07\x04\x00\x7f\x00\x07\x03\x02')
        eid.extra_fci_data = "\xab\x75\x84\x01\xa4\xaf\x70\xa0\x10\xb4\x06"\
                             "\x95\x01\x20\x83\x01\x04\xb4\x06\x95\x01\x20"\
                             "\x83\x01\x06\xa0\x54\xa4\x14\x95\x01\x80\x7f"\
                             "\x4c\x0e\x06\x09\x04\x00\x7f\x00\x07\x03\x01"\
                             "\x02\x01\x53\x01\x00\xaf\x22\xa4\x18\x95\x01"\
                             "\x80\x7f\x4c\x12\x06\x09\x04\x00\x7f\x00\x07"\
                             "\x03\x01\x02\x02\x53\x05\x00\x00\x00\x00\x00"\
                             "\xa4\x06\x95\x01\x80\x83\x01\x47\xa4\x18\x95"\
                             "\x01\x80\x7f\x4c\x12\x06\x09\x04\x00\x7f\x00"\
                             "\x07\x03\x01\x02\x02\x53\x05\x00\x00\x00\x00"\
                             "\x10\x7a\x06\x8a\x01\x05\x9e\x01\x03"
        # FIXME access control for eid application

        DocumentType = self.datagroups["DocumentType"] if "DocumentType" in \
            self.datagroups else 'ID'
        IssuingState = self.datagroups["IssuingState"] if "IssuingState" in \
            self.datagroups else 'D'
        DateOfExpiry = self.datagroups["DateOfExpiry"] if "DateOfExpiry" in \
            self.datagroups else '20201031'
        GivenNames = self.datagroups["GivenNames"] if "GivenNames" in \
            self.datagroups else 'ERIKA'
        FamilyNames = self.datagroups["FamilyNames"] if "FamilyNames" in \
            self.datagroups else 'MUSTERMANN'
        ReligiousArtisticName = self.datagroups["ReligiousArtisticName"] if \
            "ReligiousArtisticName" in self.datagroups else ''
        AcademicTitle = self.datagroups["AcademicTitle"] if \
            "AcademicTitle" in self.datagroups else ''
        DateOfBirth = self.datagroups["DateOfBirth"] if "DateOfBirth" in \
            self.datagroups else '19640812'
        PlaceOfBirth = self.datagroups["PlaceOfBirth"] if "PlaceOfBirth" in \
            self.datagroups else 'BERLIN'
        Nationality = self.datagroups["Nationality"] if "Nationality" in \
            self.datagroups else 'DE'
        Sex = self.datagroups["Sex"] if "Sex" in self.datagroups else 'F'
        BirthName = self.datagroups["BirthName"] if "BirthName" in \
            self.datagroups else 'Mein Geburtsname'
        # PlaceOfResidence variable is only a helper to get a switch for
        # <NotOnChip>
        PlaceOfResidence = self.datagroups["PlaceOfResidence"] if \
            "PlaceOfResidence" in self.datagroups else ''
        Country = self.datagroups["Country"] if "Country" in self.datagroups \
            else 'D'
        City = self.datagroups["City"] if "City" in self.datagroups else \
            'KOLN'
        ZIP = self.datagroups["ZIP"] if "ZIP" in self.datagroups else '51147'
        Street = self.datagroups["Street"] if "Street" in \
            self.datagroups else 'HEIDESTRASSE 17'
        CommunityID = self.datagroups["CommunityID"] if "CommunityID" in \
            self.datagroups else '02760378900276'
        if (CommunityID.rstrip() != "<NotOnChip>"):
            # the plain CommunityID integer value has to be translated into
            # its binary representation. '0276...' will be '\x02\x76\...'
            CommunityID_Binary = binascii.unhexlify(CommunityID)
        # ResidencePermit1 and ResidencePermit2 are part of eAT only
        ResidencePermit1 = self.datagroups["ResidencePermit1"] if \
            "ResidencePermit1" in self.datagroups else \
            'ResidencePermit1 field up to 750 characters'
        ResidencePermit2 = self.datagroups["ResidencePermit2"] if \
            "ResidencePermit2" in self.datagroups else \
            'ResidencePermit1 field up to 250 characters'

        # Currently, those data groups are for further usage:
        dg12_param = self.datagroups["dg12"] if "dg12" in \
            self.datagroups else ''
        dg14_param = self.datagroups["dg14"] if "dg14" in \
            self.datagroups else ''
        dg15_param = self.datagroups["dg15"] if "dg15" in \
            self.datagroups else ''
        dg16_param = self.datagroups["dg16"] if "dg16" in \
            self.datagroups else ''
        dg21_param = self.datagroups["dg21"] if "dg21" in \
            self.datagroups else ''

        # "Attribute not on Chip" makes sence only for ReligiousArtisticName,
        # Nationality, BirthName, ResidencePermit1 and ResidencePermit2, refer
        # to BSI TR-03127
        if (DocumentType.rstrip() != "<NotOnChip>"):
            dg1 = pack([(0x61, 0, [(0x13, 0, DocumentType)])], True)
        else:
            dg1 = None
        if (IssuingState.rstrip() != "<NotOnChip>"):
            dg2 = pack([(0x62, 0, [(0x13, 0, IssuingState)])], True)
        else:
            dg2 = None
        if (DateOfExpiry.rstrip() != "<NotOnChip>"):
            dg3 = pack([(0x63, 0, [(0x12, 0, DateOfExpiry)])], True)
        else:
            dg3 = None
        if (GivenNames.rstrip() != "<NotOnChip>"):
            dg4 = pack([(0x64, 0, [(0x0C, 0, GivenNames)])], True)
        else:
            dg4 = None
        if (FamilyNames.rstrip() != "<NotOnChip>"):
            dg5 = pack([(0x65, 0, [(0x0C, 0, FamilyNames)])], True)
        else:
            dg5 = None
        if (ReligiousArtisticName.rstrip() != "<NotOnChip>"):
            dg6 = pack([(0x66, 0, [(0x0C, 0, ReligiousArtisticName)])], True)
        else:
            dg6 = None
        if (AcademicTitle.rstrip() != "<NotOnChip>"):
            dg7 = pack([(0x67, 0, [(0x0C, 0, AcademicTitle)])], True)
        else:
            dg7 = None
        if (DateOfBirth.rstrip() != "<NotOnChip>"):
            dg8 = pack([(0x68, 0, [(0x12, 0, DateOfBirth)])], True)
        else:
            dg8 = None
        if (PlaceOfBirth.rstrip() != "<NotOnChip>"):
            dg9 = pack([(0x69, 0, [(0xA1, 0, [(0x0C, 0, PlaceOfBirth)])])],
                       True)
        else:
            dg9 = None
        if (Nationality.rstrip() != "<NotOnChip>"):
            dg10 = pack([(0x6A, 0, [(0x13, 0, Nationality)])], True)
        else:
            dg10 = None
        if (Sex.rstrip() != "<NotOnChip>"):
            dg11 = pack([(0x6B, 0, [(0x13, 0, Sex)])], True)
        else:
            dg11 = None
        if (dg12_param.rstrip() != "<NotOnChip>"):
            dg12 = dg12_param
        else:
            dg12 = None
        if (BirthName.rstrip() != "<NotOnChip>"):
            dg13 = pack([(0x6D, 0, [(0x0C, 0, BirthName)])], True)
        else:
            dg13 = None
        if (dg14_param.rstrip() != "<NotOnChip>"):
            dg14 = dg14_param
        else:
            dg14 = None
        if (dg15_param.rstrip() != "<NotOnChip>"):
            dg15 = dg15_param
        else:
            dg15 = None
        if (dg16_param.rstrip() != "<NotOnChip>"):
            dg16 = dg16_param
        else:
            dg16 = None
        if (PlaceOfResidence.rstrip() != "<NotOnChip>"):
            dg17 = pack([(0x71, 0, [(0x30, 0, [
                    (0xAA, 0, [(0x0C, 0, Street)]),
                    (0xAB, 0, [(0x0C, 0, City)]),
                    (0xAD, 0, [(0x13, 0, Country)]),
                    (0xAE, 0, [(0x13, 0, ZIP)])
                    ])])], True)
        else:
            dg17 = None
        if (CommunityID.rstrip() != "<NotOnChip>"):
            dg18 = pack([(0x72, 0, [(0x04, 0, CommunityID_Binary)])], True)
        else:
            dg18 = None
        if (ResidencePermit1.rstrip() != "<NotOnChip>"):
            dg19 = pack([(0x73, 0, [(0xA1, 0,
                                    [(0x0C, 0, ResidencePermit1)])])], True)
        else:
            dg19 = None
        if (ResidencePermit1.rstrip() != "<NotOnChip>"):
            dg20 = pack([(0x74, 0, [(0xA1, 0,
                                    [(0x0C, 0, ResidencePermit2)])])], True)
        else:
            dg20 = None
        if (dg21_param.rstrip() != "<NotOnChip>"):
            dg21 = dg21_param
        else:
            dg21 = None

        # If eid.append is not done for a DG, it results into required
        # SwError() with FileNotFound "6A82" APDU return code
        if dg1:
            eid.append(TransparentStructureEF(parent=eid, fid=0x0101,
                       shortfid=0x01, data=dg1))
        if dg2:
            eid.append(TransparentStructureEF(parent=eid, fid=0x0102,
                       shortfid=0x02, data=dg2))
        if dg3:
            eid.append(TransparentStructureEF(parent=eid, fid=0x0103,
                       shortfid=0x03, data=dg3))
        if dg4:
            eid.append(TransparentStructureEF(parent=eid, fid=0x0104,
                       shortfid=0x04, data=dg4))
        if dg5:
            eid.append(TransparentStructureEF(parent=eid, fid=0x0105,
                       shortfid=0x05, data=dg5))
        if dg6:
            eid.append(TransparentStructureEF(parent=eid, fid=0x0106,
                       shortfid=0x06, data=dg6))
        if dg7:
            eid.append(TransparentStructureEF(parent=eid, fid=0x0107,
                       shortfid=0x07, data=dg7))
        if dg8:
            eid.append(TransparentStructureEF(parent=eid, fid=0x0108,
                       shortfid=0x08, data=dg8))
        if dg9:
            eid.append(TransparentStructureEF(parent=eid, fid=0x0109,
                       shortfid=0x09, data=dg9))
        if dg10:
            eid.append(TransparentStructureEF(parent=eid, fid=0x010a,
                       shortfid=0x0a, data=dg10))
        if dg11:
            eid.append(TransparentStructureEF(parent=eid, fid=0x010b,
                       shortfid=0x0b, data=dg11))
        if dg12:
            eid.append(TransparentStructureEF(parent=eid, fid=0x010c,
                       shortfid=0x0c, data=dg12))
        if dg13:
            eid.append(TransparentStructureEF(parent=eid, fid=0x010d,
                       shortfid=0x0d, data=dg13))
        if dg14:
            eid.append(TransparentStructureEF(parent=eid, fid=0x010e,
                       shortfid=0x0e, data=dg14))
        if dg15:
            eid.append(TransparentStructureEF(parent=eid, fid=0x010f,
                       shortfid=0x0f, data=dg15))
        if dg16:
            eid.append(TransparentStructureEF(parent=eid, fid=0x0110,
                       shortfid=0x10, data=dg16))
        if dg17:
            eid.append(TransparentStructureEF(parent=eid, fid=0x0111,
                       shortfid=0x11, data=dg17))
        if dg18:
            eid.append(TransparentStructureEF(parent=eid, fid=0x0112,
                       shortfid=0x12, data=dg18))
        if dg19:
            eid.append(TransparentStructureEF(parent=eid, fid=0x0113,
                       shortfid=0x13, data=dg19))
        if dg20:
            eid.append(TransparentStructureEF(parent=eid, fid=0x0114,
                       shortfid=0x14, data=dg20))
        if dg21:
            eid.append(TransparentStructureEF(parent=eid, fid=0x0115,
                       shortfid=0x15, data=dg21))
        self.mf.append(eid)

        # DF.CIA
        cia = DF(parent=self.mf, fid=0xfffe,
                 dfname='\xE8\x28\xBD\x08\x0F\xA0\x00\x00\x01\x67\x45\x53\x49'
                        '\x47\x4E')
        # EF.OD / EF.ODF
        cia.append(TransparentStructureEF(parent=cia, fid=0x5031,
                                          shortfid=0x11,
                                          data='\xa0\x060\x04\x04\x02D\x00\xa4'
                                          '\x060\x04\x04\x02D\x04\xa8\x060\x04'
                                          '\x04\x02D\x08'))
        # EF.CIAInfo / EF.TokenInfo
        cia.append(TransparentStructureEF(parent=cia, fid=0x5032,
                                          shortfid=0x12,
                                          data='06\x02\x01\x01\x80\x11eSign '
                                          'Application\x03\x02\x06\xc0\xa2'
                                          '\x1a0\x18\x02\x01\x01\x02\x02\x10A'
                                          '\x05\x00\x03\x02\x06@\x06\t\x04\x00'
                                          '\x7f\x00\x07\x01\x01\x04\x01'))
        # EF.PrKD / EF.PrKDF
        cia.append(TransparentStructureEF(parent=cia, fid=0x4400,
                                          data='\xa080\x17\x0c\x0bPrK.ICC.QES'
                                          '\x03\x02\x07\x80\x04\x01\x01\x02'
                                          '\x01\x010\x15\x04\x01F\x03\x03\x06'
                                          '\x00@\x03\x02\x03\xb8\x02\x02\x00'
                                          '\x84\xa1\x03\x02\x01\x01\xa1\x060'
                                          '\x040\x02\x04\x00'))
        # EF.PuKD / EF.PuKDF
        cia.append(TransparentStructureEF(parent=cia, fid=0x4404,
                                          data='050!\x0c\x1fZertifikat des ZDA'
                                          ' f\xc3\xbcr die QES0\x06\x04\x01E'
                                          '\x01\x01\xff\xa1\x080\x060\x04\x04'
                                          '\x02\xc0\x000:0&\x0c$Zertifikat des'
                                          ' Inhabers f\xc3\xbcr die QES0\x06'
                                          '\x04\x01F\x01\x01\x00\xa1\x080\x060'
                                          '\x04\x04\x02\xc0\x01'))
        # EF.AOD / EF.AODF
        cia.append(TransparentStructureEF(parent=cia, fid=0x4408,
                                          data='0/0\x0f\x0c\teSign-PIN\x03\x02'
                                          '\x06@0\x03\x04\x01\x01\xa1\x170\x15'
                                          '\x03\x03\x02H\x1c\n\x01\x01\x02\x01'
                                          '\x06\x02\x01\x00\x80\x01\x810\x02'
                                          '\x04\x00'))
        self.mf.append(cia)

        # DF.eSign
        esign = DF(parent=self.mf, fid=0xfffd,
                   dfname='\xA0\x00\x00\x01\x67\x45\x53\x49\x47\x4E')

        # ZDA certificate
        esign.append(TransparentStructureEF(parent=esign, fid=0xC000, data=''))
        # User's certificate
        esign.append(TransparentStructureEF(parent=esign, fid=0xC001, data=''))
        self.mf.append(esign)

        self.sam = nPA_SAM(eid_pin="111111", can="222222",
                           mrz="IDD<<T220001293<<<<<<<<<<<<<<<6408125<2010315D"
                           "<<<<<<<<<<<<<<MUSTERMANN<<ERIKA<<<<<<<<<<<<<",
                           puk="3333333333", qes_pin="444444", mf=self.mf)
        # FIXME: add CVCA for inspection systems and signature terminals. Here
        #        we only add the eID CVCA.
        self.sam.current_SE.cvca = "\x7f\x21\x82\x01\xb6\x7f\x4e\x82\x01\x6e"\
                                   "\x5f\x29\x01\x00\x42\x0e\x44\x45\x43\x56"\
                                   "\x43\x41\x65\x49\x44\x30\x30\x31\x30\x32"\
                                   "\x7f\x49\x82\x01\x1d\x06\x0a\x04\x00\x7f"\
                                   "\x00\x07\x02\x02\x02\x02\x03\x81\x20\xa9"\
                                   "\xfb\x57\xdb\xa1\xee\xa9\xbc\x3e\x66\x0a"\
                                   "\x90\x9d\x83\x8d\x72\x6e\x3b\xf6\x23\xd5"\
                                   "\x26\x20\x28\x20\x13\x48\x1d\x1f\x6e\x53"\
                                   "\x77\x82\x20\x7d\x5a\x09\x75\xfc\x2c\x30"\
                                   "\x57\xee\xf6\x75\x30\x41\x7a\xff\xe7\xfb"\
                                   "\x80\x55\xc1\x26\xdc\x5c\x6c\xe9\x4a\x4b"\
                                   "\x44\xf3\x30\xb5\xd9\x83\x20\x26\xdc\x5c"\
                                   "\x6c\xe9\x4a\x4b\x44\xf3\x30\xb5\xd9\xbb"\
                                   "\xd7\x7c\xbf\x95\x84\x16\x29\x5c\xf7\xe1"\
                                   "\xce\x6b\xcc\xdc\x18\xff\x8c\x07\xb6\x84"\
                                   "\x41\x04\x8b\xd2\xae\xb9\xcb\x7e\x57\xcb"\
                                   "\x2c\x4b\x48\x2f\xfc\x81\xb7\xaf\xb9\xde"\
                                   "\x27\xe1\xe3\xbd\x23\xc2\x3a\x44\x53\xbd"\
                                   "\x9a\xce\x32\x62\x54\x7e\xf8\x35\xc3\xda"\
                                   "\xc4\xfd\x97\xf8\x46\x1a\x14\x61\x1d\xc9"\
                                   "\xc2\x77\x45\x13\x2d\xed\x8e\x54\x5c\x1d"\
                                   "\x54\xc7\x2f\x04\x69\x97\x85\x20\xa9\xfb"\
                                   "\x57\xdb\xa1\xee\xa9\xbc\x3e\x66\x0a\x90"\
                                   "\x9d\x83\x8d\x71\x8c\x39\x7a\xa3\xb5\x61"\
                                   "\xa6\xf7\x90\x1e\x0e\x82\x97\x48\x56\xa7"\
                                   "\x86\x41\x04\x33\x47\xec\xf9\x6f\xfb\x4b"\
                                   "\xd9\xb8\x55\x4e\xfb\xcc\xfc\x7d\x0b\x24"\
                                   "\x2f\x10\x71\xe2\x9b\x4c\x9c\x62\x2c\x79"\
                                   "\xe3\x39\xd8\x40\xaf\x67\xbe\xb9\xb9\x12"\
                                   "\x69\x22\x65\xd9\xc1\x6c\x62\x57\x3f\x45"\
                                   "\x79\xff\xd4\xde\x2d\xe9\x2b\xab\x40\x9d"\
                                   "\xd5\xc5\xd4\x82\x44\xa9\xf7\x87\x01\x01"\
                                   "\x5f\x20\x0e\x44\x45\x43\x56\x43\x41\x65"\
                                   "\x49\x44\x30\x30\x31\x30\x32\x7f\x4c\x12"\
                                   "\x06\x09\x04\x00\x7f\x00\x07\x03\x01\x02"\
                                   "\x02\x53\x05\xfe\x0f\x01\xff\xff\x5f\x25"\
                                   "\x06\x01\x00\x01\x00\x01\x08\x5f\x24\x06"\
                                   "\x01\x03\x01\x00\x01\x08\x5f\x37\x40\x50"\
                                   "\x67\x14\x5c\x68\xca\xe9\x52\x0f\x5b\xb3"\
                                   "\x48\x17\xf1\xca\x9c\x43\x59\x3d\xb5\x64"\
                                   "\x06\xc6\xa3\xb0\x06\xcb\xf3\xf3\x14\xe7"\
                                   "\x34\x9a\xcf\x0c\xc6\xbf\xeb\xcb\xde\xfd"\
                                   "\x10\xb4\xdc\xf0\xf2\x31\xda\x56\x97\x7d"\
                                   "\x88\xf9\xf9\x01\x82\xd1\x99\x07\x6a\x56"\
                                   "\x50\x64\x51"

    def __generate_cryptoflex(self):
        """Generate the Filesystem and SAM of a cryptoflex card"""
        from virtualsmartcard.cards.cryptoflex import CryptoflexMF
        from virtualsmartcard.cards.cryptoflex import CryptoflexSAM
        self.mf = CryptoflexMF()
        self.mf.append(TransparentStructureEF(parent=self.mf, fid=0x0002,
                       filedescriptor=0x01,
                       data="\x00\x00\x00\x01\x00\x01\x00\x00"))  # EF.ICCSN
        self.sam = CryptoflexSAM(self.mf)

    def generateCard(self):
        """Generate a new card"""
        if self.type == 'iso7816':
            self.__generate_iso_card()
        elif self.type == 'ePass':
            self.__generate_ePass()
        elif self.type == 'cryptoflex':
            self.__generate_cryptoflex()
        elif self.type == 'nPA':
            self.__generate_nPA()
        else:
            return (None, None)

    def getCard(self):
        """Get the MF and SAM from the current card"""
        if self.sam is None or self.mf is None:
            self.generateCard()
        return self.mf, self.sam

    def setCard(self, mf=None, sam=None):
        """Set the MF and SAM of the current card"""
        if mf is not None:
            self.mf = mf
        if sam is not None:
            self.sam = sam

    def readDatagroups(self, datasetfile):
        """Read Datagroups from file"""
        with open(datasetfile, 'r') as f:
            for line in f:
                if (not line.startswith("#")) and (not len(line.strip()) == 0):
                    # spaces after equal sign are allowed to get strings with
                    # leading spaces
                    line = line.replace(" =", "=")
                    splitLine = line.split("=")
                    # we don't want to have the newline char from dataset file
                    # as part of the value
                    self.datagroups[splitLine[0]] = splitLine[1].rstrip("\n\r")
                    logging.info("Dataset value for " + splitLine[0].rstrip() +
                                 ": '" + splitLine[1].rstrip("\n\r") + "'")
Esempio n. 2
0
class CardGenerator(object):
    """This class is used to generate the SAM and filesystem for the 
    different supported card types. It is also able used for persistent storage
    (in encrypted form) of the card on disks. """
    def __init__(self, card_type=None, sam=None, mf=None):
        self.type = card_type
        self.mf = mf
        self.sam = sam
        self.password = None
        self.datagroups = {}

    def __generate_iso_card(self):
        default_pin = "1234"
        default_cardno = "1234567890"

        logging.warning("Using default SAM parameters. PIN=%s, Card Nr=%s" %
                        (default_pin, default_cardno))
        #TODO: Use user provided data
        self.sam = SAM(default_pin, default_cardno)

        self.mf = MF(filedescriptor=FDB["DF"])
        self.sam.set_MF(self.mf)

    def __generate_ePass(self):
        """Generate the MF and SAM of an ICAO passport. This method is 
        responsible for generating the filesystem and filling it with content.
        Therefore it must interact with the user by prompting for the MRZ and
        optionally for the path to a photo."""
        from PIL import Image
        from virtualsmartcard.cards.ePass import PassportSAM

        #TODO: Sanity checks
        MRZ = raw_input("Please enter the MRZ as one string: ")

        readline.set_completer_delims("")
        readline.parse_and_bind("tab: complete")

        picturepath = raw_input("Please enter the path to an image: ")
        picturepath = picturepath.strip()

        #MRZ1 = "P<UTOERIKSSON<<ANNA<MARIX<<<<<<<<<<<<<<<<<<<"
        #MRZ2 = "L898902C<3UTO6908061F9406236ZE184226B<<<<<14"
        #MRZ = MRZ1 + MRZ2

        try:
            im = Image.open(picturepath)
            pic_width, pic_height = im.size
            fd = open(picturepath, "rb")
            picture = fd.read()
            fd.close()
        except IOError:
            logging.warning("Failed to open file: " + picturepath)
            pic_width = 0
            pic_height = 0
            picture = None

        mf = MF()

        #We need a MF with Application DF \xa0\x00\x00\x02G\x10\x01
        df = DF(parent=mf,
                fid=4,
                dfname='\xa0\x00\x00\x02G\x10\x01',
                bertlv_data=[])

        #EF.COM
        COM = pack([(0x5F01, 4, "0107"), (0x5F36, 6, "040000"),
                    (0x5C, 2, "6175")])
        COM = pack(((0x60, len(COM), COM), ))
        df.append(
            TransparentStructureEF(parent=df,
                                   fid=0x011E,
                                   filedescriptor=0,
                                   data=COM))

        #EF.DG1
        DG1 = pack([(0x5F1F, len(MRZ), MRZ)])
        DG1 = pack([(0x61, len(DG1), DG1)])
        df.append(
            TransparentStructureEF(parent=df,
                                   fid=0x0101,
                                   filedescriptor=0,
                                   data=DG1))

        #EF.DG2
        if picture != None:
            IIB = "\x00\x01" + inttostring(pic_width, 2) +\
                    inttostring(pic_height, 2) + 6 * "\x00"
            length = 32 + len(picture)  #32 is the length of IIB + FIB
            FIB = inttostring(length, 4) + 16 * "\x00"
            FRH = "FAC" + "\x00" + "010" + "\x00" +\
                    inttostring(14 + length, 4) + inttostring(1, 2)
            picture = FRH + FIB + IIB + picture
            DG2 = pack([(0xA1, 8, "\x87\x02\x01\x01\x88\x02\x05\x01"),
                        (0x5F2E, len(picture), picture)])
            DG2 = pack([(0x02, 1, "\x01"), (0x7F60, len(DG2), DG2)])
            DG2 = pack([(0x7F61, len(DG2), DG2)])
        else:
            DG2 = ""
        df.append(
            TransparentStructureEF(parent=df,
                                   fid=0x0102,
                                   filedescriptor=0,
                                   data=DG2))

        #EF.SOD
        df.append(
            TransparentStructureEF(parent=df,
                                   fid=0x010D,
                                   filedescriptor=0,
                                   data=""))

        mf.append(df)

        self.mf = mf
        self.sam = PassportSAM(self.mf)

    def __generate_nPA(self):
        from virtualsmartcard.cards.nPA import nPA_SAM
        for oid_base, x_list, y_list, algo in [
            ('\x04\x00\x7f\x00\x07\x02\x02\x04', range(1,
                                                       5), range(1,
                                                                 5), "PACE"),
            ('\x04\x00\x7f\x00\x07\x02\x02\x02', range(1, 3), range(1,
                                                                    6), "TA"),
            ('\x04\x00\x7f\x00\x07\x02\x02\x02', [1], [6], "TA"),
            ('\x04\x00\x7f\x00\x07\x02\x02\x03', range(1, 3), range(1,
                                                                    5), "CA"),
            ('\x04\x00\x7f\x00\x07\x02\x02\x05', range(1, 3), range(1,
                                                                    6), "RI"),
        ]:
            for oid in [
                    oid_base + chr(x) + chr(y) for x in x_list for y in y_list
            ]:
                ALGO_MAPPING[oid] = algo
        ALGO_MAPPING["\x04\x00\x7f\x00\x07\x03\x01\x04\x03"] = "CommunityID"
        ALGO_MAPPING["\x04\x00\x7f\x00\x07\x03\x01\x04\x02"] = "DateOfExpiry"
        ALGO_MAPPING["\x04\x00\x7f\x00\x07\x03\x01\x04\x01"] = "DateOfBirth"

        self.mf = MF()

        card_access = "\x31\x81\xb3\x30\x0d\x06\x08\x04\x00\x7f\x00\x07\x02\x02\x02\x02\x01\x02\x30\x12\x06\x0a\x04\x00\x7f\x00\x07\x02\x02\x03\x02\x02\x02\x01\x02\x02\x01\x41\x30\x12\x06\x0a\x04\x00\x7f\x00\x07\x02\x02\x03\x02\x02\x02\x01\x02\x02\x01\x45\x30\x12\x06\x0a\x04\x00\x7f\x00\x07\x02\x02\x04\x02\x02\x02\x01\x02\x02\x01\x0d\x30\x1c\x06\x09\x04\x00\x7f\x00\x07\x02\x02\x03\x02\x30\x0c\x06\x07\x04\x00\x7f\x00\x07\x01\x02\x02\x01\x0d\x02\x01\x41\x30\x1c\x06\x09\x04\x00\x7f\x00\x07\x02\x02\x03\x02\x30\x0c\x06\x07\x04\x00\x7f\x00\x07\x01\x02\x02\x01\x0d\x02\x01\x45\x30\x2a\x06\x08\x04\x00\x7f\x00\x07\x02\x02\x06\x16\x1e\x68\x74\x74\x70\x3a\x2f\x2f\x62\x73\x69\x2e\x62\x75\x6e\x64\x2e\x64\x65\x2f\x63\x69\x66\x2f\x6e\x70\x61\x2e\x78\x6d\x6c"
        self.mf.append(
            TransparentStructureEF(parent=self.mf,
                                   fid=0x011c,
                                   shortfid=0x1c,
                                   data=card_access))
        card_security = "\x30\x82\x05\xA0\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02\xA0\x82\x05\x91\x30\x82\x05\x8D\x02\x01\x03\x31\x0F\x30\x0D\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x30\x82\x01\x48\x06\x08\x04\x00\x7F\x00\x07\x03\x02\x01\xA0\x82\x01\x3A\x04\x82\x01\x36\x31\x82\x01\x32\x30\x0D\x06\x08\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x01\x02\x30\x12\x06\x0A\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x02\x02\x01\x02\x02\x01\x41\x30\x12\x06\x0A\x04\x00\x7F\x00\x07\x02\x02\x04\x02\x02\x02\x01\x02\x02\x01\x0D\x30\x17\x06\x0A\x04\x00\x7F\x00\x07\x02\x02\x05\x02\x03\x30\x09\x02\x01\x01\x02\x01\x43\x01\x01\xFF\x30\x17\x06\x0A\x04\x00\x7F\x00\x07\x02\x02\x05\x02\x03\x30\x09\x02\x01\x01\x02\x01\x44\x01\x01\x00\x30\x19\x06\x09\x04\x00\x7F\x00\x07\x02\x02\x05\x02\x30\x0C\x06\x07\x04\x00\x7F\x00\x07\x01\x02\x02\x01\x0D\x30\x1C\x06\x09\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x30\x0C\x06\x07\x04\x00\x7F\x00\x07\x01\x02\x02\x01\x0D\x02\x01\x41\x30\x2A\x06\x08\x04\x00\x7F\x00\x07\x02\x02\x06\x16\x1E\x68\x74\x74\x70\x3A\x2F\x2F\x62\x73\x69\x2E\x62\x75\x6E\x64\x2E\x64\x65\x2F\x63\x69\x66\x2F\x6E\x70\x61\x2E\x78\x6D\x6C\x30\x62\x06\x09\x04\x00\x7F\x00\x07\x02\x02\x01\x02\x30\x52\x30\x0C\x06\x07\x04\x00\x7F\x00\x07\x01\x02\x02\x01\x0D\x03\x42\x00\x04\x92\x5D\xB4\xE1\x7A\xDE\x58\x20\x9F\x96\xFA\xA0\x7F\x1F\x8A\x22\x3F\x82\x3F\x96\xCC\x5D\x78\xCB\xEF\x5D\x17\x42\x20\x88\xFD\xD5\x8E\x56\xBC\x42\x50\xDE\x33\x46\xB3\xC8\x32\xCA\xE4\x86\x35\xFB\x6C\x43\x78\x9D\xE8\xB3\x10\x2F\x43\x93\xB4\x18\xE2\x4A\x13\xD9\x02\x01\x41\xA0\x82\x03\x1C\x30\x82\x03\x18\x30\x82\x02\xBC\xA0\x03\x02\x01\x02\x02\x02\x01\x5C\x30\x0C\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x02\x05\x00\x30\x4F\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x0D\x30\x0B\x06\x03\x55\x04\x0A\x0C\x04\x62\x75\x6E\x64\x31\x0C\x30\x0A\x06\x03\x55\x04\x0B\x0C\x03\x62\x73\x69\x31\x0C\x30\x0A\x06\x03\x55\x04\x05\x13\x03\x30\x31\x33\x31\x15\x30\x13\x06\x03\x55\x04\x03\x0C\x0C\x63\x73\x63\x61\x2D\x67\x65\x72\x6D\x61\x6E\x79\x30\x1E\x17\x0D\x31\x30\x31\x30\x30\x35\x31\x31\x30\x37\x35\x32\x5A\x17\x0D\x32\x31\x30\x34\x30\x35\x30\x38\x33\x39\x34\x37\x5A\x30\x47\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x1D\x30\x1B\x06\x03\x55\x04\x0A\x0C\x14\x42\x75\x6E\x64\x65\x73\x64\x72\x75\x63\x6B\x65\x72\x65\x69\x20\x47\x6D\x62\x48\x31\x0C\x30\x0A\x06\x03\x55\x04\x05\x13\x03\x30\x37\x34\x31\x0B\x30\x09\x06\x03\x55\x04\x03\x0C\x02\x44\x53\x30\x82\x01\x13\x30\x81\xD4\x06\x07\x2A\x86\x48\xCE\x3D\x02\x01\x30\x81\xC8\x02\x01\x01\x30\x28\x06\x07\x2A\x86\x48\xCE\x3D\x01\x01\x02\x1D\x00\xD7\xC1\x34\xAA\x26\x43\x66\x86\x2A\x18\x30\x25\x75\xD1\xD7\x87\xB0\x9F\x07\x57\x97\xDA\x89\xF5\x7E\xC8\xC0\xFF\x30\x3C\x04\x1C\x68\xA5\xE6\x2C\xA9\xCE\x6C\x1C\x29\x98\x03\xA6\xC1\x53\x0B\x51\x4E\x18\x2A\xD8\xB0\x04\x2A\x59\xCA\xD2\x9F\x43\x04\x1C\x25\x80\xF6\x3C\xCF\xE4\x41\x38\x87\x07\x13\xB1\xA9\x23\x69\xE3\x3E\x21\x35\xD2\x66\xDB\xB3\x72\x38\x6C\x40\x0B\x04\x39\x04\x0D\x90\x29\xAD\x2C\x7E\x5C\xF4\x34\x08\x23\xB2\xA8\x7D\xC6\x8C\x9E\x4C\xE3\x17\x4C\x1E\x6E\xFD\xEE\x12\xC0\x7D\x58\xAA\x56\xF7\x72\xC0\x72\x6F\x24\xC6\xB8\x9E\x4E\xCD\xAC\x24\x35\x4B\x9E\x99\xCA\xA3\xF6\xD3\x76\x14\x02\xCD\x02\x1D\x00\xD7\xC1\x34\xAA\x26\x43\x66\x86\x2A\x18\x30\x25\x75\xD0\xFB\x98\xD1\x16\xBC\x4B\x6D\xDE\xBC\xA3\xA5\xA7\x93\x9F\x02\x01\x01\x03\x3A\x00\x04\x3D\x6A\x7C\x2A\x6F\x20\x5F\x83\x9B\x04\x14\xEC\x58\xC6\xC7\x1B\x75\xF5\x15\xDE\xC3\xAE\x73\x3B\x5F\x47\x88\xDD\xC8\x15\xF0\x5B\xC1\xF6\x53\x8F\xD9\x69\x54\xE1\xF8\x40\xA2\xE2\x18\x99\x62\xCC\xAA\x14\x90\x08\x24\xC7\xDD\xB9\xA3\x81\xD1\x30\x81\xCE\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x07\x80\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14\x60\x44\xF2\x45\xF2\xE0\x71\xD4\xD5\x64\xF4\xE5\x77\xD6\x36\x69\xDB\xEB\x18\x59\x30\x41\x06\x03\x55\x1D\x20\x04\x3A\x30\x38\x30\x36\x06\x09\x04\x00\x7F\x00\x07\x03\x01\x01\x01\x30\x29\x30\x27\x06\x08\x2B\x06\x01\x05\x05\x07\x02\x01\x16\x1B\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x62\x73\x69\x2E\x62\x75\x6E\x64\x2E\x64\x65\x2F\x63\x73\x63\x61\x30\x2B\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x15\x04\x1E\x04\x1C\x31\x2E\x32\x2E\x32\x37\x36\x2E\x30\x2E\x38\x30\x2E\x31\x2E\x31\x32\x2E\x30\x2E\x32\x30\x2E\x35\x2E\x31\x2E\x30\x30\x2B\x06\x03\x55\x1D\x10\x04\x24\x30\x22\x80\x0F\x32\x30\x31\x30\x31\x30\x30\x35\x31\x31\x30\x37\x35\x32\x5A\x81\x0F\x32\x30\x31\x31\x30\x32\x30\x35\x30\x39\x33\x39\x34\x37\x5A\x30\x0C\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x02\x05\x00\x03\x48\x00\x30\x45\x02\x20\x13\xE9\xE1\x7A\x9E\xFE\x8B\xD7\xD7\x27\x62\x92\x30\x5B\xCC\xC3\x2B\x70\xC2\xB7\x60\x40\xF4\x88\x30\x66\x62\x26\xCD\x6A\x4B\xF4\x02\x21\x00\x87\xF4\x71\xE2\x44\x35\xB4\xC3\x4A\xF3\x57\x30\x94\xFB\x1F\x1C\x2A\x48\xB1\x3E\xE5\xED\x67\xF1\x72\x6D\xCF\x56\xE3\x84\xE3\x6F\x31\x82\x01\x09\x30\x82\x01\x05\x02\x01\x01\x30\x55\x30\x4F\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x0D\x30\x0B\x06\x03\x55\x04\x0A\x0C\x04\x62\x75\x6E\x64\x31\x0C\x30\x0A\x06\x03\x55\x04\x0B\x0C\x03\x62\x73\x69\x31\x0C\x30\x0A\x06\x03\x55\x04\x05\x13\x03\x30\x31\x33\x31\x15\x30\x13\x06\x03\x55\x04\x03\x0C\x0C\x63\x73\x63\x61\x2D\x67\x65\x72\x6D\x61\x6E\x79\x02\x02\x01\x5C\x30\x0D\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\xA0\x4A\x30\x17\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x03\x31\x0A\x06\x08\x04\x00\x7F\x00\x07\x03\x02\x01\x30\x2F\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x04\x31\x22\x04\x20\xEF\x0F\xDA\x94\x2E\x5A\x0F\x6F\xC9\xC5\x46\xEE\x01\xF9\x10\x31\x43\x64\x30\xF7\x5E\x9D\x36\x54\xD3\x69\x30\x9E\x8B\xE7\x17\x48\x30\x0C\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x02\x05\x00\x04\x40\x30\x3E\x02\x1D\x00\x89\x75\x92\x5B\xE1\x31\xB7\x7C\x95\x8C\x3E\xCB\x2A\x5C\x67\xFC\x5C\xE3\x1C\xBD\x01\x41\xE3\x4B\xC7\xF0\xA4\x47\x02\x1D\x00\xCC\x65\xE6\x2D\xDC\xF2\x93\x96\x4B\x22\xD7\xB5\x10\xD7\x81\x88\x07\xC8\x95\x96\xBD\x34\xD8\xF9\xBB\x4C\x05\x27"
        self.mf.append(
            TransparentStructureEF(parent=self.mf,
                                   fid=0x011d,
                                   shortfid=0x1d,
                                   data=card_security))
        ef_dir = '\x61\x32\x4F\x0F\xE8\x28\xBD\x08\x0F\xA0\x00\x00\x01\x67\x45\x53\x49\x47\x4E\x50\x0F\x43\x49\x41\x20\x7A\x75\x20\x44\x46\x2E\x65\x53\x69\x67\x6E\x51\x00\x73\x0C\x4F\x0A\xA0\x00\x00\x01\x67\x45\x53\x49\x47\x4E\x61\x09\x4F\x07\xA0\x00\x00\x02\x47\x10\x01\x61\x0B\x4F\x09\xE8\x07\x04\x00\x7F\x00\x07\x03\x02\x61\x0C\x4F\x0A\xA0\x00\x00\x01\x67\x45\x53\x49\x47\x4E'
        self.mf.append(
            TransparentStructureEF(parent=self.mf,
                                   fid=0x2f00,
                                   shortfid=30,
                                   data=ef_dir))

        #print 'nPA:', unpack('\x62\x81\x88\x82\x01\x38\x8a\x01\x05\x84\x09\xe8\x07\x04\x00\x7f\x00\x07\x03\x02\xab\x75\x84\x01\xa4\xaf\x70\xa0\x10\xb4\x06\x95\x01\x20\x83\x01\x04\xb4\x06\x95\x01\x20\x83\x01\x06\xa0\x54\xa4\x14\x95\x01\x80\x7f\x4c\x0e\x06\x09\x04\x00\x7f\x00\x07\x03\x01\x02\x01\x53\x01\x00\xaf\x22\xa4\x18\x95\x01\x80\x7f\x4c\x12\x06\x09\x04\x00\x7f\x00\x07\x03\x01\x02\x02\x53\x05\x00\x00\x00\x00\x00\xa4\x06\x95\x01\x80\x83\x01\x47\xa4\x18\x95\x01\x80\x7f\x4c\x12\x06\x09\x04\x00\x7f\x00\x07\x03\x01\x02\x02\x53\x05\x00\x00\x00\x00\x10\x7a\x06\x8a\x01\x05\x9e\x01\x03')
        #print 'vicc:', unpack('\x62\x15\x83\x02\xff\xff\x8a\x01\x05\x82\x01\x38\x84\x09\xe8\x07\x04\x00\x7f\x00\x07\x03\x02')
        eid = DF(parent=self.mf,
                 fid=0xffff,
                 dfname='\xe8\x07\x04\x00\x7f\x00\x07\x03\x02')
        eid.extra_fci_data = '\xab\x75\x84\x01\xa4\xaf\x70\xa0\x10\xb4\x06\x95\x01\x20\x83\x01\x04\xb4\x06\x95\x01\x20\x83\x01\x06\xa0\x54\xa4\x14\x95\x01\x80\x7f\x4c\x0e\x06\x09\x04\x00\x7f\x00\x07\x03\x01\x02\x01\x53\x01\x00\xaf\x22\xa4\x18\x95\x01\x80\x7f\x4c\x12\x06\x09\x04\x00\x7f\x00\x07\x03\x01\x02\x02\x53\x05\x00\x00\x00\x00\x00\xa4\x06\x95\x01\x80\x83\x01\x47\xa4\x18\x95\x01\x80\x7f\x4c\x12\x06\x09\x04\x00\x7f\x00\x07\x03\x01\x02\x02\x53\x05\x00\x00\x00\x00\x10\x7a\x06\x8a\x01\x05\x9e\x01\x03'
        # FIXME access control for eid application

        DocumentType = self.datagroups[
            "DocumentType"] if "DocumentType" in self.datagroups else 'ID'
        IssuingState = self.datagroups[
            "IssuingState"] if "IssuingState" in self.datagroups else 'D'
        DateOfExpiry = self.datagroups[
            "DateOfExpiry"] if "DateOfExpiry" in self.datagroups else '20201031'
        GivenNames = self.datagroups[
            "GivenNames"] if "GivenNames" in self.datagroups else 'ERIKA'
        FamilyNames = self.datagroups[
            "FamilyNames"] if "FamilyNames" in self.datagroups else 'MUSTERMANN'
        ReligiousArtisticName = self.datagroups[
            "ReligiousArtisticName"] if "ReligiousArtisticName" in self.datagroups else ''
        AcademicTitle = self.datagroups[
            "AcademicTitle"] if "AcademicTitle" in self.datagroups else ''
        DateOfBirth = self.datagroups[
            "DateOfBirth"] if "DateOfBirth" in self.datagroups else '19640812'
        PlaceOfBirth = self.datagroups[
            "PlaceOfBirth"] if "PlaceOfBirth" in self.datagroups else 'BERLIN'
        Nationality = self.datagroups[
            "Nationality"] if "Nationality" in self.datagroups else 'DE'
        Sex = self.datagroups["Sex"] if "Sex" in self.datagroups else 'F'
        BirthName = self.datagroups[
            "BirthName"] if "BirthName" in self.datagroups else 'Mein Geburtsname'
        # PlaceOfResidence variable is only a helper to get a switch for <NotOnChip>
        PlaceOfResidence = self.datagroups[
            "PlaceOfResidence"] if "PlaceOfResidence" in self.datagroups else ''
        Country = self.datagroups[
            "Country"] if "Country" in self.datagroups else 'D'
        City = self.datagroups["City"] if "City" in self.datagroups else 'KOLN'
        ZIP = self.datagroups["ZIP"] if "ZIP" in self.datagroups else '51147'
        Street = self.datagroups[
            "Street"] if "Street" in self.datagroups else 'HEIDESTRASSE 17'
        CommunityID = eval(
            self.datagroups["CommunityID"]
        ) if "CommunityID" in self.datagroups else '\x02\x76\x03\x78\x90\x02\x76'
        # ResidencePermit1 and ResidencePermit2 are part of eAT only
        ResidencePermit1 = self.datagroups[
            "ResidencePermit1"] if "ResidencePermit1" in self.datagroups else 'ResidencePermit1 field up to 750 characters'
        ResidencePermit2 = self.datagroups[
            "ResidencePermit2"] if "ResidencePermit2" in self.datagroups else 'ResidencePermit1 field up to 250 characters'

        # Currently, those data groups are for further usage:
        dg12_param = self.datagroups[
            "dg12"] if "dg12" in self.datagroups else ''
        dg14_param = self.datagroups[
            "dg14"] if "dg14" in self.datagroups else ''
        dg15_param = self.datagroups[
            "dg15"] if "dg15" in self.datagroups else ''
        dg16_param = self.datagroups[
            "dg16"] if "dg16" in self.datagroups else ''
        dg21_param = self.datagroups[
            "dg21"] if "dg21" in self.datagroups else ''

        # "Attribute not on Chip" makes sence only for ReligiousArtisticName, Nationality, BirthName, ResidencePermit1 and ResidencePermit2, refer to BSI TR-03127
        if (DocumentType.rstrip() != "<NotOnChip>"):
            dg1 = pack([(0x61, 0, [(0x13, 0, DocumentType)])], True)
        else:
            dg1 = None
        if (IssuingState.rstrip() != "<NotOnChip>"):
            dg2 = pack([(0x62, 0, [(0x13, 0, IssuingState)])], True)
        else:
            dg2 = None
        if (DateOfExpiry.rstrip() != "<NotOnChip>"):
            dg3 = pack([(0x63, 0, [(0x12, 0, DateOfExpiry)])], True)
        else:
            dg3 = None
        if (GivenNames.rstrip() != "<NotOnChip>"):
            dg4 = pack([(0x64, 0, [(0x0C, 0, GivenNames)])], True)
        else:
            dg4 = None
        if (FamilyNames.rstrip() != "<NotOnChip>"):
            dg5 = pack([(0x65, 0, [(0x0C, 0, FamilyNames)])], True)
        else:
            dg5 = None
        if (ReligiousArtisticName.rstrip() != "<NotOnChip>"):
            dg6 = pack([(0x66, 0, [(0x0C, 0, ReligiousArtisticName)])], True)
        else:
            dg6 = None
        if (AcademicTitle.rstrip() != "<NotOnChip>"):
            dg7 = pack([(0x67, 0, [(0x0C, 0, AcademicTitle)])], True)
        else:
            dg7 = None
        if (DateOfBirth.rstrip() != "<NotOnChip>"):
            dg8 = pack([(0x68, 0, [(0x12, 0, DateOfBirth)])], True)
        else:
            dg8 = None
        if (PlaceOfBirth.rstrip() != "<NotOnChip>"):
            dg9 = pack([(0x69, 0, [(0xA1, 0, [(0x0C, 0, PlaceOfBirth)])])],
                       True)
        else:
            dg9 = None
        if (Nationality.rstrip() != "<NotOnChip>"):
            dg10 = pack([(0x6A, 0, [(0x13, 0, Nationality)])], True)
        else:
            dg10 = None
        if (Sex.rstrip() != "<NotOnChip>"):
            dg11 = pack([(0x6B, 0, [(0x13, 0, Sex)])], True)
        else:
            dg11 = None
        if (dg12_param.rstrip() != "<NotOnChip>"):
            dg12 = dg12_param
        else:
            dg12 = None
        if (BirthName.rstrip() != "<NotOnChip>"):
            dg13 = pack([(0x6D, 0, [(0x0C, 0, BirthName)])], True)
        else:
            dg13 = None
        if (dg14_param.rstrip() != "<NotOnChip>"):
            dg14 = dg14_param
        else:
            dg14 = None
        if (dg15_param.rstrip() != "<NotOnChip>"):
            dg15 = dg15_param
        else:
            dg15 = None
        if (dg16_param.rstrip() != "<NotOnChip>"):
            dg16 = dg16_param
        else:
            dg16 = None
        if (PlaceOfResidence.rstrip() != "<NotOnChip>"):
            dg17 = pack(
                [(0x71, 0, [(0x30, 0, [(0xAA, 0, [(0x0C, 0, Street)]),
                                       (0xAB, 0, [(0x0C, 0, City)]),
                                       (0xAD, 0, [(0x13, 0, Country)]),
                                       (0xAE, 0, [(0x13, 0, ZIP)])])])], True)
        else:
            dg17 = None
#FIXME: Dataset file with CommunityID =<NotOnChip> still not works while assigning of non hex value due to eval()
        if (CommunityID.rstrip() != "<NotOnChip>"):
            dg18 = pack([(0x72, 0, [(0x04, 0, CommunityID)])], True)
        else:
            dg18 = None
        if (ResidencePermit1.rstrip() != "<NotOnChip>"):
            dg19 = pack(
                [(0x73, 0, [(0xA1, 0, [(0x0C, 0, ResidencePermit1)])])], True)
        else:
            dg19 = None
        if (ResidencePermit1.rstrip() != "<NotOnChip>"):
            dg20 = pack(
                [(0x74, 0, [(0xA1, 0, [(0x0C, 0, ResidencePermit2)])])], True)
        else:
            dg20 = None
        if (dg21_param.rstrip() != "<NotOnChip>"):
            dg21 = dg21_param
        else:
            dg21 = None

# If eid.append is not done for a DG, it results into required SwError() with FileNotFound "6A82" APDU return code
        if dg1:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x0101,
                                       shortfid=0x01,
                                       data=dg1))
        if dg2:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x0102,
                                       shortfid=0x02,
                                       data=dg2))
        if dg3:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x0103,
                                       shortfid=0x03,
                                       data=dg3))
        if dg4:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x0104,
                                       shortfid=0x04,
                                       data=dg4))
        if dg5:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x0105,
                                       shortfid=0x05,
                                       data=dg5))
        if dg6:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x0106,
                                       shortfid=0x06,
                                       data=dg6))
        if dg7:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x0107,
                                       shortfid=0x07,
                                       data=dg7))
        if dg8:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x0108,
                                       shortfid=0x08,
                                       data=dg8))
        if dg9:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x0109,
                                       shortfid=0x09,
                                       data=dg9))
        if dg10:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x010a,
                                       shortfid=0x0a,
                                       data=dg10))
        if dg11:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x010b,
                                       shortfid=0x0b,
                                       data=dg11))
        if dg12:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x010c,
                                       shortfid=0x0c,
                                       data=dg12))
        if dg13:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x010d,
                                       shortfid=0x0d,
                                       data=dg13))
        if dg14:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x010e,
                                       shortfid=0x0e,
                                       data=dg14))
        if dg15:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x010f,
                                       shortfid=0x0f,
                                       data=dg15))
        if dg16:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x0110,
                                       shortfid=0x10,
                                       data=dg16))
        if dg17:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x0111,
                                       shortfid=0x11,
                                       data=dg17))
        if dg18:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x0112,
                                       shortfid=0x12,
                                       data=dg18))
        if dg19:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x0113,
                                       shortfid=0x13,
                                       data=dg19))
        if dg20:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x0114,
                                       shortfid=0x14,
                                       data=dg20))
        if dg21:
            eid.append(
                TransparentStructureEF(parent=eid,
                                       fid=0x0115,
                                       shortfid=0x15,
                                       data=dg21))
        self.mf.append(eid)

        self.sam = nPA_SAM(
            pin="111111",
            can="222222",
            mrz=
            "IDD<<T220001293<<<<<<<<<<<<<<<6408125<2010315D<<<<<<<<<<<<<<MUSTERMANN<<ERIKA<<<<<<<<<<<<<",
            puk="3333333333",
            mf=self.mf)
        # FIXME add CVCA for inspection systems and signature terminals. Here we only add the eID CVCA.
        self.sam.current_SE.cvca = '\x7f\x21\x82\x01\xb6\x7f\x4e\x82\x01\x6e\x5f\x29\x01\x00\x42\x0e\x44\x45\x43\x56\x43\x41\x65\x49\x44\x30\x30\x31\x30\x32\x7f\x49\x82\x01\x1d\x06\x0a\x04\x00\x7f\x00\x07\x02\x02\x02\x02\x03\x81\x20\xa9\xfb\x57\xdb\xa1\xee\xa9\xbc\x3e\x66\x0a\x90\x9d\x83\x8d\x72\x6e\x3b\xf6\x23\xd5\x26\x20\x28\x20\x13\x48\x1d\x1f\x6e\x53\x77\x82\x20\x7d\x5a\x09\x75\xfc\x2c\x30\x57\xee\xf6\x75\x30\x41\x7a\xff\xe7\xfb\x80\x55\xc1\x26\xdc\x5c\x6c\xe9\x4a\x4b\x44\xf3\x30\xb5\xd9\x83\x20\x26\xdc\x5c\x6c\xe9\x4a\x4b\x44\xf3\x30\xb5\xd9\xbb\xd7\x7c\xbf\x95\x84\x16\x29\x5c\xf7\xe1\xce\x6b\xcc\xdc\x18\xff\x8c\x07\xb6\x84\x41\x04\x8b\xd2\xae\xb9\xcb\x7e\x57\xcb\x2c\x4b\x48\x2f\xfc\x81\xb7\xaf\xb9\xde\x27\xe1\xe3\xbd\x23\xc2\x3a\x44\x53\xbd\x9a\xce\x32\x62\x54\x7e\xf8\x35\xc3\xda\xc4\xfd\x97\xf8\x46\x1a\x14\x61\x1d\xc9\xc2\x77\x45\x13\x2d\xed\x8e\x54\x5c\x1d\x54\xc7\x2f\x04\x69\x97\x85\x20\xa9\xfb\x57\xdb\xa1\xee\xa9\xbc\x3e\x66\x0a\x90\x9d\x83\x8d\x71\x8c\x39\x7a\xa3\xb5\x61\xa6\xf7\x90\x1e\x0e\x82\x97\x48\x56\xa7\x86\x41\x04\x33\x47\xec\xf9\x6f\xfb\x4b\xd9\xb8\x55\x4e\xfb\xcc\xfc\x7d\x0b\x24\x2f\x10\x71\xe2\x9b\x4c\x9c\x62\x2c\x79\xe3\x39\xd8\x40\xaf\x67\xbe\xb9\xb9\x12\x69\x22\x65\xd9\xc1\x6c\x62\x57\x3f\x45\x79\xff\xd4\xde\x2d\xe9\x2b\xab\x40\x9d\xd5\xc5\xd4\x82\x44\xa9\xf7\x87\x01\x01\x5f\x20\x0e\x44\x45\x43\x56\x43\x41\x65\x49\x44\x30\x30\x31\x30\x32\x7f\x4c\x12\x06\x09\x04\x00\x7f\x00\x07\x03\x01\x02\x02\x53\x05\xfe\x0f\x01\xff\xff\x5f\x25\x06\x01\x00\x01\x00\x01\x08\x5f\x24\x06\x01\x03\x01\x00\x01\x08\x5f\x37\x40\x50\x67\x14\x5c\x68\xca\xe9\x52\x0f\x5b\xb3\x48\x17\xf1\xca\x9c\x43\x59\x3d\xb5\x64\x06\xc6\xa3\xb0\x06\xcb\xf3\xf3\x14\xe7\x34\x9a\xcf\x0c\xc6\xbf\xeb\xcb\xde\xfd\x10\xb4\xdc\xf0\xf2\x31\xda\x56\x97\x7d\x88\xf9\xf9\x01\x82\xd1\x99\x07\x6a\x56\x50\x64\x51'

    def __generate_cryptoflex(self):
        """Generate the Filesystem and SAM of a cryptoflex card"""
        from virtualsmartcard.cards.cryptoflex import CryptoflexMF, CryptoflexSAM
        self.mf = CryptoflexMF()
        self.mf.append(
            TransparentStructureEF(
                parent=self.mf,
                fid=0x0002,
                filedescriptor=0x01,
                data="\x00\x00\x00\x01\x00\x01\x00\x00"))  #EF.ICCSN
        self.sam = CryptoflexSAM(self.mf)

    def generateCard(self):
        """Generate a new card"""
        if self.type == 'iso7816':
            self.__generate_iso_card()
        elif self.type == 'ePass':
            self.__generate_ePass()
        elif self.type == 'cryptoflex':
            self.__generate_cryptoflex()
        elif self.type == 'nPA':
            self.__generate_nPA()
        else:
            return (None, None)

    def getCard(self):
        """Get the MF and SAM from the current card"""
        if self.sam is None or self.mf is None:
            self.generateCard()
        return self.mf, self.sam

    def setCard(self, mf=None, sam=None):
        """Set the MF and SAM of the current card"""
        if mf != None:
            self.mf = mf
        if sam != None:
            self.sam = sam

    def loadCard(self, filename):
        """Load a card from disk"""
        db = anydbm.open(filename, 'r')

        if self.password is None:
            self.password = getpass.getpass("Please enter your password:"******"mf"], self.password)
        serializedSAM = read_protected_string(db["sam"], self.password)
        self.sam = loads(serializedSAM)
        self.mf = loads(serializedMF)
        self.type = db["type"]

    def saveCard(self, filename):
        """Save the currently running card to disk"""
        if self.password is None:
            passwd1 = getpass.getpass("Please enter your password:"******"Please retype your password:"******"Passwords did not match. Will now exit")
            else:
                self.password = passwd1

        if self.mf == None or self.sam == None:
            raise ValueError("Card Generator wasn't set up properly" +\
                 "(missing MF or SAM).")

        mf_string = dumps(self.mf)
        sam_string = dumps(self.sam)
        protectedMF = protect_string(mf_string, self.password)
        protectedSAM = protect_string(sam_string, self.password)

        db = anydbm.open(filename, 'c')
        db["mf"] = protectedMF
        db["sam"] = protectedSAM
        db["type"] = self.type
        db["version"] = "0.1"
        db.close()

    def readDatagroups(self, datasetfile):
        """Read Datagroups from file"""
        with open(datasetfile, 'r') as f:
            for line in f:
                if (not line.startswith("#")) and (not len(line.strip()) == 0):
                    # spaces after equal sign are allowed to get strings with leading spaces!
                    line = line.replace(" =", "=")
                    splitLine = line.split("=")
                    # we don't want to have the newline char from dataset file as part of the value!!
                    self.datagroups[splitLine[0]] = splitLine[1].rstrip("\n\r")
        f.close()
Esempio n. 3
0
class CardGenerator(object):
    """This class is used to generate the SAM and filesystem for the 
    different supported card types. It is also able used for persistent storage
    (in encrypted form) of the card on disks. """
    
    def __init__(self, card_type=None, sam=None, mf=None):
        self.type = card_type
        self.mf = mf
        self.sam = sam
        self.password = None
        self.datagroups = {}
    
    def __generate_iso_card(self):
        default_pin = "1234"
        default_cardno = "1234567890"
        
        logging.warning("Using default SAM parameters. PIN=%s, Card Nr=%s"
                        % (default_pin, default_cardno))
        #TODO: Use user provided data
        self.sam = SAM(default_pin, default_cardno)
        
        self.mf = MF(filedescriptor=FDB["DF"])
        self.sam.set_MF(self.mf)
           
    def __generate_ePass(self):
        """Generate the MF and SAM of an ICAO passport. This method is 
        responsible for generating the filesystem and filling it with content.
        Therefore it must interact with the user by prompting for the MRZ and
        optionally for the path to a photo."""
        from PIL import Image
        from virtualsmartcard.cards.ePass import PassportSAM
            
        #TODO: Sanity checks
        MRZ = raw_input("Please enter the MRZ as one string: ")

        readline.set_completer_delims("")
        readline.parse_and_bind("tab: complete")
        
        picturepath = raw_input("Please enter the path to an image: ")
        picturepath = picturepath.strip()
        
        #MRZ1 = "P<UTOERIKSSON<<ANNA<MARIX<<<<<<<<<<<<<<<<<<<"
        #MRZ2 = "L898902C<3UTO6908061F9406236ZE184226B<<<<<14"
        #MRZ = MRZ1 + MRZ2        

        try:
            im = Image.open(picturepath)
            pic_width, pic_height = im.size
            fd = open(picturepath,"rb")
            picture = fd.read()
            fd.close()
        except IOError:
            logging.warning("Failed to open file: " + picturepath)
            pic_width = 0
            pic_height = 0
            picture = None  

        mf = MF()
        
        #We need a MF with Application DF \xa0\x00\x00\x02G\x10\x01
        df = DF(parent=mf, fid=4, dfname='\xa0\x00\x00\x02G\x10\x01',
                bertlv_data=[])

        #EF.COM
        COM = pack([(0x5F01, 4, "0107"), (0x5F36, 6, "040000"),
                    (0x5C, 2, "6175")])
        COM = pack(((0x60, len(COM), COM),))
        df.append(TransparentStructureEF(parent=df, fid=0x011E,
                  filedescriptor=0, data=COM))

        #EF.DG1
        DG1 = pack([(0x5F1F, len(MRZ), MRZ)])
        DG1 = pack([(0x61, len(DG1), DG1)])
        df.append(TransparentStructureEF(parent=df, fid=0x0101,
                  filedescriptor=0, data=DG1))

        #EF.DG2
        if picture != None:
            IIB = "\x00\x01" + inttostring(pic_width, 2) +\
                    inttostring(pic_height, 2) + 6 * "\x00" 
            length = 32 + len(picture) #32 is the length of IIB + FIB
            FIB = inttostring(length, 4) + 16 * "\x00"
            FRH = "FAC" + "\x00" + "010" + "\x00" +\
                    inttostring(14 + length, 4) + inttostring(1, 2)
            picture = FRH + FIB + IIB + picture
            DG2 = pack([(0xA1, 8, "\x87\x02\x01\x01\x88\x02\x05\x01"), 
                    (0x5F2E, len(picture), picture)])
            DG2 = pack([(0x02, 1, "\x01"), (0x7F60, len(DG2), DG2)])
            DG2 = pack([(0x7F61, len(DG2), DG2)])
        else:
            DG2 = ""
        df.append(TransparentStructureEF(parent=df, fid=0x0102,
                  filedescriptor=0, data=DG2))

        #EF.SOD
        df.append(TransparentStructureEF(parent=df, fid=0x010D,
                  filedescriptor=0, data=""))

        mf.append(df)

        self.mf = mf
        self.sam = PassportSAM(self.mf)
    
    def __generate_nPA(self):
        from virtualsmartcard.cards.nPA import nPA_SAM
        for oid_base, x_list, y_list, algo in [
                ('\x04\x00\x7f\x00\x07\x02\x02\x04', range(1,5), range(1,5), "PACE"),
                ('\x04\x00\x7f\x00\x07\x02\x02\x02', range(1,3), range(1,6), "TA"),
                ('\x04\x00\x7f\x00\x07\x02\x02\x02', [1],        [6],        "TA"),
                ('\x04\x00\x7f\x00\x07\x02\x02\x03', range(1,3), range(1,5), "CA"),
                ('\x04\x00\x7f\x00\x07\x02\x02\x05', range(1,3), range(1,6), "RI"),
                ]:
            for oid in [oid_base+chr(x)+chr(y) for x in x_list for y in y_list]:
                ALGO_MAPPING[oid] = algo
        ALGO_MAPPING["\x04\x00\x7f\x00\x07\x03\x01\x04\x03"] = "CommunityID"
        ALGO_MAPPING["\x04\x00\x7f\x00\x07\x03\x01\x04\x02"] = "DateOfExpiry"
        ALGO_MAPPING["\x04\x00\x7f\x00\x07\x03\x01\x04\x01"] = "DateOfBirth"

        self.mf = MF()

        card_access =  "\x31\x81\xb3\x30\x0d\x06\x08\x04\x00\x7f\x00\x07\x02\x02\x02\x02\x01\x02\x30\x12\x06\x0a\x04\x00\x7f\x00\x07\x02\x02\x03\x02\x02\x02\x01\x02\x02\x01\x41\x30\x12\x06\x0a\x04\x00\x7f\x00\x07\x02\x02\x03\x02\x02\x02\x01\x02\x02\x01\x45\x30\x12\x06\x0a\x04\x00\x7f\x00\x07\x02\x02\x04\x02\x02\x02\x01\x02\x02\x01\x0d\x30\x1c\x06\x09\x04\x00\x7f\x00\x07\x02\x02\x03\x02\x30\x0c\x06\x07\x04\x00\x7f\x00\x07\x01\x02\x02\x01\x0d\x02\x01\x41\x30\x1c\x06\x09\x04\x00\x7f\x00\x07\x02\x02\x03\x02\x30\x0c\x06\x07\x04\x00\x7f\x00\x07\x01\x02\x02\x01\x0d\x02\x01\x45\x30\x2a\x06\x08\x04\x00\x7f\x00\x07\x02\x02\x06\x16\x1e\x68\x74\x74\x70\x3a\x2f\x2f\x62\x73\x69\x2e\x62\x75\x6e\x64\x2e\x64\x65\x2f\x63\x69\x66\x2f\x6e\x70\x61\x2e\x78\x6d\x6c"
        self.mf.append(TransparentStructureEF(parent=self.mf, fid=0x011c, shortfid=0x1c, data=card_access))
        card_security = "\x30\x82\x05\xA0\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02\xA0\x82\x05\x91\x30\x82\x05\x8D\x02\x01\x03\x31\x0F\x30\x0D\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x30\x82\x01\x48\x06\x08\x04\x00\x7F\x00\x07\x03\x02\x01\xA0\x82\x01\x3A\x04\x82\x01\x36\x31\x82\x01\x32\x30\x0D\x06\x08\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x01\x02\x30\x12\x06\x0A\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x02\x02\x01\x02\x02\x01\x41\x30\x12\x06\x0A\x04\x00\x7F\x00\x07\x02\x02\x04\x02\x02\x02\x01\x02\x02\x01\x0D\x30\x17\x06\x0A\x04\x00\x7F\x00\x07\x02\x02\x05\x02\x03\x30\x09\x02\x01\x01\x02\x01\x43\x01\x01\xFF\x30\x17\x06\x0A\x04\x00\x7F\x00\x07\x02\x02\x05\x02\x03\x30\x09\x02\x01\x01\x02\x01\x44\x01\x01\x00\x30\x19\x06\x09\x04\x00\x7F\x00\x07\x02\x02\x05\x02\x30\x0C\x06\x07\x04\x00\x7F\x00\x07\x01\x02\x02\x01\x0D\x30\x1C\x06\x09\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x30\x0C\x06\x07\x04\x00\x7F\x00\x07\x01\x02\x02\x01\x0D\x02\x01\x41\x30\x2A\x06\x08\x04\x00\x7F\x00\x07\x02\x02\x06\x16\x1E\x68\x74\x74\x70\x3A\x2F\x2F\x62\x73\x69\x2E\x62\x75\x6E\x64\x2E\x64\x65\x2F\x63\x69\x66\x2F\x6E\x70\x61\x2E\x78\x6D\x6C\x30\x62\x06\x09\x04\x00\x7F\x00\x07\x02\x02\x01\x02\x30\x52\x30\x0C\x06\x07\x04\x00\x7F\x00\x07\x01\x02\x02\x01\x0D\x03\x42\x00\x04\x92\x5D\xB4\xE1\x7A\xDE\x58\x20\x9F\x96\xFA\xA0\x7F\x1F\x8A\x22\x3F\x82\x3F\x96\xCC\x5D\x78\xCB\xEF\x5D\x17\x42\x20\x88\xFD\xD5\x8E\x56\xBC\x42\x50\xDE\x33\x46\xB3\xC8\x32\xCA\xE4\x86\x35\xFB\x6C\x43\x78\x9D\xE8\xB3\x10\x2F\x43\x93\xB4\x18\xE2\x4A\x13\xD9\x02\x01\x41\xA0\x82\x03\x1C\x30\x82\x03\x18\x30\x82\x02\xBC\xA0\x03\x02\x01\x02\x02\x02\x01\x5C\x30\x0C\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x02\x05\x00\x30\x4F\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x0D\x30\x0B\x06\x03\x55\x04\x0A\x0C\x04\x62\x75\x6E\x64\x31\x0C\x30\x0A\x06\x03\x55\x04\x0B\x0C\x03\x62\x73\x69\x31\x0C\x30\x0A\x06\x03\x55\x04\x05\x13\x03\x30\x31\x33\x31\x15\x30\x13\x06\x03\x55\x04\x03\x0C\x0C\x63\x73\x63\x61\x2D\x67\x65\x72\x6D\x61\x6E\x79\x30\x1E\x17\x0D\x31\x30\x31\x30\x30\x35\x31\x31\x30\x37\x35\x32\x5A\x17\x0D\x32\x31\x30\x34\x30\x35\x30\x38\x33\x39\x34\x37\x5A\x30\x47\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x1D\x30\x1B\x06\x03\x55\x04\x0A\x0C\x14\x42\x75\x6E\x64\x65\x73\x64\x72\x75\x63\x6B\x65\x72\x65\x69\x20\x47\x6D\x62\x48\x31\x0C\x30\x0A\x06\x03\x55\x04\x05\x13\x03\x30\x37\x34\x31\x0B\x30\x09\x06\x03\x55\x04\x03\x0C\x02\x44\x53\x30\x82\x01\x13\x30\x81\xD4\x06\x07\x2A\x86\x48\xCE\x3D\x02\x01\x30\x81\xC8\x02\x01\x01\x30\x28\x06\x07\x2A\x86\x48\xCE\x3D\x01\x01\x02\x1D\x00\xD7\xC1\x34\xAA\x26\x43\x66\x86\x2A\x18\x30\x25\x75\xD1\xD7\x87\xB0\x9F\x07\x57\x97\xDA\x89\xF5\x7E\xC8\xC0\xFF\x30\x3C\x04\x1C\x68\xA5\xE6\x2C\xA9\xCE\x6C\x1C\x29\x98\x03\xA6\xC1\x53\x0B\x51\x4E\x18\x2A\xD8\xB0\x04\x2A\x59\xCA\xD2\x9F\x43\x04\x1C\x25\x80\xF6\x3C\xCF\xE4\x41\x38\x87\x07\x13\xB1\xA9\x23\x69\xE3\x3E\x21\x35\xD2\x66\xDB\xB3\x72\x38\x6C\x40\x0B\x04\x39\x04\x0D\x90\x29\xAD\x2C\x7E\x5C\xF4\x34\x08\x23\xB2\xA8\x7D\xC6\x8C\x9E\x4C\xE3\x17\x4C\x1E\x6E\xFD\xEE\x12\xC0\x7D\x58\xAA\x56\xF7\x72\xC0\x72\x6F\x24\xC6\xB8\x9E\x4E\xCD\xAC\x24\x35\x4B\x9E\x99\xCA\xA3\xF6\xD3\x76\x14\x02\xCD\x02\x1D\x00\xD7\xC1\x34\xAA\x26\x43\x66\x86\x2A\x18\x30\x25\x75\xD0\xFB\x98\xD1\x16\xBC\x4B\x6D\xDE\xBC\xA3\xA5\xA7\x93\x9F\x02\x01\x01\x03\x3A\x00\x04\x3D\x6A\x7C\x2A\x6F\x20\x5F\x83\x9B\x04\x14\xEC\x58\xC6\xC7\x1B\x75\xF5\x15\xDE\xC3\xAE\x73\x3B\x5F\x47\x88\xDD\xC8\x15\xF0\x5B\xC1\xF6\x53\x8F\xD9\x69\x54\xE1\xF8\x40\xA2\xE2\x18\x99\x62\xCC\xAA\x14\x90\x08\x24\xC7\xDD\xB9\xA3\x81\xD1\x30\x81\xCE\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x07\x80\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14\x60\x44\xF2\x45\xF2\xE0\x71\xD4\xD5\x64\xF4\xE5\x77\xD6\x36\x69\xDB\xEB\x18\x59\x30\x41\x06\x03\x55\x1D\x20\x04\x3A\x30\x38\x30\x36\x06\x09\x04\x00\x7F\x00\x07\x03\x01\x01\x01\x30\x29\x30\x27\x06\x08\x2B\x06\x01\x05\x05\x07\x02\x01\x16\x1B\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x62\x73\x69\x2E\x62\x75\x6E\x64\x2E\x64\x65\x2F\x63\x73\x63\x61\x30\x2B\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x15\x04\x1E\x04\x1C\x31\x2E\x32\x2E\x32\x37\x36\x2E\x30\x2E\x38\x30\x2E\x31\x2E\x31\x32\x2E\x30\x2E\x32\x30\x2E\x35\x2E\x31\x2E\x30\x30\x2B\x06\x03\x55\x1D\x10\x04\x24\x30\x22\x80\x0F\x32\x30\x31\x30\x31\x30\x30\x35\x31\x31\x30\x37\x35\x32\x5A\x81\x0F\x32\x30\x31\x31\x30\x32\x30\x35\x30\x39\x33\x39\x34\x37\x5A\x30\x0C\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x02\x05\x00\x03\x48\x00\x30\x45\x02\x20\x13\xE9\xE1\x7A\x9E\xFE\x8B\xD7\xD7\x27\x62\x92\x30\x5B\xCC\xC3\x2B\x70\xC2\xB7\x60\x40\xF4\x88\x30\x66\x62\x26\xCD\x6A\x4B\xF4\x02\x21\x00\x87\xF4\x71\xE2\x44\x35\xB4\xC3\x4A\xF3\x57\x30\x94\xFB\x1F\x1C\x2A\x48\xB1\x3E\xE5\xED\x67\xF1\x72\x6D\xCF\x56\xE3\x84\xE3\x6F\x31\x82\x01\x09\x30\x82\x01\x05\x02\x01\x01\x30\x55\x30\x4F\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x0D\x30\x0B\x06\x03\x55\x04\x0A\x0C\x04\x62\x75\x6E\x64\x31\x0C\x30\x0A\x06\x03\x55\x04\x0B\x0C\x03\x62\x73\x69\x31\x0C\x30\x0A\x06\x03\x55\x04\x05\x13\x03\x30\x31\x33\x31\x15\x30\x13\x06\x03\x55\x04\x03\x0C\x0C\x63\x73\x63\x61\x2D\x67\x65\x72\x6D\x61\x6E\x79\x02\x02\x01\x5C\x30\x0D\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\xA0\x4A\x30\x17\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x03\x31\x0A\x06\x08\x04\x00\x7F\x00\x07\x03\x02\x01\x30\x2F\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x04\x31\x22\x04\x20\xEF\x0F\xDA\x94\x2E\x5A\x0F\x6F\xC9\xC5\x46\xEE\x01\xF9\x10\x31\x43\x64\x30\xF7\x5E\x9D\x36\x54\xD3\x69\x30\x9E\x8B\xE7\x17\x48\x30\x0C\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x02\x05\x00\x04\x40\x30\x3E\x02\x1D\x00\x89\x75\x92\x5B\xE1\x31\xB7\x7C\x95\x8C\x3E\xCB\x2A\x5C\x67\xFC\x5C\xE3\x1C\xBD\x01\x41\xE3\x4B\xC7\xF0\xA4\x47\x02\x1D\x00\xCC\x65\xE6\x2D\xDC\xF2\x93\x96\x4B\x22\xD7\xB5\x10\xD7\x81\x88\x07\xC8\x95\x96\xBD\x34\xD8\xF9\xBB\x4C\x05\x27"
        self.mf.append(TransparentStructureEF(parent=self.mf, fid=0x011d, shortfid=0x1d, data=card_security))
        ef_dir = '\x61\x32\x4F\x0F\xE8\x28\xBD\x08\x0F\xA0\x00\x00\x01\x67\x45\x53\x49\x47\x4E\x50\x0F\x43\x49\x41\x20\x7A\x75\x20\x44\x46\x2E\x65\x53\x69\x67\x6E\x51\x00\x73\x0C\x4F\x0A\xA0\x00\x00\x01\x67\x45\x53\x49\x47\x4E\x61\x09\x4F\x07\xA0\x00\x00\x02\x47\x10\x01\x61\x0B\x4F\x09\xE8\x07\x04\x00\x7F\x00\x07\x03\x02\x61\x0C\x4F\x0A\xA0\x00\x00\x01\x67\x45\x53\x49\x47\x4E'
        self.mf.append(TransparentStructureEF(parent=self.mf, fid=0x2f00, shortfid=30, data=ef_dir))

        #print 'nPA:', unpack('\x62\x81\x88\x82\x01\x38\x8a\x01\x05\x84\x09\xe8\x07\x04\x00\x7f\x00\x07\x03\x02\xab\x75\x84\x01\xa4\xaf\x70\xa0\x10\xb4\x06\x95\x01\x20\x83\x01\x04\xb4\x06\x95\x01\x20\x83\x01\x06\xa0\x54\xa4\x14\x95\x01\x80\x7f\x4c\x0e\x06\x09\x04\x00\x7f\x00\x07\x03\x01\x02\x01\x53\x01\x00\xaf\x22\xa4\x18\x95\x01\x80\x7f\x4c\x12\x06\x09\x04\x00\x7f\x00\x07\x03\x01\x02\x02\x53\x05\x00\x00\x00\x00\x00\xa4\x06\x95\x01\x80\x83\x01\x47\xa4\x18\x95\x01\x80\x7f\x4c\x12\x06\x09\x04\x00\x7f\x00\x07\x03\x01\x02\x02\x53\x05\x00\x00\x00\x00\x10\x7a\x06\x8a\x01\x05\x9e\x01\x03')
        #print 'vicc:', unpack('\x62\x15\x83\x02\xff\xff\x8a\x01\x05\x82\x01\x38\x84\x09\xe8\x07\x04\x00\x7f\x00\x07\x03\x02')
        eid=DF(parent=self.mf, fid=0xffff, dfname='\xe8\x07\x04\x00\x7f\x00\x07\x03\x02')
        eid.extra_fci_data = '\xab\x75\x84\x01\xa4\xaf\x70\xa0\x10\xb4\x06\x95\x01\x20\x83\x01\x04\xb4\x06\x95\x01\x20\x83\x01\x06\xa0\x54\xa4\x14\x95\x01\x80\x7f\x4c\x0e\x06\x09\x04\x00\x7f\x00\x07\x03\x01\x02\x01\x53\x01\x00\xaf\x22\xa4\x18\x95\x01\x80\x7f\x4c\x12\x06\x09\x04\x00\x7f\x00\x07\x03\x01\x02\x02\x53\x05\x00\x00\x00\x00\x00\xa4\x06\x95\x01\x80\x83\x01\x47\xa4\x18\x95\x01\x80\x7f\x4c\x12\x06\x09\x04\x00\x7f\x00\x07\x03\x01\x02\x02\x53\x05\x00\x00\x00\x00\x10\x7a\x06\x8a\x01\x05\x9e\x01\x03'
        # FIXME access control for eid application
        DocumentType = self.datagroups["DocumentType"] if "DocumentType" in self.datagroups else 'ID'
        IssuingState = self.datagroups["IssuingState"] if "IssuingState" in self.datagroups else 'DE'
        DateOfExpiry = self.datagroups["DateOfExpiry"] if "DateOfExpiry" in self.datagroups else '20201031'
        GivenNames = self.datagroups["GivenNames"] if "GivenNames" in self.datagroups else 'ERIKA'
        FamilyNames = self.datagroups["FamilyNames"] if "FamilyNames" in self.datagroups else 'MUSTERMANN'
        ReligiousArtisticName = self.datagroups["ReligiousArtisticName"] if "ReligiousArtisticName" in self.datagroups else ''
        AcademicTitle = self.datagroups["AcademicTitle"] if "AcademicTitle" in self.datagroups else ''
        DateOfBirth = self.datagroups["DateOfBirth"] if "DateOfBirth" in self.datagroups else '19640812'
        PlaceOfBirth = self.datagroups["PlaceOfBirth"] if "PlaceOfBirth" in self.datagroups else 'BERLIN'
        Nationality = self.datagroups["Nationality"] if "Nationality" in self.datagroups else 'DE'
        Sex = self.datagroups["Sex"] if "Sex" in self.datagroups else 'F'
        Country = self.datagroups["Country"] if "Country" in self.datagroups else 'D'
        City = self.datagroups["City"] if "City" in self.datagroups else 'KOLN'
        ZIP = self.datagroups["ZIP"] if "ZIP" in self.datagroups else '51147'
        Street = self.datagroups["Street"] if "Street" in self.datagroups else 'HEIDESTRASSE 17'
        CommunityID = eval(self.datagroups["CommunityID"])  if "CommunityID" in self.datagroups else '\x12\x34\x56\x78\x90\x12\x34'
        dg1 =  pack([(0x61, 0, [(0x13, 0, DocumentType)])], True)
        dg2 =  pack([(0x62, 0, [(0x13, 0, IssuingState)])], True)
        dg3 =  pack([(0x63, 0, [(0x12, 0, DateOfExpiry)])], True)
        dg4 =  pack([(0x64, 0, [(0x0C, 0, GivenNames)])], True)
        dg5 =  pack([(0x65, 0, [(0x0C, 0, FamilyNames)])], True)
        dg6 =  pack([(0x66, 0, [(0x0C, 0, ReligiousArtisticName)])], True)
        dg7 =  pack([(0x67, 0, [(0x0C, 0, AcademicTitle)])], True)
        dg8 =  pack([(0x68, 0, [(0x12, 0, DateOfBirth)])], True)
        dg9 =  pack([(0x69, 0, [(0xA1, 0, [(0x0C, 0, PlaceOfBirth)])])], True)
        dg10 = pack([(0x6A, 0, [(0x13, 0, Nationality)])], True)
        dg11 = pack([(0x6B, 0, [(0x13, 0, Sex)])], True)
        dg12 = self.datagroups["dg12"] if "dg12" in self.datagroups else ''
        dg13 = self.datagroups["dg13"] if "dg13" in self.datagroups else ''
        dg14 = self.datagroups["dg14"] if "dg14" in self.datagroups else ''
        dg15 = self.datagroups["dg15"] if "dg15" in self.datagroups else ''
        dg16 = self.datagroups["dg16"] if "dg16" in self.datagroups else ''
        dg17 = pack([(0x71, 0, [(0x30, 0, [
                (0xAA, 0, [(0x0C, 0, Street)]),
                (0xAB, 0, [(0x0C, 0, City)]),
                (0xAD, 0, [(0x13, 0, Country)]),
                (0xAE, 0, [(0x13, 0, ZIP)])
                ])])], True)
        dg18 = pack([(0x72, 0, [(0x04, 0, CommunityID)])], True)
        dg19 = self.datagroups["dg19"] if "dg19" in self.datagroups else ''
        dg20 = self.datagroups["dg20"] if "dg20" in self.datagroups else ''
        dg21 = self.datagroups["dg21"] if "dg21" in self.datagroups else ''
        eid.append(TransparentStructureEF(parent=eid, fid=0x0101, shortfid=0x01, data=dg1))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0102, shortfid=0x02, data=dg2))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0103, shortfid=0x03, data=dg3))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0104, shortfid=0x04, data=dg4))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0105, shortfid=0x05, data=dg5))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0106, shortfid=0x06, data=dg6))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0107, shortfid=0x07, data=dg7))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0108, shortfid=0x08, data=dg8))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0109, shortfid=0x09, data=dg9))
        eid.append(TransparentStructureEF(parent=eid, fid=0x010a, shortfid=0x0a, data=dg10))
        eid.append(TransparentStructureEF(parent=eid, fid=0x010b, shortfid=0x0b, data=dg11))
        eid.append(TransparentStructureEF(parent=eid, fid=0x010c, shortfid=0x0c, data=dg12))
        eid.append(TransparentStructureEF(parent=eid, fid=0x010d, shortfid=0x0d, data=dg13))
        eid.append(TransparentStructureEF(parent=eid, fid=0x010e, shortfid=0x0e, data=dg14))
        eid.append(TransparentStructureEF(parent=eid, fid=0x010f, shortfid=0x0f, data=dg15))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0110, shortfid=0x10, data=dg16))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0111, shortfid=0x11, data=dg17))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0112, shortfid=0x12, data=dg18))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0113, shortfid=0x13, data=dg19))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0114, shortfid=0x14, data=dg20))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0115, shortfid=0x15, data=dg21))
        self.mf.append(eid)

        self.sam = nPA_SAM(pin="111111", can="222222", mrz="IDD<<T220001293<<<<<<<<<<<<<<<6408125<2010315D<<<<<<<<<<<<<<MUSTERMANN<<ERIKA<<<<<<<<<<<<<", puk="3333333333", mf=self.mf)
        # FIXME add CVCA for inspection systems and signature terminals. Here we only add the eID CVCA.
        self.sam.current_SE.cvca = '\x7f\x21\x82\x01\xb6\x7f\x4e\x82\x01\x6e\x5f\x29\x01\x00\x42\x0e\x44\x45\x43\x56\x43\x41\x65\x49\x44\x30\x30\x31\x30\x32\x7f\x49\x82\x01\x1d\x06\x0a\x04\x00\x7f\x00\x07\x02\x02\x02\x02\x03\x81\x20\xa9\xfb\x57\xdb\xa1\xee\xa9\xbc\x3e\x66\x0a\x90\x9d\x83\x8d\x72\x6e\x3b\xf6\x23\xd5\x26\x20\x28\x20\x13\x48\x1d\x1f\x6e\x53\x77\x82\x20\x7d\x5a\x09\x75\xfc\x2c\x30\x57\xee\xf6\x75\x30\x41\x7a\xff\xe7\xfb\x80\x55\xc1\x26\xdc\x5c\x6c\xe9\x4a\x4b\x44\xf3\x30\xb5\xd9\x83\x20\x26\xdc\x5c\x6c\xe9\x4a\x4b\x44\xf3\x30\xb5\xd9\xbb\xd7\x7c\xbf\x95\x84\x16\x29\x5c\xf7\xe1\xce\x6b\xcc\xdc\x18\xff\x8c\x07\xb6\x84\x41\x04\x8b\xd2\xae\xb9\xcb\x7e\x57\xcb\x2c\x4b\x48\x2f\xfc\x81\xb7\xaf\xb9\xde\x27\xe1\xe3\xbd\x23\xc2\x3a\x44\x53\xbd\x9a\xce\x32\x62\x54\x7e\xf8\x35\xc3\xda\xc4\xfd\x97\xf8\x46\x1a\x14\x61\x1d\xc9\xc2\x77\x45\x13\x2d\xed\x8e\x54\x5c\x1d\x54\xc7\x2f\x04\x69\x97\x85\x20\xa9\xfb\x57\xdb\xa1\xee\xa9\xbc\x3e\x66\x0a\x90\x9d\x83\x8d\x71\x8c\x39\x7a\xa3\xb5\x61\xa6\xf7\x90\x1e\x0e\x82\x97\x48\x56\xa7\x86\x41\x04\x33\x47\xec\xf9\x6f\xfb\x4b\xd9\xb8\x55\x4e\xfb\xcc\xfc\x7d\x0b\x24\x2f\x10\x71\xe2\x9b\x4c\x9c\x62\x2c\x79\xe3\x39\xd8\x40\xaf\x67\xbe\xb9\xb9\x12\x69\x22\x65\xd9\xc1\x6c\x62\x57\x3f\x45\x79\xff\xd4\xde\x2d\xe9\x2b\xab\x40\x9d\xd5\xc5\xd4\x82\x44\xa9\xf7\x87\x01\x01\x5f\x20\x0e\x44\x45\x43\x56\x43\x41\x65\x49\x44\x30\x30\x31\x30\x32\x7f\x4c\x12\x06\x09\x04\x00\x7f\x00\x07\x03\x01\x02\x02\x53\x05\xfe\x0f\x01\xff\xff\x5f\x25\x06\x01\x00\x01\x00\x01\x08\x5f\x24\x06\x01\x03\x01\x00\x01\x08\x5f\x37\x40\x50\x67\x14\x5c\x68\xca\xe9\x52\x0f\x5b\xb3\x48\x17\xf1\xca\x9c\x43\x59\x3d\xb5\x64\x06\xc6\xa3\xb0\x06\xcb\xf3\xf3\x14\xe7\x34\x9a\xcf\x0c\xc6\xbf\xeb\xcb\xde\xfd\x10\xb4\xdc\xf0\xf2\x31\xda\x56\x97\x7d\x88\xf9\xf9\x01\x82\xd1\x99\x07\x6a\x56\x50\x64\x51'

    def __generate_cryptoflex(self):
        """Generate the Filesystem and SAM of a cryptoflex card"""
        from virtualsmartcard.cards.cryptoflex import CryptoflexMF, CryptoflexSAM
        self.mf = CryptoflexMF()
        self.mf.append(TransparentStructureEF(parent=self.mf, fid=0x0002,
                       filedescriptor=0x01,
                       data="\x00\x00\x00\x01\x00\x01\x00\x00")) #EF.ICCSN
        self.sam = CryptoflexSAM(self.mf)
        
    def generateCard(self):
        """Generate a new card"""
        if self.type == 'iso7816':
            self.__generate_iso_card()
        elif self.type == 'ePass':
            self.__generate_ePass()
        elif self.type == 'cryptoflex':
            self.__generate_cryptoflex()
        elif self.type == 'nPA':
            self.__generate_nPA()
        else:
            return (None, None)
    
    def getCard(self):
        """Get the MF and SAM from the current card"""
        if self.sam is None or self.mf is None:
            self.generateCard()
        return self.mf, self.sam
    
    def setCard(self, mf=None, sam=None):
        """Set the MF and SAM of the current card"""
        if mf != None:
            self.mf = mf
        if sam != None:
            self.sam = sam
        
    
    def loadCard(self, filename):
        """Load a card from disk"""
        db = anydbm.open(filename, 'r')
        
        if self.password is None:
            self.password = getpass.getpass("Please enter your password:"******"mf"], self.password)
        serializedSAM = read_protected_string(db["sam"], self.password)
        self.sam = loads(serializedSAM)
        self.mf = loads(serializedMF)
        self.type = db["type"]
            
    def saveCard(self, filename):
        """Save the currently running card to disk"""
        if self.password is None:
            passwd1 = getpass.getpass("Please enter your password:"******"Please retype your password:"******"Passwords did not match. Will now exit")
            else:
                self.password = passwd1
        
        if self.mf == None or self.sam == None:
            raise ValueError("Card Generator wasn't set up properly" +\
                 "(missing MF or SAM).")
        
        mf_string = dumps(self.mf)
        sam_string = dumps(self.sam)
        protectedMF = protect_string(mf_string, self.password)
        protectedSAM = protect_string(sam_string, self.password)
        
        db = anydbm.open(filename, 'c')
        db["mf"] = protectedMF
        db["sam"] = protectedSAM
        db["type"] = self.type
        db["version"] = "0.1"
        db.close()

    def readDatagroups(self, datasetfile):
        """Read Datagroups from file"""
        with open(datasetfile, 'r') as f:
		for line in f:
			if not line.startswith("#"):
				line=line.replace(" =", "=")
				line=line.replace("= ", "=")
				splitLine = line.split("=")
				self.datagroups[splitLine[0]] = splitLine[1]
	f.close()
Esempio n. 4
0
class CardGenerator(object):
    """This class is used to generate the SAM and filesystem for the 
    different supported card types. It is also able used for persistent storage
    (in encrypted form) of the card on disks. """
    
    def __init__(self, card_type=None, sam=None, mf=None):
        self.type = card_type
        self.mf = mf
        self.sam = sam
        self.password = None
    
    def __generate_iso_card(self):
        default_pin = "1234"
        default_cardno = "1234567890"
        
        logging.warning("Using default SAM parameters. PIN=%s, Card Nr=%s"
                        % (default_pin, default_cardno))
        #TODO: Use user provided data
        self.sam = SAM(default_pin, default_cardno)
        
        self.mf = MF(filedescriptor=FDB["DF"])
        self.sam.set_MF(self.mf)
           
    def __generate_ePass(self):
        """Generate the MF and SAM of an ICAO passport. This method is 
        responsible for generating the filesystem and filling it with content.
        Therefore it must interact with the user by prompting for the MRZ and
        optionally for the path to a photo."""
        from PIL import Image
        from virtualsmartcard.cards.ePass import PassportSAM
            
        #TODO: Sanity checks
        MRZ = raw_input("Please enter the MRZ as one string: ")

        readline.set_completer_delims("")
        readline.parse_and_bind("tab: complete")
        
        picturepath = raw_input("Please enter the path to an image: ")
        picturepath = picturepath.strip()
        
        #MRZ1 = "P<UTOERIKSSON<<ANNA<MARIX<<<<<<<<<<<<<<<<<<<"
        #MRZ2 = "L898902C<3UTO6908061F9406236ZE184226B<<<<<14"
        #MRZ = MRZ1 + MRZ2        

        try:
            im = Image.open(picturepath)
            pic_width, pic_height = im.size
            fd = open(picturepath,"rb")
            picture = fd.read()
            fd.close()
        except IOError:
            logging.warning("Failed to open file: " + picturepath)
            pic_width = 0
            pic_height = 0
            picture = None  

        mf = MF()
        
        #We need a MF with Application DF \xa0\x00\x00\x02G\x10\x01
        df = DF(parent=mf, fid=4, dfname='\xa0\x00\x00\x02G\x10\x01',
                bertlv_data=[])

        #EF.COM
        COM = pack([(0x5F01, 4, "0107"), (0x5F36, 6, "040000"),
                    (0x5C, 2, "6175")])
        COM = pack(((0x60, len(COM), COM),))
        df.append(TransparentStructureEF(parent=df, fid=0x011E,
                  filedescriptor=0, data=COM))

        #EF.DG1
        DG1 = pack([(0x5F1F, len(MRZ), MRZ)])
        DG1 = pack([(0x61, len(DG1), DG1)])
        df.append(TransparentStructureEF(parent=df, fid=0x0101,
                  filedescriptor=0, data=DG1))

        #EF.DG2
        if picture != None:
            IIB = "\x00\x01" + inttostring(pic_width, 2) +\
                    inttostring(pic_height, 2) + 6 * "\x00" 
            length = 32 + len(picture) #32 is the length of IIB + FIB
            FIB = inttostring(length, 4) + 16 * "\x00"
            FRH = "FAC" + "\x00" + "010" + "\x00" +\
                    inttostring(14 + length, 4) + inttostring(1, 2)
            picture = FRH + FIB + IIB + picture
            DG2 = pack([(0xA1, 8, "\x87\x02\x01\x01\x88\x02\x05\x01"), 
                    (0x5F2E, len(picture), picture)])
            DG2 = pack([(0x02, 1, "\x01"), (0x7F60, len(DG2), DG2)])
            DG2 = pack([(0x7F61, len(DG2), DG2)])
        else:
            DG2 = ""
        df.append(TransparentStructureEF(parent=df, fid=0x0102,
                  filedescriptor=0, data=DG2))

        #EF.SOD
        df.append(TransparentStructureEF(parent=df, fid=0x010D,
                  filedescriptor=0, data=""))

        mf.append(df)

        self.mf = mf
        self.sam = PassportSAM(self.mf)
    
    def __generate_nPA(self):
        from virtualsmartcard.cards.nPA import nPA_SAM
        for oid_base, x_list, y_list, algo in [
                ('\x04\x00\x7f\x00\x07\x02\x02\x04', range(1,5), range(1,5), "PACE"),
                ('\x04\x00\x7f\x00\x07\x02\x02\x02', range(1,3), range(1,6), "TA"),
                ('\x04\x00\x7f\x00\x07\x02\x02\x02', [1],        [6],        "TA"),
                ('\x04\x00\x7f\x00\x07\x02\x02\x03', range(1,3), range(1,5), "CA"),
                ('\x04\x00\x7f\x00\x07\x02\x02\x05', range(1,3), range(1,6), "RI"),
                ]:
            for oid in [oid_base+chr(x)+chr(y) for x in x_list for y in y_list]:
                ALGO_MAPPING[oid] = algo
        ALGO_MAPPING["\x04\x00\x7f\x00\x07\x03\x01\x04\x03"] = "CommunityID"
        ALGO_MAPPING["\x04\x00\x7f\x00\x07\x03\x01\x04\x02"] = "DateOfExpiry"
        ALGO_MAPPING["\x04\x00\x7f\x00\x07\x03\x01\x04\x01"] = "DateOfBirth"

        self.mf = MF()

        card_access =  "\x31\x81\xb3\x30\x0d\x06\x08\x04\x00\x7f\x00\x07\x02\x02\x02\x02\x01\x02\x30\x12\x06\x0a\x04\x00\x7f\x00\x07\x02\x02\x03\x02\x02\x02\x01\x02\x02\x01\x41\x30\x12\x06\x0a\x04\x00\x7f\x00\x07\x02\x02\x03\x02\x02\x02\x01\x02\x02\x01\x45\x30\x12\x06\x0a\x04\x00\x7f\x00\x07\x02\x02\x04\x02\x02\x02\x01\x02\x02\x01\x0d\x30\x1c\x06\x09\x04\x00\x7f\x00\x07\x02\x02\x03\x02\x30\x0c\x06\x07\x04\x00\x7f\x00\x07\x01\x02\x02\x01\x0d\x02\x01\x41\x30\x1c\x06\x09\x04\x00\x7f\x00\x07\x02\x02\x03\x02\x30\x0c\x06\x07\x04\x00\x7f\x00\x07\x01\x02\x02\x01\x0d\x02\x01\x45\x30\x2a\x06\x08\x04\x00\x7f\x00\x07\x02\x02\x06\x16\x1e\x68\x74\x74\x70\x3a\x2f\x2f\x62\x73\x69\x2e\x62\x75\x6e\x64\x2e\x64\x65\x2f\x63\x69\x66\x2f\x6e\x70\x61\x2e\x78\x6d\x6c"
        self.mf.append(TransparentStructureEF(parent=self.mf, fid=0x011c, shortfid=0x1c, data=card_access))
        card_security = "\x30\x82\x05\xA0\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02\xA0\x82\x05\x91\x30\x82\x05\x8D\x02\x01\x03\x31\x0F\x30\x0D\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x30\x82\x01\x48\x06\x08\x04\x00\x7F\x00\x07\x03\x02\x01\xA0\x82\x01\x3A\x04\x82\x01\x36\x31\x82\x01\x32\x30\x0D\x06\x08\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x01\x02\x30\x12\x06\x0A\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x02\x02\x01\x02\x02\x01\x41\x30\x12\x06\x0A\x04\x00\x7F\x00\x07\x02\x02\x04\x02\x02\x02\x01\x02\x02\x01\x0D\x30\x17\x06\x0A\x04\x00\x7F\x00\x07\x02\x02\x05\x02\x03\x30\x09\x02\x01\x01\x02\x01\x43\x01\x01\xFF\x30\x17\x06\x0A\x04\x00\x7F\x00\x07\x02\x02\x05\x02\x03\x30\x09\x02\x01\x01\x02\x01\x44\x01\x01\x00\x30\x19\x06\x09\x04\x00\x7F\x00\x07\x02\x02\x05\x02\x30\x0C\x06\x07\x04\x00\x7F\x00\x07\x01\x02\x02\x01\x0D\x30\x1C\x06\x09\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x30\x0C\x06\x07\x04\x00\x7F\x00\x07\x01\x02\x02\x01\x0D\x02\x01\x41\x30\x2A\x06\x08\x04\x00\x7F\x00\x07\x02\x02\x06\x16\x1E\x68\x74\x74\x70\x3A\x2F\x2F\x62\x73\x69\x2E\x62\x75\x6E\x64\x2E\x64\x65\x2F\x63\x69\x66\x2F\x6E\x70\x61\x2E\x78\x6D\x6C\x30\x62\x06\x09\x04\x00\x7F\x00\x07\x02\x02\x01\x02\x30\x52\x30\x0C\x06\x07\x04\x00\x7F\x00\x07\x01\x02\x02\x01\x0D\x03\x42\x00\x04\x92\x5D\xB4\xE1\x7A\xDE\x58\x20\x9F\x96\xFA\xA0\x7F\x1F\x8A\x22\x3F\x82\x3F\x96\xCC\x5D\x78\xCB\xEF\x5D\x17\x42\x20\x88\xFD\xD5\x8E\x56\xBC\x42\x50\xDE\x33\x46\xB3\xC8\x32\xCA\xE4\x86\x35\xFB\x6C\x43\x78\x9D\xE8\xB3\x10\x2F\x43\x93\xB4\x18\xE2\x4A\x13\xD9\x02\x01\x41\xA0\x82\x03\x1C\x30\x82\x03\x18\x30\x82\x02\xBC\xA0\x03\x02\x01\x02\x02\x02\x01\x5C\x30\x0C\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x02\x05\x00\x30\x4F\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x0D\x30\x0B\x06\x03\x55\x04\x0A\x0C\x04\x62\x75\x6E\x64\x31\x0C\x30\x0A\x06\x03\x55\x04\x0B\x0C\x03\x62\x73\x69\x31\x0C\x30\x0A\x06\x03\x55\x04\x05\x13\x03\x30\x31\x33\x31\x15\x30\x13\x06\x03\x55\x04\x03\x0C\x0C\x63\x73\x63\x61\x2D\x67\x65\x72\x6D\x61\x6E\x79\x30\x1E\x17\x0D\x31\x30\x31\x30\x30\x35\x31\x31\x30\x37\x35\x32\x5A\x17\x0D\x32\x31\x30\x34\x30\x35\x30\x38\x33\x39\x34\x37\x5A\x30\x47\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x1D\x30\x1B\x06\x03\x55\x04\x0A\x0C\x14\x42\x75\x6E\x64\x65\x73\x64\x72\x75\x63\x6B\x65\x72\x65\x69\x20\x47\x6D\x62\x48\x31\x0C\x30\x0A\x06\x03\x55\x04\x05\x13\x03\x30\x37\x34\x31\x0B\x30\x09\x06\x03\x55\x04\x03\x0C\x02\x44\x53\x30\x82\x01\x13\x30\x81\xD4\x06\x07\x2A\x86\x48\xCE\x3D\x02\x01\x30\x81\xC8\x02\x01\x01\x30\x28\x06\x07\x2A\x86\x48\xCE\x3D\x01\x01\x02\x1D\x00\xD7\xC1\x34\xAA\x26\x43\x66\x86\x2A\x18\x30\x25\x75\xD1\xD7\x87\xB0\x9F\x07\x57\x97\xDA\x89\xF5\x7E\xC8\xC0\xFF\x30\x3C\x04\x1C\x68\xA5\xE6\x2C\xA9\xCE\x6C\x1C\x29\x98\x03\xA6\xC1\x53\x0B\x51\x4E\x18\x2A\xD8\xB0\x04\x2A\x59\xCA\xD2\x9F\x43\x04\x1C\x25\x80\xF6\x3C\xCF\xE4\x41\x38\x87\x07\x13\xB1\xA9\x23\x69\xE3\x3E\x21\x35\xD2\x66\xDB\xB3\x72\x38\x6C\x40\x0B\x04\x39\x04\x0D\x90\x29\xAD\x2C\x7E\x5C\xF4\x34\x08\x23\xB2\xA8\x7D\xC6\x8C\x9E\x4C\xE3\x17\x4C\x1E\x6E\xFD\xEE\x12\xC0\x7D\x58\xAA\x56\xF7\x72\xC0\x72\x6F\x24\xC6\xB8\x9E\x4E\xCD\xAC\x24\x35\x4B\x9E\x99\xCA\xA3\xF6\xD3\x76\x14\x02\xCD\x02\x1D\x00\xD7\xC1\x34\xAA\x26\x43\x66\x86\x2A\x18\x30\x25\x75\xD0\xFB\x98\xD1\x16\xBC\x4B\x6D\xDE\xBC\xA3\xA5\xA7\x93\x9F\x02\x01\x01\x03\x3A\x00\x04\x3D\x6A\x7C\x2A\x6F\x20\x5F\x83\x9B\x04\x14\xEC\x58\xC6\xC7\x1B\x75\xF5\x15\xDE\xC3\xAE\x73\x3B\x5F\x47\x88\xDD\xC8\x15\xF0\x5B\xC1\xF6\x53\x8F\xD9\x69\x54\xE1\xF8\x40\xA2\xE2\x18\x99\x62\xCC\xAA\x14\x90\x08\x24\xC7\xDD\xB9\xA3\x81\xD1\x30\x81\xCE\x30\x0E\x06\x03\x55\x1D\x0F\x01\x01\xFF\x04\x04\x03\x02\x07\x80\x30\x1F\x06\x03\x55\x1D\x23\x04\x18\x30\x16\x80\x14\x60\x44\xF2\x45\xF2\xE0\x71\xD4\xD5\x64\xF4\xE5\x77\xD6\x36\x69\xDB\xEB\x18\x59\x30\x41\x06\x03\x55\x1D\x20\x04\x3A\x30\x38\x30\x36\x06\x09\x04\x00\x7F\x00\x07\x03\x01\x01\x01\x30\x29\x30\x27\x06\x08\x2B\x06\x01\x05\x05\x07\x02\x01\x16\x1B\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x62\x73\x69\x2E\x62\x75\x6E\x64\x2E\x64\x65\x2F\x63\x73\x63\x61\x30\x2B\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x15\x04\x1E\x04\x1C\x31\x2E\x32\x2E\x32\x37\x36\x2E\x30\x2E\x38\x30\x2E\x31\x2E\x31\x32\x2E\x30\x2E\x32\x30\x2E\x35\x2E\x31\x2E\x30\x30\x2B\x06\x03\x55\x1D\x10\x04\x24\x30\x22\x80\x0F\x32\x30\x31\x30\x31\x30\x30\x35\x31\x31\x30\x37\x35\x32\x5A\x81\x0F\x32\x30\x31\x31\x30\x32\x30\x35\x30\x39\x33\x39\x34\x37\x5A\x30\x0C\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x02\x05\x00\x03\x48\x00\x30\x45\x02\x20\x13\xE9\xE1\x7A\x9E\xFE\x8B\xD7\xD7\x27\x62\x92\x30\x5B\xCC\xC3\x2B\x70\xC2\xB7\x60\x40\xF4\x88\x30\x66\x62\x26\xCD\x6A\x4B\xF4\x02\x21\x00\x87\xF4\x71\xE2\x44\x35\xB4\xC3\x4A\xF3\x57\x30\x94\xFB\x1F\x1C\x2A\x48\xB1\x3E\xE5\xED\x67\xF1\x72\x6D\xCF\x56\xE3\x84\xE3\x6F\x31\x82\x01\x09\x30\x82\x01\x05\x02\x01\x01\x30\x55\x30\x4F\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x44\x45\x31\x0D\x30\x0B\x06\x03\x55\x04\x0A\x0C\x04\x62\x75\x6E\x64\x31\x0C\x30\x0A\x06\x03\x55\x04\x0B\x0C\x03\x62\x73\x69\x31\x0C\x30\x0A\x06\x03\x55\x04\x05\x13\x03\x30\x31\x33\x31\x15\x30\x13\x06\x03\x55\x04\x03\x0C\x0C\x63\x73\x63\x61\x2D\x67\x65\x72\x6D\x61\x6E\x79\x02\x02\x01\x5C\x30\x0D\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\xA0\x4A\x30\x17\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x03\x31\x0A\x06\x08\x04\x00\x7F\x00\x07\x03\x02\x01\x30\x2F\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x04\x31\x22\x04\x20\xEF\x0F\xDA\x94\x2E\x5A\x0F\x6F\xC9\xC5\x46\xEE\x01\xF9\x10\x31\x43\x64\x30\xF7\x5E\x9D\x36\x54\xD3\x69\x30\x9E\x8B\xE7\x17\x48\x30\x0C\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x02\x05\x00\x04\x40\x30\x3E\x02\x1D\x00\x89\x75\x92\x5B\xE1\x31\xB7\x7C\x95\x8C\x3E\xCB\x2A\x5C\x67\xFC\x5C\xE3\x1C\xBD\x01\x41\xE3\x4B\xC7\xF0\xA4\x47\x02\x1D\x00\xCC\x65\xE6\x2D\xDC\xF2\x93\x96\x4B\x22\xD7\xB5\x10\xD7\x81\x88\x07\xC8\x95\x96\xBD\x34\xD8\xF9\xBB\x4C\x05\x27"
        self.mf.append(TransparentStructureEF(parent=self.mf, fid=0x011d, shortfid=0x1d, data=card_security))

        eid=DF(parent=self.mf, fid=0xffff, dfname='\xe8\x07\x04\x00\x7f\x00\x07\x03\x02')
        # FIXME access control for eid application
        dg1 = ''
        dg2 = ''
        dg3 = ''
        dg4 = ''
        dg5 = ''
        dg6 = ''
        dg7 = ''
        dg8 = ''
        dg9 = ''
        dg10 = ''
        dg11 = ''
        dg12 = ''
        dg13 = ''
        dg14 = ''
        dg15 = ''
        dg16 = ''
        dg17 = ''
        dg18 = ''
        dg19 = ''
        dg20 = ''
        dg21 = ''
        eid.append(TransparentStructureEF(parent=eid, fid=0x0101, shortfid=0x01, data=dg1))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0102, shortfid=0x02, data=dg2))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0103, shortfid=0x03, data=dg3))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0104, shortfid=0x04, data=dg4))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0105, shortfid=0x05, data=dg5))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0106, shortfid=0x06, data=dg6))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0107, shortfid=0x07, data=dg7))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0108, shortfid=0x08, data=dg8))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0109, shortfid=0x09, data=dg9))
        eid.append(TransparentStructureEF(parent=eid, fid=0x010a, shortfid=0x0a, data=dg10))
        eid.append(TransparentStructureEF(parent=eid, fid=0x010b, shortfid=0x0b, data=dg11))
        eid.append(TransparentStructureEF(parent=eid, fid=0x010c, shortfid=0x0c, data=dg12))
        eid.append(TransparentStructureEF(parent=eid, fid=0x010d, shortfid=0x0d, data=dg13))
        eid.append(TransparentStructureEF(parent=eid, fid=0x010e, shortfid=0x0e, data=dg14))
        eid.append(TransparentStructureEF(parent=eid, fid=0x010f, shortfid=0x0f, data=dg15))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0110, shortfid=0x10, data=dg16))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0111, shortfid=0x11, data=dg17))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0112, shortfid=0x12, data=dg18))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0113, shortfid=0x13, data=dg19))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0114, shortfid=0x14, data=dg20))
        eid.append(TransparentStructureEF(parent=eid, fid=0x0115, shortfid=0x15, data=dg21))
        self.mf.append(eid)

        self.sam = nPA_SAM(pin="111111", can="222222", mrz="mrz", puk="puk", mf=self.mf)

    def __generate_cryptoflex(self):
        """Generate the Filesystem and SAM of a cryptoflex card"""
        from virtualsmartcard.cards.cryptoflex import CryptoflexMF, CryptoflexSAM
        self.mf = CryptoflexMF()
        self.mf.append(TransparentStructureEF(parent=self.mf, fid=0x0002,
                       filedescriptor=0x01,
                       data="\x00\x00\x00\x01\x00\x01\x00\x00")) #EF.ICCSN
        self.sam = CryptoflexSAM(self.mf)
        
    def generateCard(self):
        """Generate a new card"""
        if self.type == 'iso7816':
            self.__generate_iso_card()
        elif self.type == 'ePass':
            self.__generate_ePass()
        elif self.type == 'cryptoflex':
            self.__generate_cryptoflex()
        elif self.type == 'nPA':
            self.__generate_nPA()
        else:
            return (None, None)
    
    def getCard(self):
        """Get the MF and SAM from the current card"""
        if self.sam is None or self.mf is None:
            self.generateCard()
        return self.mf, self.sam
    
    def setCard(self, mf=None, sam=None):
        """Set the MF and SAM of the current card"""
        if mf != None:
            self.mf = mf
        if sam != None:
            self.sam = sam
        
    
    def loadCard(self, filename):
        """Load a card from disk"""
        db = anydbm.open(filename, 'r')
        
        if self.password is None:
            self.password = getpass.getpass("Please enter your password:"******"mf"], self.password)
        serializedSAM = read_protected_string(db["sam"], self.password)
        self.sam = loads(serializedSAM)
        self.mf = loads(serializedMF)
        self.type = db["type"]
            
    def saveCard(self, filename):
        """Save the currently running card to disk"""
        if self.password is None:
            passwd1 = getpass.getpass("Please enter your password:"******"Please retype your password:"******"Passwords did not match. Will now exit")
            else:
                self.password = passwd1
        
        if self.mf == None or self.sam == None:
            raise ValueError("Card Generator wasn't set up properly" +\
                 "(missing MF or SAM).")
        
        mf_string = dumps(self.mf)
        sam_string = dumps(self.sam)
        protectedMF = protect_string(mf_string, self.password)
        protectedSAM = protect_string(sam_string, self.password)
        
        db = anydbm.open(filename, 'c')
        db["mf"] = protectedMF
        db["sam"] = protectedSAM
        db["type"] = self.type
        db["version"] = "0.1"
        db.close()