Example #1
0
    def _extract_hash_segment_algorithm(self, hash_table_size=0):
        if hash_table_size > 0:
            hash_count = self.get_hash_table(get_hash_count=True)
            hash_size = hash_table_size / (hash_count + 2)  # add 2: +1 for Hash Table Entry 0 (ELF + Program Header). +1 for Hash Table Entry 1 (Dummy Entry)
            logger.debug("Number of hash entries: " + str(hash_count))
            logger.debug("Hash table size: " + str(hash_table_size))
            logger.debug("Hash size: " + str(hash_size))

            if hash_size in SecParseGenElf.HASH_SIZE_TO_ALGO_MAP.keys():
                self._mbn_parsegen.extracted_segment_hash_algorithm = SecParseGenElf.HASH_SIZE_TO_ALGO_MAP[hash_size]
            else:
                self._mbn_parsegen.extracted_segment_hash_algorithm = ParseGenMbn.UNKNOWN_ALGORITHM

            logger.debug("Determined hash table algorithm: " + self._mbn_parsegen.extracted_segment_hash_algorithm)

            # Determine if parsegen was created during validation (-a) and print error if hash algorithm mismatch is present
            extracted_segment_hash_algorithm = self._mbn_parsegen.extracted_segment_hash_algorithm
            segment_hash_algorithm = self.segment_hash_algorithm if self.segment_hash_algorithm is not None else "sha256"
            if extracted_segment_hash_algorithm != segment_hash_algorithm and (self.validating or self.is_encrypted()):
                from sectools.common.utils.c_misc import create_mismatch_table
                errstr = list()
                mismatches = list()
                mismatches.append(("Hash Segment Algorithm", extracted_segment_hash_algorithm, segment_hash_algorithm))
                create_mismatch_table(mismatches, errstr, data_type_to_compare="Attribute", image_region="Hash Segment")
                logger.warning('Following validations failed for the image:\n       ' +
                               '\n       '.join([(str(i + 1) + '. ' + e) for i, e in enumerate(errstr)]))
Example #2
0
 def validate_more(self,
                   parsegen,
                   imageinfo,
                   attribute_extractor,
                   cert_chain_der,
                   errstr,
                   exclude_attributes=None):
     # Signing attributes validation
     if imageinfo is not None:
         if not cert_chain_der:
             errstr.append(
                 'Certificate chain for ' + parsegen.authority +
                 ' is not present in image signing attributes verification')
         else:
             mismatches = self.validate_signing_attributes(
                 cert_chain_der,
                 imageinfo,
                 attribute_extractor.attributes,
                 excluded_attributes=exclude_attributes)
             create_mismatch_table(
                 mismatches,
                 errstr,
                 operation="signing",
                 data_type_to_compare="Attribute",
                 image_region=attribute_extractor.image_region)
     if errstr:
         raise RuntimeError(
             'Following validations failed for the image:\n       ' +
             '\n       '.join([
                 '%d. %s' % (signed_authority, e)
                 for signed_authority, e in enumerate(errstr, start=1)
             ]))
Example #3
0
        def _decode_binary_blob(self, binary_blob, validating):
            if len(binary_blob) != self.SPEC_SIZE_BYTES:
                raise RuntimeError(
                    "L2 Associated Data blob is of the wrong size")

            offset = 0
            end = self.L2_ASSOCIATED_DATA_SIZE_FLD_LEN_BYTES
            self.l2_associated_data_size, = struct.unpack(
                ">H", binary_blob[offset:end])

            offset = end + EncryptionParamsSectionBody_1_0_L2_1_0.RSVD_BYTE_LEN_BYTES * 2
            end = offset + self.MAJOR_VERSION_FLD_LEN_BYTES + \
                  self.MINOR_VERSION_FLD_LEN_BYTES + \
                  self.KEY_LADDER_LEN_FLD_LEN_BYTES + \
                  EncryptionParamsSectionBody_1_0_L2_1_0.RSVD_BYTE_LEN_BYTES

            major_version, minor_version, self.key_ladder_length, tmp = struct.unpack(
                "=BBBB", binary_blob[offset:end])
            offset = end

            if (major_version, minor_version) != (self.MAJOR_VERSION,
                                                  self.MINOR_VERSION):
                raise RuntimeError((
                    "Encryption Parameters L2 Associated Data version \"{0}.{1}\" does not match "
                    "expected version \"{2}.{3}\"\n       Ensure that the correct selected_encryptor value is "
                    "set.".format(major_version, minor_version,
                                  self.MAJOR_VERSION, self.MINOR_VERSION)))

            image_id = int(
                round(math.log(self._decode_image_id(binary_blob[offset:]),
                               2)))
            if image_id != self.image_id:
                if validating:
                    errstr = list()
                    mismatches = list()
                    mismatches.append(
                        ("sw_id", "0x%X" % image_id, "0x%X" % self.image_id))
                    create_mismatch_table(mismatches,
                                          errstr,
                                          operation="encryption",
                                          data_type_to_compare="Attribute",
                                          image_region="Encryption Parameters")
                    raise RuntimeError(
                        'Following validations failed for the image:\n       '
                        + '\n       '.join([(str(i + 1) + '. ' + e)
                                            for i, e in enumerate(errstr)]))
                else:
                    logger.warning(
                        ("Extracted Encryption Parameters sw_id"
                         " value \"{0}\" does not match config value "
                         "\"{1}\"\n\t Encryption Parameters sw_id value "
                         "will be updated with value \"{1}\"".format(
                             hex(image_id), hex(self.image_id))))
Example #4
0
    def validate_hash_segment_metadata(self, authority=None):
        from sectools.common.utils.c_misc import create_mismatch_table
        # Validate metedata for unsigned image.
        # If image is signed, validation is done in signer.
        if not self.is_signed(authority):
            hash_segment_metadata = self.get_hash_segment_metadata(authority)
            if hash_segment_metadata is not None:
                from sectools.features.isc.signer.signerutils.attribute_extractor import AttributeExtractor
                from sectools.features.isc.signer.signerutils.attributes import SigningAttributes
                errstr = []
                extracted_image_attributes = AttributeExtractor(
                    hash_segment_metadata=hash_segment_metadata).attributes
                attr_config = SigningAttributes()
                attr_config.update_from_image_info_attrs(self.imageinfo)
                mismatches = extracted_image_attributes.compare(
                    attr_config,
                    extracted_image_attributes.EXCLUDE_HASH_SEGMENT_METADATA)
                create_mismatch_table(mismatches,
                                      errstr,
                                      operation="signing",
                                      data_type_to_compare="Attribute",
                                      image_region="Hash Segment")
                if errstr:
                    raise RuntimeError(
                        'Following validations failed for the image:\n       '
                        + '\n       '.join([(str(authority + 1) + '. ' + e)
                                            for authority, e in enumerate(
                                                errstr)]))

        # Ensure metadata sw_ids match
        hash_segment_metadata = self.get_hash_segment_metadata(
            defines.AUTHORITY_OEM)
        hash_segment_metadata_qti = self.get_hash_segment_metadata(
            defines.AUTHORITY_QTI)
        if hash_segment_metadata and hash_segment_metadata_qti and hash_segment_metadata[
                "sw_id"] != hash_segment_metadata_qti["sw_id"]:
            errstr = []
            mismatches = [('sw_id', [hex(hash_segment_metadata["sw_id"])],
                           [hex(hash_segment_metadata_qti["sw_id"])])]
            create_mismatch_table(mismatches,
                                  errstr,
                                  operation="signing",
                                  data_type_to_compare="Attribute",
                                  image_region="Metadata",
                                  image_region2="Metadata QTI")
            if errstr:
                raise RuntimeError(
                    'Following validations failed for the image:\n       ' +
                    '\n       '.join([(str(authority + 1) + '. ' + e)
                                      for authority, e in enumerate(errstr)]))
Example #5
0
    def validate_header(self, hdr):
        possible_image_sizes = self._compute_possible_image_sizes(hdr)
        try:
            extracted_max_num_root_certs = possible_image_sizes[hdr.image_size]
            if (self.config_max_num_root_certs and extracted_max_num_root_certs is not None and
                    extracted_max_num_root_certs != self.config_max_num_root_certs):
                error_str = []
                create_mismatch_table(
                    [("max_num_root_certs",
                      extracted_max_num_root_certs, self.config_max_num_root_certs)],
                    error_str, operation="signing", image_region="Hash Segment")
                raise RuntimeError("\n".join(error_str))
        except KeyError:
            # Check for QTI sign asset related errors
            qti_segment, qti_err_string = '', ''
            if hdr.supports_qti_signing():
                qti_segment = ('    ' + 'QTI Signature Size:       ' + hex_addr(hdr.sig_size_qti) + '\n'
                               '    ' + 'QTI Cert Chain Size:      ' + hex_addr(
                    hdr.cert_chain_size_qti) + '\n')

                # Handles case where incoming data header contains residual data in QTI sign/cc fields
                if (hdr.image_size + hdr.sig_size_qti + hdr.cert_chain_size_qti in possible_image_sizes or
                        hdr.cert_chain_size_qti == MBN_PTR_MAX):
                    qti_err_string = ('Unsigned hash table header must not contain junk data in '
                                      'QTI attribute fields when double-signing.' + '\n\n')
            raise RuntimeError("""MBN header verification failed. Image size does not match the sum of its segments:

    Code Size:                {header_code_size}
{qti_segment}
    Signature Size:           {signature_size}
    Cert Chain Size:          {cert_chain_size}
    Image Size (expected):   *{expected_image_size}
    Image Size (from file):  *{image_size}
    {qti_err_string}
Header:
{header}
    """.format(header_code_size=hex_addr(hdr.code_size), qti_segment=qti_segment,
               signature_size=hex_addr(hdr.sig_size),
               cert_chain_size=hex_addr(hdr.cert_chain_size),
               expected_image_size=(str([hex_addr(s) for s in possible_image_sizes]) +
                                    ' (Code + Signature + Cert Chain)'),
               image_size=hex_addr(hdr.image_size),
               qti_err_string=qti_err_string, header=repr(hdr)))
Example #6
0
        def _decode_binary_blob(self, binary_blob, validating):
            if len(binary_blob) != EncryptionParamsSectionBody.L2AssociatedData.SPEC_SIZE_BYTES:
                raise RuntimeError("L2 Associated Data blob is of the wrong size")

            string_offset = 0
            string_end = EncryptionParamsSectionBody.L2AssociatedData.L2_ASSOCIATED_DATA_SIZE_FLD_LEN_BYTES
            self.l2_associated_data_size, = struct.unpack(">H", binary_blob[string_offset:string_end])

            string_offset = string_end + EncryptionParamsSectionBody.RSVD_BYTE_LEN_BYTES * 2
            string_end = string_offset + EncryptionParamsSectionBody.L2AssociatedData.MAJOR_VERSION_FLD_LEN_BYTES + \
                         EncryptionParamsSectionBody.L2AssociatedData.MINOR_VERSION_FLD_LEN_BYTES + \
                         EncryptionParamsSectionBody.L2AssociatedData.KEY_LADDER_LEN_FLD_LEN_BYTES + \
                         EncryptionParamsSectionBody.RSVD_BYTE_LEN_BYTES

            major_version, minor_version, self.key_ladder_length, tmp = struct.unpack("=BBBB", binary_blob[string_offset:string_end])
            string_offset = string_end

            if (major_version, minor_version) != (self.major_version, self.minor_version):
                raise RuntimeError(("Encryption Parameters L2 Associated Data version \"{0}.{1}\" does not match expected version \"{2}.{3}\""
                                    "\n       Ensure that the correct encryptor value is set.").format(major_version, minor_version, self.major_version, self.minor_version))

            if (major_version, minor_version) == (EncryptionParamsSectionBody.L2AssociatedData.MAJOR_VERSION_FLD_VAL_1, EncryptionParamsSectionBody.L2AssociatedData.MINOR_VERSION_FLD_VAL_0):
                string_end = string_offset + EncryptionParamsSectionBody.L2AssociatedData.IMAGE_ID_BITMAP_FLD_VERSION_1_0_LEN_BYTES
                image_id_bitmap, = struct.unpack("=I", binary_blob[string_offset:string_end])
            elif (major_version, minor_version) == (EncryptionParamsSectionBody.L2AssociatedData.MAJOR_VERSION_FLD_VAL_1, EncryptionParamsSectionBody.L2AssociatedData.MINOR_VERSION_FLD_VAL_1):
                string_end = string_offset + EncryptionParamsSectionBody.L2AssociatedData.IMAGE_ID_BITMAP_FLD_VERSION_1_1_LEN_BYTES
                image_id_bitmap_upper, image_id_bitmap_lower = struct.unpack("=QQ", binary_blob[string_offset:string_end])
                image_id_bitmap = image_id_bitmap_lower * (2 ** 64) + image_id_bitmap_upper
            else:
                raise RuntimeError("Configured Encryption Parameters L2 Associated Data version \"{0}.{1}\" is invalid.".format(self.major_version, self.minor_version))

            image_id = int(math.log(image_id_bitmap, 2))
            if image_id != self.image_id:
                if validating:
                    errstr = list()
                    mismatches = list()
                    mismatches.append((EncryptionParamsSectionBody.L2AssociatedData.IMAGE_ID, "0x%X" % image_id, "0x%X" % self.image_id))
                    create_mismatch_table(mismatches, errstr, operation="encryption", data_type_to_compare="Attribute", image_region="Encryption Parameters")
                    logger.error('Following validations failed for the image:\n       ' +
                                 '\n       '.join([(str(i + 1) + '. ' + e) for i, e in enumerate(errstr)]))
                else:
                    logger.warning(("Extracted Encryption Parameters " + EncryptionParamsSectionBody.L2AssociatedData.IMAGE_ID + " value \"{0}\" does not match config value \"{1}\""
                                   "\n\t Encryption Parameters " + EncryptionParamsSectionBody.L2AssociatedData.IMAGE_ID + " value will be updated with value \"{1}\"").format(hex(image_id), hex(self.image_id)))
Example #7
0
    def _unpack(self, data, checking_if_licmngr_seg):
        # Validate size of segment matches expected size
        if len(data) != self.get_size():
            raise RuntimeError(
                "License Manager segment is of invalid size {0} bytes."
                "\n       Allowed size is {1} bytes.".format(
                    len(data), self.get_size()))

        # Extract segment values
        (
            namesz,
            descsz,
            type,
            name,
            version,
            client_id,
            lib_id,
            is_cass_signed,
        ) = struct.unpack(self._get_format(), data)

        # Validate extracted values
        error = list()
        if namesz != self.namesz:
            error += [
                "License Manager segment contains invalid namesz value {0}.".
                format(namesz), "namesz must be {0}.".format(self.namesz)
            ]
        if descsz != self.descsz:
            error += [
                "License Manager segment contains invalid descsz value {0}.".
                format(descsz), "descsz must be {0}.".format(self.descsz)
            ]
        if type != self.type:
            error += [
                "License Manager segment contains invalid type value {0}.".
                format(type), "type must be {0}.".format(self.type)
            ]
        if name != self.name:
            error += [
                "License Manager segment contains invalid name value {0}.".
                format(name), "name must be {0}.".format(self.name)
            ]
        if error:
            raise RuntimeError("\n       ".join(error))

        if not checking_if_licmngr_seg:
            # Update existing segment
            if not self.validating:
                if version != self.version:
                    logger.warning(
                        "License Manager segment contains unknown version value {0}.\n         "
                        "Updating version value to {1}".format(
                            version, self.version))
                if client_id != self.client_id:
                    logger.warning(
                        "License Manager segment's client_id value {0} does not match configured value {1}.\n         "
                        "Updating client_id value to {1}".format(
                            hex(client_id), hex(self.client_id)))
                if lib_id != self.lib_id:
                    logger.warning(
                        "License Manager segment's lib_id value {0} does not match configured value {1}.\n         "
                        "Updating lib_id value to {1}".format(
                            hex(lib_id), hex(self.lib_id)))
                if is_cass_signed != self.is_cass_signed:
                    logger.warning(
                        "License Manager segment's is_cass_signed value {0} does not match configured value {1}.\n         "
                        "Updating is_cass_signed value to {1}".format(
                            is_cass_signed, self.is_cass_signed))
            # Validate segment against config
            else:
                errstr = list()
                mismatches = list()
                if client_id != self.client_id:
                    mismatches.append(
                        ("client_id", hex(client_id), hex(self.client_id)))
                if lib_id != self.lib_id:
                    mismatches.append(
                        ("lib_id", hex(lib_id), hex(self.lib_id)))
                create_mismatch_table(mismatches,
                                      errstr,
                                      operation="license management",
                                      data_type_to_compare="Attribute",
                                      image_region="License Manager Segment")
                if errstr:
                    raise RuntimeError(
                        'Following validations failed for the image:\n       '
                        + '\n       '.join([(str(i + 1) + '. ' + e)
                                            for i, e in enumerate(errstr)]))
                self.version = version
                self.client_id = client_id
                self.lib_id = lib_id
                self.is_cass_signed = is_cass_signed
Example #8
0
    def validate(self, image, root_cert_hash=None, imageinfo=None):
        if image.is_signed():
            # Create error string
            errstr = []

            # Extracted hash segment metadata for all authorities
            metadata = {AUTHORITY_QTI: None, AUTHORITY_OEM: None}

            for signed_authority, data_to_sign, data_signature, cert_chain, hash_segment_metadata in image.get_signing_assets():
                # Save extracted hash segment metadata for signing attribute validation
                metadata[signed_authority] = hash_segment_metadata

                # Check if empty
                if not data_signature and not cert_chain:
                    if signed_authority != image.authority:
                        logger.warning(signed_authority + ' signature is not present')
                    else:
                        raise RuntimeError(signed_authority + ' signature is not present')
                    continue

                # Extract the cert chain list
                cert_chain_der = crypto.cert.split_cert_chain_bin(cert_chain)

                # Extract signing attributes from image
                extracted_image_attributes = AttributeExtractor(cert_data=cert_chain_der[0], hash_segment_metadata=hash_segment_metadata).attributes

                # Signature verification
                if not self.validate_sig(data_to_sign, data_signature, cert_chain_der, signed_authority=signed_authority, extracted_image_attributes=extracted_image_attributes):
                    errstr.append(signed_authority + ' signature is invalid')

                # OID Validation
                if len(cert_chain_der) == 3:
                    if not self.validate_oid_from_certs(cert_chain_der[1], cert_chain_der[0]):
                        errstr.append('OID values in the certificate are invalid')

            # Extract the cert chain list
            cert_chain_blob = image.cert_chain
            cert_chain_der = crypto.cert.split_cert_chain_bin(cert_chain_blob)

            # Extract signing attributes from image
            attribute_extractor = AttributeExtractor(cert_data=cert_chain_der[0], hash_segment_metadata=metadata[image.authority])
            extracted_image_attributes = attribute_extractor.attributes

            # Root cert hash validation
            if root_cert_hash:
                if not cert_chain_der:
                    errstr.append('Root certificate for ' + image.authority + ' is not present in image for root cert hash verification')
                elif not self.validate_root_cert_hash(cert_chain_der, root_cert_hash, extracted_image_attributes):
                    errstr.append('Root certificate from image does not match the given root cert hash value')

            # Signing attributes validation
            if imageinfo is not None:
                if not cert_chain_der:
                    errstr.append('Certificate chain for ' + image.authority + ' is not present in image signing attributes verification')
                else:
                    mismatches = self.validate_signing_attributes(cert_chain_der, imageinfo, extracted_image_attributes)
                    create_mismatch_table(mismatches, errstr, operation="signing", data_type_to_compare="Attribute", image_region=attribute_extractor.image_region)
            if errstr:
                raise RuntimeError('Following validations failed for the image:\n       ' +
                                   '\n       '.join([(str(signed_authority + 1) + '. ' + e) for signed_authority, e in enumerate(errstr)]))
            return True
        else:
            raise RuntimeError("Image supplied is not signed.")