Example #1
0
    def parse_SE_config(self, config):
        r = 0x9000
        try:
            ControlReferenceTemplate.parse_SE_config(self, config)
        except SwError as e:
            structure = unpack(config)
            for tlv in structure:
                tag, length, value = tlv
                if tag == 0x7f4c:
                    self.chat = CHAT(bertlv_pack([[tag, length, value]]))
                    print(self.chat)
                elif tag == 0x67:
                    self.auxiliary_data = bertlv_pack([[tag, length, value]])
                elif tag == 0x80 or tag == 0x84 or tag == 0x83 or tag == 0x91:
                    # handled by ControlReferenceTemplate.parse_SE_config
                    pass
                else:
                    raise SwError(SW["ERR_REFNOTUSABLE"])

        structure = unpack(config)

        pin_ref_str = '%c'% self.PACE_PIN
        for tlv in structure:
            if [0x83, len(pin_ref_str), pin_ref_str] == tlv:
                if self.sam.counter <= 0:
                    r = 0x63c0
                elif self.sam.counter == 1:
                    r = 0x63c1
                elif self.sam.counter == 2:
                    r = 0x63c2

        return r, ""
Example #2
0
    def verify(self, p1, p2, data):
        if p1 == 0x80 and p2 == 0x00:
            if self.current_SE.eac_step == 6:
                # data should only contain exactly OID
                [(tag, _, value)] = structure = unpack(data)
                if tag == 6:
                    mapped_algo = ALGO_MAPPING[value]
                    eid = self.mf.select("dfname", "\xe8\x07\x04\x00\x7f\x00\x07\x03\x02")
                    if mapped_algo == "DateOfExpiry":
                        [(_, _, [(_, _, mine)])] = unpack(eid.select("fid", 0x0103).data)
                        logging.info(
                            "DateOfExpiry: " + str(mine) + "; reference: " + str(self.current_SE.at.DateOfExpiry)
                        )
                        if self.current_SE.at.DateOfExpiry < mine:
                            print ("Date of expiry verified")
                            return SW["NORMAL"], ""
                        else:
                            print ("Date of expiry not verified (expired)")
                            return SW["WARN_NOINFO63"], ""
                    elif mapped_algo == "DateOfBirth":
                        [(_, _, [(_, _, mine)])] = unpack(eid.select("fid", 0x0108).data)
                        # case1: YYYYMMDD -> good
                        # case2: YYYYMM   -> mapped to last day of given month, i.e. YYYYMM31 ;-)
                        # case3: YYYY     -> mapped to YYYY-12-31
                        if len(str(mine)) == 6:
                            mine = int(str(mine) + "31")
                        elif len(str(mine)) == 4:
                            mine = int(str(mine) + "1231")
                        logging.info(
                            "DateOfBirth: " + str(mine) + "; reference: " + str(self.current_SE.at.DateOfExpiry)
                        )
                        if self.current_SE.at.DateOfBirth < mine:
                            print ("Date of birth verified (old enough)")
                            return SW["NORMAL"], ""
                        else:
                            print ("Date of birth not verified (too young)")
                            return SW["WARN_NOINFO63"], ""
                    elif mapped_algo == "CommunityID":
                        [(_, _, [(_, _, mine)])] = unpack(eid.select("fid", 0x0112).data)
                        mine = binascii.hexlify(mine)
                        logging.info(
                            "CommunityID: " + str(mine) + "; reference: " + str(self.current_SE.at.CommunityID)
                        )
                        if mine.startswith(self.current_SE.at.CommunityID):
                            print ("Community ID verified (living there)")
                            return SW["NORMAL"], ""
                        else:
                            print ("Community ID not verified (not living there)")
                            return SW["WARN_NOINFO63"], ""
                    else:
                        return SwError(SW["ERR_DATANOTFOUND"])
                else:
                    return SwError(SW["ERR_DATANOTFOUND"])

        else:
            return SAM.verify(self, p1, p2, data)
Example #3
0
    def verify_digital_signature(self, p1, p2, data):
        """
        Verify the digital signature contained in the data field. Data must
        contain a data to sign (tag 0x9A, 0xAC or 0xBC) and a digital signature
        (0x9E)
        """
        key = self.dst.key
        to_sign = ""
        signature = ""

        if key == None:
            raise SwError(SW["ERR_CONDITIONNOTSATISFIED"])

        structure = unpack(data)
        for tag, length, value in structure:
            if tag == 0x9E:
                signature = value
            elif tag == 0x9A: #FIXME: Correct treatment of all possible tags
                to_sign = value
            elif tag == 0xAC:
                pass
            elif tag == 0xBC:
                pass

        if to_sign == "" or signature == "":
            raise SwError(SW["ERR_SECMESSOBJECTSMISSING"])

        my_signature = key.sign(value)
        if my_signature == signature:
            return ""
        else:
            raise SwError(["ERR_SECMESSOBJECTSINCORRECT"])
Example #4
0
    def verify_cryptographic_checksum(self, p1, p2, data):
        """
        Verify the cryptographic checksum contained in the data field.
        Data field must contain a cryptographic checksum (tag 0x8E) and a plain
        value (tag 0x80)
        """
        plain = ""
        cct = ""

        algo = self.cct.algorithm
        key = self.cct.key
        iv = self.cct.iv
        if algo == None or key == None:
            raise SwError(SW["ERR_CONDITIONNOTSATISFIED"])

        structure = unpack(data)
        for tag, length, value in structure:
            if tag == 0x80:
                plain = value
            elif tag == 0x8E:
                cct = value
        if plain == "" or cct == "":
            raise SwError(SW["ERR_SECMESSOBJECTSMISSING"])
        else:
            my_cct = vsCrypto.crypto_checksum(algo, key, plain, iv)
            if my_cct == cct:
                return ""
            else:
                raise SwError["ERR_SECMESSOBJECTSINCORRECT"]
Example #5
0
    def compute_digital_signature(self, p1, p2, data):
        """
        Compute a digital signature for the given data.
        Algorithm and key are specified in the current SE
        
        :param p1: Must be 0x9E = Secure Messaging class for digital signatures
        :param p2: Must be one of 0x9A, 0xAC, 0xBC. Indicates what kind of data
            is included in the data field.
        """
        
        if p1 != 0x9E or not p2 in (0x9A, 0xAC, 0xBC):
            raise SwError(SW["ERR_INCORRECTP1P2"])

        if self.dst.key == None:
            raise SwError(SW["ERR_CONDITIONNOTSATISFIED"])

        to_sign = ""              
        if p2 == 0x9A: #Data to be signed
            to_sign = data
        elif p2 == 0xAC: #Data objects, sign values
            to_sign = ""
            structure = unpack(data)
            for tag, length, value in structure:
                to_sign += value
        elif p2 == 0xBC: #Data objects to be signed
            pass
        
        signature = self.dst.key.sign(to_sign, "")
        return signature
Example #6
0
    def parse_SE_config(self, config):
        """
        Parse a control reference template as given e.g. in an MSE APDU.

        :param config: a TLV string containing the configuration for the CRT.
        """
        error = False
        structure = unpack(config)
        for tlv in structure:
            tag, length, value = tlv
            if tag == 0x80:
                self.__set_algo(value)
            elif tag in (0x81, 0x82, 0x83, 0x84):
                self.__set_key(tag, value)
            elif tag in range(0x85, 0x93):
                self.__set_iv(tag, length, value)
            elif tag == 0x95:
                self.usage_qualifier = value
            else:
                error = True

        if error:
            raise SwError(SW["ERR_REFNOTUSABLE"])
        else:
            return SW["NORMAL"], ""
Example #7
0
 def __unpack_general_authenticate(data):
     data_structure = []
     structure = unpack(data)
     for tlv in structure:
         tag, length, value = tlv
         if tag == 0x7c:
             data_structure = value
         else:
             raise SwError(SW["ERR_INCORRECTPARAMETERS"])
     return data_structure
Example #8
0
    def parse_SE_config(self, config):
        r = 0x9000
        try:
            ControlReferenceTemplate.parse_SE_config(self, config)
        except SwError as e:
            structure = unpack(config)
            for tlv in structure:
                tag, length, value = tlv
                if tag == 0x7f4c:
                    self.chat = CHAT(bertlv_pack([[tag, length, value]]))
                    print(self.chat)
                elif tag == 0x67:
                    self.auxiliary_data = bertlv_pack([[tag, length, value]])
                elif tag == 0x80 or tag == 0x84 or tag == 0x83 or tag == 0x91:
                    # handled by ControlReferenceTemplate.parse_SE_config
                    pass
                else:
                    raise SwError(SW["ERR_REFNOTUSABLE"])

        return r, ""
Example #9
0
    def verify(self, p1, p2, data):
        if (p1 != 0x80 or p2 != 0x00):
            raise SwError(SW["ERR_INCORRECTP1P2"])

        if self.current_SE.eac_step == 6:
            structure = unpack(data)
            for tag, length, value in structure:
                if tag == 6 and ALGO_MAPPING[value] == "DateOfExpiry":
                    # hell yes, this is a valid nPA
                    # TODO actually check it...
                    return SW["NORMAL"], ""
                if tag == 6 and ALGO_MAPPING[value] == "DateOfBirth":
                    # hell yes, we are old enough
                    # TODO actually check it...
                    return SW["NORMAL"], ""
                if tag == 6 and ALGO_MAPPING[value] == "CommunityID":
                    # well OK, we are living there
                    # TODO actually check it...
                    return SW["NORMAL"], ""

        raise SwError(SW["WARN_NOINFO63"])
Example #10
0
    def parse_SE_config(self, config):
        r = 0x9000
        try:
            ControlReferenceTemplate.parse_SE_config(self, config)
        except SwError as e:
            structure = unpack(config)
            for tlv in structure:
                tag, length, value = tlv
                if tag == 0x7f4c:
                    self.chat = CHAT(bertlv_pack([[tag, length, value]]))
                elif tag == 0x67:
                    self.auxiliary_data = bertlv_pack([[tag, length, value]])
                    # extract reference values for verifying
                    # DateOfBirth, DateOfExpiry and CommunityID
                    for ddo in decodeDiscretionaryDataObjects(value):
                        try:
                            oidvalue = ddo[0][2]
                            reference = ddo[1][2]
                            mapped_algo = ALGO_MAPPING[oidvalue]
                            if mapped_algo == "DateOfBirth":
                                self.DateOfBirth = int(reference)
                                logging.info("Found reference DateOfBirth: " +
                                             str(self.DateOfBirth))
                            elif mapped_algo == "DateOfExpiry":
                                self.DateOfExpiry = int(reference)
                                logging.info("Found reference DateOfExpiry: " +
                                             str(self.DateOfExpiry))
                            elif mapped_algo == "CommunityID":
                                self.CommunityID = binascii.hexlify(reference)
                                logging.info("Found reference CommunityID: " +
                                             str(self.CommunityID))
                        except:
                            pass
                elif tag == 0x80 or tag == 0x84 or tag == 0x83 or tag == 0x91:
                    # handled by ControlReferenceTemplate.parse_SE_config
                    pass
                else:
                    raise SwError(SW["ERR_REFNOTUSABLE"])

        return r, ""
Example #11
0
    def parse_SM_CAPDU(self, CAPDU, authenticate_header):
        """
        This methods parses a data field including Secure Messaging objects.
        SM_header indicates whether or not the header of the message shall be 
        authenticated. It returns an unprotected command APDU
        
        :param CAPDU: The protected CAPDU to be parsed
        :param authenticate_header: Whether or not the header should be
            included in authentication mechanisms 
        :returns: Unprotected command APDU
        """
            
        structure = unpack(CAPDU.data)
        return_data = ["",]
        
        cla = None
        ins = None
        p1 = None
        p2 = None
        le = None
        
        if authenticate_header:
            to_authenticate = inttostring(CAPDU.cla) + inttostring(CAPDU.ins)+\
                              inttostring(CAPDU.p1) + inttostring(CAPDU.p2)
            to_authenticate = vsCrypto.append_padding(self.cct.blocklength, to_authenticate)
        else:
            to_authenticate = ""

        for tlv in structure:
            tag, length, value = tlv
            
            if tag % 2 == 1: #Include object in checksum calculation
                to_authenticate += bertlv_pack([[tag, length, value]])
            
            #SM data objects for encapsulating plain values
            if tag in (SM_Class["PLAIN_VALUE_NO_TLV"],
                       SM_Class["PLAIN_VALUE_NO_TLV_ODD"]):
                return_data.append(value) #FIXME: Need TLV coding?
            #Encapsulated SM objects. Parse them
            #FIXME: Need to pack value into a dummy CAPDU
            elif tag in (SM_Class["PLAIN_VALUE_TLV_INCULDING_SM"],
                         SM_Class["PLAIN_VALUE_TLV_INCULDING_SM_ODD"]):
                return_data.append(self.parse_SM_CAPDU(value, authenticate_header)) 
            #Encapsulated plaintext BER-TLV objects
            elif tag in (SM_Class["PLAIN_VALUE_TLV_NO_SM"],
                         SM_Class["PLAIN_VALUE_TLV_NO_SM_ODD"]):
                return_data.append(value)
            elif tag in (SM_Class["Ne"], SM_Class["Ne_ODD"]):
                le = value
            elif tag == SM_Class["PLAIN_COMMAND_HEADER"]:
                if len(value) != 8:
                    raise SwError(SW["ERR_SECMESSOBJECTSINCORRECT"])
                else:
                    cla = value[:2]
                    ins = value[2:4]
                    p1 = value[4:6]
                    p2 = value[6:8]

            #SM data objects for confidentiality
            if tag in (SM_Class["CRYPTOGRAM_PLAIN_TLV_INCLUDING_SM"],
                       SM_Class["CRYPTOGRAM_PLAIN_TLV_INCLUDING_SM_ODD"]):
                #The cryptogram includes SM objects. 
                #We decrypt them and parse the objects.
                plain = self.decipher(tag, 0x80, value)
                #TODO: Need Le = length
                return_data.append(self.parse_SM_CAPDU(plain, authenticate_header))
            elif tag in (SM_Class["CRYPTOGRAM_PLAIN_TLV_NO_SM"],
                         SM_Class["CRYPTOGRAM_PLAIN_TLV_NO_SM_ODD"]):
                #The cryptogram includes BER-TLV encoded plaintext. 
                #We decrypt them and return the objects.
                plain = self.decipher(tag, 0x80, value)
                return_data.append(plain)
            elif tag in (SM_Class["CRYPTOGRAM_PADDING_INDICATOR"],
                         SM_Class["CRYPTOGRAM_PADDING_INDICATOR_ODD"]):
                #The first byte of the data field indicates the padding to use:
                """
                Value        Meaning
                '00'     No further indication
                '01'     Padding as specified in 6.2.3.1
                '02'     No padding
                '1X'     One to four secret keys for enciphering information,
                         not keys ('X' is a bitmap with any value from '0' to 'F')
                '11'     indicates the first key (e.g., an "even" control word
                         in a pay TV system)
                '12'     indicates the second key (e.g., an "odd" control word
                         in a pay TV system)
                '13'     indicates the first key followed by the second key
                         (e.g., a pair of control words in a pay TV system)
                '2X'     Secret key for enciphering keys, not information
                         ('X' is a reference with any value from '0' to 'F')
                         (e.g., in a pay TV system, either an operational key
                         for enciphering control words, or a management key for
                         enciphering operational keys)
                '3X'     Private key of an asymmetric key pair ('X' is a
                         reference with any value from '0' to 'F')
                '4X'     Password ('X' is a reference with any value from '0' to
                         'F')
            '80' to '8E' Proprietary
                """
                padding_indicator = stringtoint(value[0])
                plain = self.decipher(tag, 0x80, value[1:])
                plain = vsCrypto.strip_padding(self.ct.blocklength, plain,
                                               padding_indicator)
                return_data.append(plain)

            #SM data objects for authentication 
            if tag == SM_Class["CHECKSUM"]:
                auth = vsCrypto.append_padding(self.cct.blocklength, to_authenticate)
                checksum = self.compute_cryptographic_checksum(0x8E,
                                                                   0x80,
                                                                   auth)
                if checksum != value:
                    raise SwError(SW["ERR_SECMESSOBJECTSINCORRECT"])
            elif tag == SM_Class["DIGITAL_SIGNATURE"]:
                auth = to_authenticate #FIXME: Need padding?
                signature = self.compute_digital_signature(0x9E, 0x9A, auth)
                if signature != value:
                    raise SwError(SW["ERR_SECMESSOBJECTSINCORRECT"])
            elif tag in (SM_Class["HASH_CODE"], SM_Class["HASH_CODE_ODD"]):
                hash = self.hash(p1, p2, to_authenticate)
                if hash != value:
                    raise SwError(SW["ERR_SECMESSOBJECTSINCORRECT"])
                
        #Form unprotected CAPDU
        if cla == None:
            cla = CAPDU.cla
        if ins == None:
            ins = CAPDU.ins
        if p1 == None:
            p1 = CAPDU.p1
        if p2 == None:
            p2 = CAPDU.p2
        if le == None:
            le = CAPDU.le
        # FIXME
        #if expected != "":
            #raise SwError(SW["ERR_SECMESSOBJECTSMISSING"])

        if isinstance(le, str):
            # FIXME C_APDU only handles le with strings of length 1. Better patch utils.py to support extended length apdus
            le_int = stringtoint(le)
            if le_int == 0 and len(le) > 1:
                le_int = MAX_EXTENDED_LE
            le = le_int
        
        c = C_APDU(cla=cla, ins=ins, p1=p1, p2=p2, le=le, data="".join(return_data))
        return c