def store_debug_data(self, file_name, data, prefix=None, suffix=None): if prefix is None: prefix = self.debug_prefix if suffix is None: suffix = self.debug_suffix if prefix is not None and suffix is not None: store_debug_data_to_file(prefix + '_' + file_name + suffix, data, self.debug_dir)
def store_debug_data(self, file_name, data, prefix=None, suffix=None): if prefix is None: prefix = self.debug_prefix if suffix is None: suffix = self.debug_suffix if prefix is not None and suffix is not None: store_debug_data_to_file(prefix + '_' + file_name + suffix, data, self.debug_dir)
def store_debug_data(self, file_name, data, prefix=None, suffix=None): if prefix is None: prefix = self.debug_prefix if suffix is None: suffix = self.debug_suffix if prefix is not None and suffix is not None: store_debug_data_to_file(str(prefix) + '_' + str(file_name) + str(suffix), data, self.debug_dir)
def store_debug_data(self, file_name, data, debug_dir=None, prefix=None, suffix=None): if prefix is None: prefix = getattr(self, "debug_prefix", None) if suffix is None: suffix = getattr(self, "debug_suffix", None) if debug_dir is None: debug_dir = getattr(self, "debug_dir", None) if prefix is not None and suffix is not None: store_debug_data_to_file(prefix + '_' + file_name + suffix, data, debug_dir)
def _unpack(self, data): # Validate size of segment is not smaller than allowed minimum min_size_of_hash_entry = min(HASH_ALGO_TO_SIZE_MAP.values()) min_size = self._get_fixed_size() + self._get_id_size() + min_size_of_hash_entry if len(data) < min_size: raise RuntimeError(multi_image_string() + " segment is of invalid size {0} bytes." "\nMinimum allowed size is {1} bytes.".format(len(data), min_size)) # Extract segment header offset = 0 end = self._get_fixed_size() (self.magic_number, self.version, self.res0, self.res1, self.res2, self.res3, self.res4, self.res5, self.res6, self.res7, self.res8, self.res9, self.res10, self.res11, self.res12, self.res13, self.res14, self.res15, self.res16, self.res17, self.res18, self.res19, self.res20, self.res21, self.res22, self.res23, self.res24, self.res25, self.res26, self.res27, self.res28, self.res29, self.res30, self.res31, num_images, hash_algorithm,) = struct.unpack(self._get_fixed_format(), data[offset:end]) # Validate extracted values if self.magic_number != MAGIC_NUM: raise RuntimeError(multi_image_string() + " segment contains invalid magic number {0}." "\nMagic number must be {1}.".format(self.magic_number, MAGIC_NUM)) if self.version != MULT_IMAGE_VERSION_0: raise RuntimeError(multi_image_string() + " segment contains invalid version number {0}." "\nSupported version are: {1}.".format(self.version, SUPPORTED_VERSIONS)) if num_images > MAX_NUM_IMAGES: raise RuntimeError(multi_image_string() + " segment contains {0} image entries." "\nMaximum allowed number of images entries is {1}.".format(num_images, MAX_NUM_IMAGES)) if hash_algorithm not in DECODE_HASH_ALGO: raise RuntimeError(multi_image_string() + " segment contains invalid hash algorithm value {0}." "\nAllowed hash algorithm values are {1}.".format(hash_algorithm, DECODE_HASH_ALGO.keys())) elif DECODE_HASH_ALGO[hash_algorithm] != self.hash_algorithm: raise RuntimeError(multi_image_string() + " segment was created using {0} but segment_hash_algorithm is configured to {1}." "\nChange configured segment_hash_algorithm value to {0}.".format(DECODE_HASH_ALGO[hash_algorithm], self.hash_algorithm)) # Validate segment size expected_size = self._get_fixed_size() + (self._get_id_size() + HASH_ALGO_TO_SIZE_MAP[self.hash_algorithm]) * num_images if expected_size < len(data): raise RuntimeError(multi_image_string() + " segment is of invalid size {0} bytes." "\nSegment containing {1} {2} image entries should be {} bytes.".format(len(data), num_images, self.hash_algorithm, expected_size)) # Extract sw_id/app_id and hash values for i in range(num_images): offset = end end += self._get_id_size() (sw_id, app_id,) = struct.unpack(self._get_id_format(), data[offset:end]) hash_size = HASH_ALGO_TO_SIZE_MAP[self.hash_algorithm] offset = end end += hash_size image_hash = data[offset:end] self.image_hash_dict[(sw_id, app_id)] = image_hash store_debug_data_to_file(FILE_EXTRACTED, data[0:end], self.debug_dir) store_debug_data_to_file(FILE_EXTRACTED_READABLE, str(self), self.debug_dir)
def __init__(self, encryption_params_blob=None, private_key=None, config=None, debug_dir=None, l3_key_blob=None, validating=False, encrypted_segments_indices=None): self.image_id = int( config.signing_attributes.sw_id[EncryptionParameters. SOFTWARE_TYPE_FLD_OFFSET:], 16) if encryption_params_blob is None and private_key is None and l3_key_blob is None: self.key_service = key_service_module.KeyService(config) encryption_params_blob, private_key = self._generate_new_blob( config, debug_dir, encrypted_segments_indices=encrypted_segments_indices) # Set the base params BaseEncryptionParameters.__init__( self, encryption_params_blob=encryption_params_blob, key=private_key, debug_dir=debug_dir, validating=validating) elif encryption_params_blob is not None and l3_key_blob is not None: self._set_l3_and_iv(encryption_params_blob, l3_key_blob) # Set the base params BaseEncryptionParameters.__init__( self, encryption_params_blob=encryption_params_blob, key=None, debug_dir=debug_dir, validating=validating) elif encryption_params_blob is not None and private_key is not None: # Set the base params BaseEncryptionParameters.__init__( self, encryption_params_blob=encryption_params_blob, key=private_key, debug_dir=debug_dir, validating=validating) # Get the image encryption key & iv self._decode_blob(encryption_params_blob, private_key, debug_dir) else: raise RuntimeError( "ERROR: Invalid configuration of params used to create encryption params." ) store_debug_data_to_file(defines.DEST_DEBUG_FILE_ENCRYPTION_PARAMETERS, hexdump(self.encryption_params_blob), debug_dir)
def process_signature_response(self): self.signature_package = SignaturePackage( self.connector_response, self.signing_package.get_digest().lower(), self.signature_result_file_name) [signature, cert_chain_list ] = signerutils.readSigFromZip(self.signature_result_file_name) if not self.validate_sig_using_hash(self.hash_to_sign, signature, cert_chain_list): raise ExternalSignerError( self.MESG_INVALID_SIG.format(self.signature_result_file_name)) # Validate padding cert_text = crypto.cert.get_text(cert_chain_list[0]) use_pss = crypto.cert.get_sign_algo( cert_text) == crypto.cert.SIGN_ALGO_RSA_PSS cass_padding = self.PAD_PSS if use_pss else self.PAD_PKCS if cass_padding != self.padding: raise ExternalSignerError( self.MESG_INVALID_PADDING.format(cass_padding.upper(), self.padding.upper())) # Clean up/save signing package and signature response if self.debug_dir is None: c_path.clean_file(self.signing_package_file_name) c_path.clean_file(self.signature_result_file_name) c_misc.store_debug_data_to_file(self.SIGNATURE_PACKAGE_FILENAME, self.connector_response, self.debug_dir) # Extract certificates to create signer output out_root_cert = None out_attest_ca_cert = None out_attest_cert = cert_chain_list[0] if len(cert_chain_list) == 3: out_attest_ca_cert = cert_chain_list[1] out_root_cert = cert_chain_list[2] elif len(cert_chain_list) == 2: out_root_cert = cert_chain_list[1] signer_output = SignerOutput() signer_output.root_cert = out_root_cert signer_output.attestation_ca_cert = out_attest_ca_cert signer_output.attestation_cert = out_attest_cert signer_output.signature = signature return signer_output
def sign(self, hash_to_sign, imageinfo, binary_to_sign=None, debug_dir=None): cass_signer_attributes = self.config.signing.signer_attributes.cass_signer_attributes self._validate_config(cass_signer_attributes) if debug_dir is not None: cass_output_dir = debug_dir else: cass_output_dir = imageinfo.dest_image.image_dir signingpackage_fname = os.path.join(cass_output_dir, self.SIGNINGPACKAGE_FILENAME) signature_result_fname = os.path.join(cass_output_dir, self.SIGNATURE_RESULT_FILENAME) signing_package = self._generate_signing_package( hash_to_sign, imageinfo.signing_attributes, cass_signer_attributes, imageinfo.dest_image.image_path, signingpackage_fname, binary_to_sign) connector = CassConnector(cass_signer_attributes) signature_package_blob = connector.sign(signingpackage_fname, imageinfo.dest_image.image_dir) self._process_signature_package(signature_package_blob, signing_package, signature_result_fname) [signature, cert_chain_list] = signerutils.\ readSigFromZip(signature_result_fname) if self.validate_sig(binary_to_sign, signature, cert_chain_list) is False: raise ExternalSignerError( self.MESG_INVALID_SIG.format(signature_result_fname)) signer_output = self._get_signer_output(signature, cert_chain_list) #Clean up/save signing package and signature response if debug_dir is None: c_path.clean_file(signingpackage_fname) c_path.clean_file(signature_result_fname) c_misc.store_debug_data_to_file(self.SIGNATUREPACKAGE_FILENAME, signature_package_blob, debug_dir) return signer_output
def sign(self, hash_to_sign, imageinfo, binary_to_sign = None, debug_dir=None): cass_signer_attributes = self.config.signing.signer_attributes.cass_signer_attributes self._validate_config(cass_signer_attributes) if debug_dir is not None: cass_output_dir = debug_dir else: cass_output_dir = imageinfo.dest_image.image_dir signingpackage_fname = os.path.join(cass_output_dir, self.SIGNINGPACKAGE_FILENAME) signature_result_fname = os.path.join(cass_output_dir, self.SIGNATURE_RESULT_FILENAME) signing_package = self._generate_signing_package(hash_to_sign, imageinfo.signing_attributes, cass_signer_attributes, imageinfo.dest_image.image_path, signingpackage_fname, binary_to_sign ) connector = CassConnector(cass_signer_attributes) signature_package_blob = connector.sign(signingpackage_fname, imageinfo.dest_image.image_dir) self._process_signature_package(signature_package_blob, signing_package, signature_result_fname) [signature, cert_chain_list] = signerutils.\ readSigFromZip(signature_result_fname) if self.validate_sig(binary_to_sign, signature, cert_chain_list) is False: raise ExternalSignerError( self.MESG_INVALID_SIG.format(signature_result_fname)) signer_output = self._get_signer_output(signature, cert_chain_list) #Clean up/save signing package and signature response if debug_dir is None: c_path.clean_file(signingpackage_fname) c_path.clean_file(signature_result_fname) c_misc.store_debug_data_to_file(self.SIGNATUREPACKAGE_FILENAME, signature_package_blob, debug_dir) return signer_output
def pack(self): # Pack segment header data = struct.pack(self._get_fixed_format(), ensure_binary(self.magic_number), self.version, self.res0, self.res1, self.res2, self.res3, self.res4, self.res5, self.res6, self.res7, self.res8, self.res9, self.res10, self.res11, self.res12, self.res13, self.res14, self.res15, self.res16, self.res17, self.res18, self.res19, self.res20, self.res21, self.res22, self.res23, self.res24, self.res25, self.res26, self.res27, self.res28, self.res29, self.res30, self.res31, len(self.image_hash_dict), ENCODE_HASH_ALGO[self.hash_algorithm]) # Pack sw_id/app_id and hash values for (sw_id, app_id), image_hash in self.image_hash_dict.items(): data += struct.pack(self._get_id_format(), sw_id, app_id) data += image_hash store_debug_data_to_file(FILE_GENERATED, data, self.debug_dir) store_debug_data_to_file(FILE_GENERATED_READABLE, str(self), self.debug_dir) return data
def process_signature_response(self): self.signature_package = SignaturePackage( self.connector_response, self.signing_package.get_digest().lower(), self.signature_result_file_name) [signature, cert_chain_list ] = signerutils.readSigFromZip(self.signature_result_file_name) if self.validate_sig_using_hash(self.hash_to_sign, signature, cert_chain_list) is False: raise ExternalSignerError( self.MESG_INVALID_SIG.format(self.signature_result_file_name)) # Clean up/save signing package and signature response if self.debug_dir is None: c_path.clean_file(self.signing_package_file_name) c_path.clean_file(self.signature_result_file_name) c_misc.store_debug_data_to_file(self.SIGNATURE_PACKAGE_FILENAME, self.connector_response, self.debug_dir) # Extract certificates to create signer output out_root_cert = None out_attest_ca_cert = None out_attest_cert = cert_chain_list[0] if len(cert_chain_list) == 3: out_attest_ca_cert = cert_chain_list[1] out_root_cert = cert_chain_list[2] elif len(cert_chain_list) == 2: out_root_cert = cert_chain_list[1] signer_output = SignerOutput() signer_output.root_cert = out_root_cert signer_output.attestation_ca_cert = out_attest_ca_cert signer_output.attestation_cert = out_attest_cert signer_output.signature = signature return signer_output
def _decode_binary_blob(self, binary_blob, validating, l1_key, debug_dir): string_offset = 0 string_end = EncryptionParamsSectionBody.B0block.get_spec_size() self.L2B0block = EncryptionParamsSectionBody.B0block(binary_blob[string_offset:string_end]) self.L2_IV = self.L2B0block.nonce_fld logger.debug("L2 IV: \n" + hexdump(self.L2_IV)) string_offset = string_end string_end += EncryptionParamsSectionBody.L2AssociatedData.get_spec_size() self.L2_associated_data = binary_blob[string_offset:string_end] EncryptionParamsSectionBody.L2AssociatedData(self.L2_associated_data_major_version, self.L2_associated_data_minor_version, self.image_id, binary_blob=self.L2_associated_data, validating=validating) string_offset = string_end string_end += EncryptionParamsSectionBody.ENCRYPTED_KEY_PAYLOAD_LEN_BYTES self.L1_key_payload = binary_blob[string_offset:string_end] string_offset = string_end string_end += EncryptionParamsSectionBody.MAC_LEN_BYTES self.L2_MAC = binary_blob[string_offset:string_end] store_debug_data_to_file(defines.DEST_DEBUG_FILE_ENCRYPTED_L2_KEY, self.L1_key_payload + self.L2_MAC, debug_dir) store_debug_data_to_file(defines.DEST_DEBUG_FILE_L2_IMAGE_IV, self.L2_IV, debug_dir) store_debug_data_to_file(defines.DEST_DEBUG_FILE_L2_ADD, self.L2_associated_data, debug_dir) try: self.l2_key = crypto.aes_ccm.decrypt(self.L1_key_payload + self.L2_MAC, binascii.hexlify(l1_key), binascii.hexlify(self.L2_IV), binascii.hexlify(self.L2_associated_data)) logger.debug("L2 Key extracted from image: \n" + hexdump(self.l2_key)) logger.debug("Any previously generated L2 keys will be ignored.") except subprocess.CalledProcessError: raise RuntimeError("Extraction of L2 key from image failed. This can be caused by the use of an invalid L1 key.") string_offset = string_end string_end += EncryptionParamsSectionBody.B0block.get_spec_size() self.L3B0block = EncryptionParamsSectionBody.B0block(binary_blob[string_offset:string_end]) self.L3_IV = self.L3B0block.nonce_fld logger.debug("L3 IV: \n" + hexdump(self.L3_IV)) string_offset = string_end string_end += EncryptionParamsSectionBody.L3AssociatedData.get_spec_size() self.L3_associated_data = binary_blob[string_offset:string_end] string_offset = string_end string_end += EncryptionParamsSectionBody.ENCRYPTED_KEY_PAYLOAD_LEN_BYTES self.L2_key_payload = binary_blob[string_offset:string_end] string_offset = string_end string_end += EncryptionParamsSectionBody.MAC_LEN_BYTES self.L3_MAC = binary_blob[string_offset:string_end] store_debug_data_to_file(defines.DEST_DEBUG_FILE_ENCRYPTED_L3_KEY, self.L2_key_payload + self.L3_MAC, debug_dir) store_debug_data_to_file(defines.DEST_DEBUG_FILE_L3_IMAGE_IV, self.L3_IV, debug_dir) store_debug_data_to_file(defines.DEST_DEBUG_FILE_L3_ADD, self.L3_associated_data, debug_dir) try: self.l3_key = crypto.aes_ccm.decrypt(self.L2_key_payload + self.L3_MAC, binascii.hexlify(self.l2_key), binascii.hexlify(self.L3_IV), binascii.hexlify(self.L3_associated_data)) logger.debug("L3 Key extracted from image: \n" + hexdump(self.l3_key)) logger.debug("Any previously generated L3 keys will be ignored.") except subprocess.CalledProcessError: raise RuntimeError("Extraction of L3 key from image failed. This can be caused by the use of an invalid L1 or L2 key.") string_offset = string_end string_end += EncryptionParamsSectionBody.BASE_IV_LEN_BYTES self.base_iv = binary_blob[string_offset:string_end]