/ util / amdfwtool / signed_psp.c
signed_psp.c
  1  /* SPDX-License-Identifier: GPL-2.0-only */
  2  
  3  #include <assert.h>
  4  #include <fcntl.h>
  5  #include <errno.h>
  6  #include <limits.h>
  7  #include <openssl/sha.h>
  8  #include <stdio.h>
  9  #include <sys/stat.h>
 10  #include <unistd.h>
 11  #include <string.h>
 12  #include <stdlib.h>
 13  
 14  #include "amdfwtool.h"
 15  
 16  /* Defines related to hashing signed binaries */
 17  enum hash_header_ver {
 18  	HASH_HDR_V1 = 1,
 19  	HASH_HDR_V2,
 20  };
 21  /* Signature ID enums are defined by PSP based on the algorithm used. */
 22  enum signature_id {
 23  	SIG_ID_RSA2048,
 24  	SIG_ID_RSA4096 = 2,
 25  };
 26  
 27  #define HASH_FILE_SUFFIX ".hash"
 28  struct psp_fw_hash_file_info {
 29  	int fd;
 30  	bool present;
 31  	struct psp_fw_hash_table hash_header;
 32  };
 33  static struct psp_fw_hash_file_info hash_files[MAX_NUM_HASH_TABLES];
 34  
 35  #define UUID_MAGIC "gpd.ta.appID"
 36  
 37  static uint16_t get_psp_fw_type(enum platform soc_id, struct amd_fw_header *header)
 38  {
 39  	switch (soc_id) {
 40  	case PLATFORM_MENDOCINO:
 41  	case PLATFORM_PHOENIX:
 42  	case PLATFORM_GLINDA:
 43  		/* Fallback to fw_type if fw_id is not populated, which serves the same
 44  		   purpose on older SoCs. */
 45  		return header->fw_id ? header->fw_id : header->fw_type;
 46  	default:
 47  		return header->fw_type;
 48  	}
 49  }
 50  
 51  static void get_psp_fw_uuid(void *buf, size_t buf_len, uint8_t *uuid)
 52  {
 53  	void *ptr = memmem(buf, buf_len, UUID_MAGIC, strlen(UUID_MAGIC));
 54  
 55  	assert(ptr != NULL);
 56  
 57  	memcpy(uuid, ptr + strlen(UUID_MAGIC), UUID_LEN_BYTES);
 58  }
 59  
 60  static int add_single_sha(amd_fw_entry_hash *entry, void *buf, enum platform soc_id,
 61  								fwid_type_t fwid_type)
 62  {
 63  	uint8_t hash[SHA384_DIGEST_LENGTH];
 64  	struct amd_fw_header *header = (struct amd_fw_header *)buf;
 65  	/* Include only signed part for hash calculation. */
 66  	size_t len = header->fw_size_signed + sizeof(struct amd_fw_header);
 67  	uint8_t *body = (uint8_t *)buf;
 68  
 69  	if (len > header->size_total)
 70  		return -1;
 71  
 72  	if (header->sig_id == SIG_ID_RSA4096) {
 73  		SHA384(body, len, hash);
 74  		entry->sha_len = SHA384_DIGEST_LENGTH;
 75  	} else if (header->sig_id == SIG_ID_RSA2048) {
 76  		SHA256(body, len, hash);
 77  		entry->sha_len = SHA256_DIGEST_LENGTH;
 78  	} else {
 79  		fprintf(stderr, "%s: Unknown signature id: 0x%08x\n",
 80  						__func__, header->sig_id);
 81  		return -1;
 82  	}
 83  
 84  	memcpy(entry->sha, hash, entry->sha_len);
 85  	entry->fwid_type = fwid_type;
 86  	if (fwid_type == FWID_TYPE_UUID)
 87  		get_psp_fw_uuid(buf, header->size_total, entry->uuid);
 88  	else
 89  		entry->fw_id = get_psp_fw_type(soc_id, header);
 90  	entry->subtype = header->fw_subtype;
 91  
 92  	return 0;
 93  }
 94  
 95  static int get_num_binaries(void *buf, size_t buf_size)
 96  {
 97  	struct amd_fw_header *header = (struct amd_fw_header *)buf;
 98  	size_t total_len = 0;
 99  	int num_binaries = 0;
100  
101  	while (total_len < buf_size) {
102  		num_binaries++;
103  		total_len += header->size_total;
104  		header = (struct amd_fw_header *)(buf + total_len);
105  	}
106  
107  	if (total_len != buf_size) {
108  		fprintf(stderr, "Malformed binary\n");
109  		return -1;
110  	}
111  	return num_binaries;
112  }
113  
114  static int add_sha(amd_fw_entry *entry, void *buf, size_t buf_size, enum platform soc_id)
115  {
116  	struct amd_fw_header *header = (struct amd_fw_header *)buf;
117  	/* Include only signed part for hash calculation. */
118  	size_t total_len = 0;
119  	int num_binaries = get_num_binaries(buf, buf_size);
120  
121  	if (num_binaries <= 0)
122  		return num_binaries;
123  
124  	entry->hash_entries = calloc(num_binaries, sizeof(amd_fw_entry_hash));
125  	if (!entry->hash_entries) {
126  		fprintf(stderr, "Error allocating memory to add FW hash\n");
127  		return -1;
128  	}
129  	entry->num_hash_entries = num_binaries;
130  
131  	/* Iterate through each binary */
132  	for (int i = 0; i < num_binaries; i++) {
133  		if (add_single_sha(&entry->hash_entries[i], buf + total_len, soc_id,
134  								entry->fwid_type)) {
135  			free(entry->hash_entries);
136  			return -1;
137  		}
138  		total_len += header->size_total;
139  		header = (struct amd_fw_header *)(buf + total_len);
140  	}
141  
142  	return 0;
143  }
144  
145  static void write_one_psp_firmware_hash_entry(int fd, amd_fw_entry_hash *entry,
146  								uint8_t hash_tbl_id)
147  {
148  	uint16_t subtype = entry->subtype;
149  
150  	if (hash_files[hash_tbl_id].hash_header.version == HASH_HDR_V2) {
151  		write_or_fail(fd, entry->uuid, UUID_LEN_BYTES);
152  	} else {
153  		write_or_fail(fd, &entry->fw_id, sizeof(entry->fw_id));
154  		write_or_fail(fd, &subtype, sizeof(subtype));
155  	}
156  	write_or_fail(fd, entry->sha, entry->sha_len);
157  }
158  
159  static void open_psp_fw_hash_files(const char *file_prefix)
160  {
161  	size_t hash_file_strlen;
162  	char *hash_file_name;
163  
164  	/* Hash Table ID is part of the file name. For now only single digit ID is
165  	   supported and is sufficient. Hence assert MAX_NUM_HASH_TABLES < 10 before
166  	   constructing file name. Revisit later when > 10 hash tables are required. */
167  	assert(MAX_NUM_HASH_TABLES < 10);
168  	/* file_prefix + ".[1-9]" + ".hash" + '\0' */
169  	hash_file_strlen = strlen(file_prefix) + 2 + strlen(HASH_FILE_SUFFIX) + 1;
170  	hash_file_name = malloc(hash_file_strlen);
171  	if (!hash_file_name)  {
172  		fprintf(stderr, "malloc(%lu) failed\n", hash_file_strlen);
173  		exit(-1);
174  	}
175  
176  	for (unsigned int i = 0; i < MAX_NUM_HASH_TABLES; i++) {
177  		/* Hash table IDs are expected to be contiguous and hence holes are not
178  		   expected. */
179  		if (!hash_files[i].present)
180  			break;
181  
182  		if (i)
183  			snprintf(hash_file_name, hash_file_strlen, "%s.%d%s",
184  				 file_prefix, i, HASH_FILE_SUFFIX);
185  		else
186  			/* Default file name without number for backwards compatibility. */
187  			snprintf(hash_file_name, hash_file_strlen, "%s%s",
188  				 file_prefix, HASH_FILE_SUFFIX);
189  
190  		hash_files[i].fd = open(hash_file_name, O_RDWR | O_CREAT | O_TRUNC, 0666);
191  		if (hash_files[i].fd < 0) {
192  			fprintf(stderr, "Error opening file: %s: %s\n",
193  					hash_file_name, strerror(errno));
194  			free(hash_file_name);
195  			exit(-1);
196  		}
197  	}
198  	free(hash_file_name);
199  }
200  
201  static void close_psp_fw_hash_files(void)
202  {
203  	for (unsigned int i = 0; i < MAX_NUM_HASH_TABLES; i++) {
204  		if (!hash_files[i].present)
205  			break;
206  
207  		close(hash_files[i].fd);
208  	}
209  }
210  
211  static void write_psp_firmware_hash(amd_fw_entry *fw_table)
212  {
213  	uint8_t hash_tbl_id;
214  
215  	for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
216  		hash_tbl_id = fw_table[i].hash_tbl_id;
217  		assert(hash_files[hash_tbl_id].present);
218  
219  		for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) {
220  			if (fw_table[i].hash_entries[j].sha_len == SHA256_DIGEST_LENGTH) {
221  				hash_files[hash_tbl_id].hash_header.no_of_entries_256++;
222  			} else if (fw_table[i].hash_entries[j].sha_len ==
223  								SHA384_DIGEST_LENGTH) {
224  				hash_files[hash_tbl_id].hash_header.no_of_entries_384++;
225  			} else if (fw_table[i].hash_entries[j].sha_len) {
226  				fprintf(stderr, "%s: Error invalid sha_len %d\n",
227  						__func__, fw_table[i].hash_entries[j].sha_len);
228  				exit(-1);
229  			}
230  		}
231  	}
232  
233  	for (unsigned int i = 0; i < MAX_NUM_HASH_TABLES; i++) {
234  		if (!hash_files[i].present)
235  			continue;
236  		write_or_fail(hash_files[i].fd, &hash_files[i].hash_header,
237  						sizeof(hash_files[i].hash_header));
238  		/* Add a reserved field as expected by version 2 header */
239  		if (hash_files[i].hash_header.version == HASH_HDR_V2) {
240  			uint16_t reserved = 0;
241  
242  			write_or_fail(hash_files[i].fd, &reserved, sizeof(reserved));
243  		}
244  	}
245  
246  	/* Add all the SHA256 hash entries first followed by SHA384 entries. PSP verstage
247  	   processes the table in that order. Mixing and matching SHA256 and SHA384 entries
248  	   will cause the hash verification failure at run-time. */
249  	for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
250  		hash_tbl_id = fw_table[i].hash_tbl_id;
251  		for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) {
252  			if (fw_table[i].hash_entries[j].sha_len == SHA256_DIGEST_LENGTH)
253  				write_one_psp_firmware_hash_entry(hash_files[hash_tbl_id].fd,
254  						&fw_table[i].hash_entries[j], hash_tbl_id);
255  		}
256  	}
257  
258  	for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
259  		hash_tbl_id = fw_table[i].hash_tbl_id;
260  		for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) {
261  			if (fw_table[i].hash_entries[j].sha_len == SHA384_DIGEST_LENGTH)
262  				write_one_psp_firmware_hash_entry(hash_files[hash_tbl_id].fd,
263  						&fw_table[i].hash_entries[j], hash_tbl_id);
264  		}
265  	}
266  
267  	for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
268  		if (!fw_table[i].num_hash_entries || !fw_table[i].hash_entries)
269  			continue;
270  
271  		free(fw_table[i].hash_entries);
272  		fw_table[i].hash_entries = NULL;
273  		fw_table[i].num_hash_entries = 0;
274  	}
275  }
276  
277  static void update_hash_files_config(amd_fw_entry *fw_table)
278  {
279  	uint16_t version = fw_table->fwid_type == FWID_TYPE_UUID ? HASH_HDR_V2 : HASH_HDR_V1;
280  
281  	hash_files[fw_table->hash_tbl_id].present = true;
282  	if (version > hash_files[fw_table->hash_tbl_id].hash_header.version)
283  		hash_files[fw_table->hash_tbl_id].hash_header.version = version;
284  }
285  
286  /**
287   * process_signed_psp_firmwares() - Process the signed PSP binaries to keep them separate
288   * @signed_rom:	Output file path grouping all the signed PSP binaries.
289   * @fw_table:	Table of all the PSP firmware entries/binaries to be processed.
290   * @signed_start_addr:	Offset of the FMAP section, within the flash device, to hold
291   *                      the signed PSP binaries.
292   * @soc_id:	SoC ID of the PSP binaries.
293   */
294  void process_signed_psp_firmwares(const char *signed_rom,
295  		amd_fw_entry *fw_table,
296  		uint64_t signed_start_addr,
297  		enum platform soc_id)
298  {
299  	unsigned int i;
300  	int fd;
301  	int signed_rom_fd;
302  	ssize_t bytes, align_bytes;
303  	uint8_t *buf;
304  	struct amd_fw_header header;
305  	struct stat fd_stat;
306  	/* Every blob in amdfw*.rom has to start at address aligned to 0x100. Prepare an
307  	   alignment data with 0xff to pad the blobs and meet the alignment requirement. */
308  	uint8_t align_data[BLOB_ALIGNMENT - 1];
309  
310  	memset(align_data, 0xff, sizeof(align_data));
311  	signed_rom_fd = open(signed_rom, O_RDWR | O_CREAT | O_TRUNC,
312  				S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
313  	if (signed_rom_fd < 0) {
314  		fprintf(stderr, "Error opening file: %s: %s\n",
315  				signed_rom, strerror(errno));
316  		return;
317  	}
318  
319  	for (i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
320  		fw_table[i].num_hash_entries = 0;
321  		fw_table[i].hash_entries = NULL;
322  
323  		if (!(fw_table[i].filename) || fw_table[i].skip_hashing)
324  			continue;
325  
326  		memset(&header, 0, sizeof(header));
327  
328  		fd = open(fw_table[i].filename, O_RDONLY);
329  		if (fd < 0) {
330  			/* Keep the file along with set of unsigned PSP binaries & continue. */
331  			fprintf(stderr, "Error opening file: %s: %s\n",
332  					fw_table[i].filename, strerror(errno));
333  			continue;
334  		}
335  
336  		if (fstat(fd, &fd_stat)) {
337  			/* Keep the file along with set of unsigned PSP binaries & continue. */
338  			fprintf(stderr, "fstat error: %s\n", strerror(errno));
339  			close(fd);
340  			continue;
341  		}
342  
343  		bytes = read_from_file_to_buf(fd, &header, sizeof(struct amd_fw_header));
344  		if (bytes != (ssize_t)sizeof(struct amd_fw_header)) {
345  			/* Keep the file along with set of unsigned PSP binaries & continue. */
346  			fprintf(stderr, "%s: Error reading header from %s\n",
347  						__func__, fw_table[i].filename);
348  			close(fd);
349  			continue;
350  		}
351  
352  		/* If firmware header looks like invalid, assume it's not signed */
353  		if (!header.fw_type && !header.fw_id) {
354  			fprintf(stderr, "%s: Invalid FWID for %s\n",
355  					__func__, fw_table[i].filename);
356  			close(fd);
357  			continue;
358  		}
359  
360  
361  		/* PSP binary is not signed and should not be part of signed PSP binaries
362  		   set. */
363  		if (header.sig_opt != 1) {
364  			close(fd);
365  			continue;
366  		}
367  
368  		buf = malloc(fd_stat.st_size);
369  		if (!buf) {
370  			/* Keep the file along with set of unsigned PSP binaries & continue. */
371  			fprintf(stderr, "%s: failed to allocate memory with size %lld\n",
372  							__func__, (long long)fd_stat.st_size);
373  			close(fd);
374  			continue;
375  		}
376  
377  		lseek(fd, SEEK_SET, 0);
378  		bytes = read_from_file_to_buf(fd, buf, fd_stat.st_size);
379  		if (bytes != fd_stat.st_size) {
380  			/* Keep the file along with set of unsigned PSP binaries & continue. */
381  			fprintf(stderr, "%s: failed to read %s\n",
382  					__func__, fw_table[i].filename);
383  			free(buf);
384  			close(fd);
385  			continue;
386  		}
387  
388  		bytes = write_from_buf_to_file(signed_rom_fd, buf, fd_stat.st_size);
389  		if (bytes != fd_stat.st_size) {
390  			/* Keep the file along with set of unsigned PSP binaries & continue. */
391  			fprintf(stderr, "%s: failed to write %s\n",
392  					__func__, fw_table[i].filename);
393  			free(buf);
394  			close(fd);
395  			continue;
396  		}
397  
398  		/* Write Blob alignment bytes */
399  		align_bytes = 0;
400  		if (fd_stat.st_size & (BLOB_ALIGNMENT - 1)) {
401  			align_bytes = BLOB_ALIGNMENT -
402  				(fd_stat.st_size & (BLOB_ALIGNMENT - 1));
403  			bytes = write_from_buf_to_file(signed_rom_fd, align_data, align_bytes);
404  			if (bytes != align_bytes) {
405  				fprintf(stderr, "%s: failed to write alignment data for %s\n",
406  								__func__, fw_table[i].filename);
407  				lseek(signed_rom_fd, SEEK_CUR, -fd_stat.st_size);
408  				free(buf);
409  				close(fd);
410  				continue;
411  			}
412  		}
413  
414  		if (add_sha(&fw_table[i], buf, fd_stat.st_size, soc_id))
415  			exit(-1);
416  
417  		/* File is successfully processed and is part of signed PSP binaries set. */
418  		fw_table[i].addr_signed = signed_start_addr;
419  		fw_table[i].file_size = (uint32_t)fd_stat.st_size;
420  		update_hash_files_config(&fw_table[i]);
421  
422  		signed_start_addr += fd_stat.st_size + align_bytes;
423  
424  		free(buf);
425  		close(fd);
426  	}
427  
428  	close(signed_rom_fd);
429  
430  	open_psp_fw_hash_files(signed_rom);
431  	write_psp_firmware_hash(fw_table);
432  	close_psp_fw_hash_files();
433  }