Browse Source

mkfwimage: Add image type definition for WA images

This patch adds a new type of ubiquiti image, the WA image. First seen
on the NanoStation AC loco the generic name implies that we will see
this type of image on more ubiquiti devices thus it makes sense to
implement it in mkfwimage.

The main difference is that WA images are signed. The "END" header has
been replaced by a "ENDS" header followed by a 2048 bit RSA signature.
This signature is not being generated by mkfwimage and filled with 0x00.

Signed-off-by: Tobias Schramm <[email protected]>
Tobias Schramm 7 years ago
parent
commit
8f697e406a
2 changed files with 129 additions and 47 deletions
  1. 8 0
      tools/firmware-utils/src/fw.h
  2. 121 47
      tools/firmware-utils/src/mkfwimage.c

+ 8 - 0
tools/firmware-utils/src/fw.h

@@ -24,6 +24,7 @@
 #define MAGIC_HEADER	"OPEN"
 #define MAGIC_PART	"PART"
 #define MAGIC_END	"END."
+#define MAGIC_ENDS	"ENDS"
 
 #define MAGIC_LENGTH	4
 
@@ -57,6 +58,13 @@ typedef struct signature {
 	u_int32_t pad;
 } __attribute__ ((packed)) signature_t;
 
+typedef struct signature_rsa {
+	char magic[MAGIC_LENGTH];
+//	u_int32_t crc;
+	unsigned char rsa_signature[256];
+	u_int32_t pad;
+} __attribute__ ((packed)) signature_rsa_t;
+
 #define VERSION "1.2"
 
 #define INFO(...) fprintf(stdout, __VA_ARGS__)

+ 121 - 47
tools/firmware-utils/src/mkfwimage.c

@@ -29,65 +29,106 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <limits.h>
+#include <stdbool.h>
 #include "fw.h"
 
 typedef struct fw_layout_data {
-	char		name[PATH_MAX];
 	u_int32_t	kern_start;
 	u_int32_t	kern_entry;
 	u_int32_t	firmware_max_length;
 } fw_layout_t;
 
-fw_layout_t fw_layout_data[] = {
+struct fw_info {
+	char			name[PATH_MAX];
+	struct fw_layout_data	fw_layout;
+	bool			sign;
+};
+
+struct fw_info fw_info[] = {
 	{
-		.name		=	"XS2",
-		.kern_start	=	0xbfc30000,
-		.kern_entry	=	0x80041000,
-		.firmware_max_length=	0x00390000,
+		.name = "XS2",
+		.fw_layout = {
+			.kern_start	=	0xbfc30000,
+			.kern_entry	=	0x80041000,
+			.firmware_max_length=	0x00390000,
+		},
+		.sign = false,
 	},
 	{
-		.name		=	"XS5",
-		.kern_start	=	0xbe030000,
-		.kern_entry	=	0x80041000,
-		.firmware_max_length=	0x00390000,
+		.name = "XS5",
+		.fw_layout = {
+			.kern_start	=	0xbe030000,
+			.kern_entry	=	0x80041000,
+			.firmware_max_length=	0x00390000,
+		},
+		.sign = false,
 	},
 	{
-		.name		=	"RS",
-		.kern_start	=	0xbf030000,
-		.kern_entry	=	0x80060000,
-		.firmware_max_length=	0x00B00000,
+		.name = "RS",
+		.fw_layout = {
+			.kern_start	=	0xbf030000,
+			.kern_entry	=	0x80060000,
+			.firmware_max_length=	0x00B00000,
+		},
+		.sign = false,
 	},
 	{
-		.name		=	"RSPRO",
-		.kern_start	=	0xbf030000,
-		.kern_entry	=	0x80060000,
-		.firmware_max_length=	0x00F00000,
+		.name = "RSPRO",
+		.fw_layout = {
+			.kern_start	=	0xbf030000,
+			.kern_entry	=	0x80060000,
+			.firmware_max_length=	0x00F00000,
+		},
+		.sign = false,
 	},
 	{
-		.name		=	"LS-SR71",
-		.kern_start	=	0xbf030000,
-		.kern_entry	=	0x80060000,
-		.firmware_max_length=	0x00640000,
+		.name = "LS-SR71",
+		.fw_layout = {
+			.kern_start	=	0xbf030000,
+			.kern_entry	=	0x80060000,
+			.firmware_max_length=	0x00640000,
+		},
+		.sign = false,
 	},
 	{
-		.name		=	"XS2-8",
-		.kern_start	=	0xa8030000,
-		.kern_entry	=	0x80041000,
-		.firmware_max_length=	0x006C0000,
+		.name = "XS2-8",
+		.fw_layout = {
+			.kern_start	=	0xa8030000,
+			.kern_entry	=	0x80041000,
+			.firmware_max_length=	0x006C0000,
+		},
+		.sign = false,
+
 	},
 	{
-		.name		=	"XM",
-		.kern_start	=	0x9f050000,
-		.kern_entry	=	0x80002000,
-		.firmware_max_length=	0x00760000,
+		.name = "XM",
+		.fw_layout = {
+			.kern_start	=	0x9f050000,
+			.kern_entry	=	0x80002000,
+			.firmware_max_length=	0x00760000,
+		},
+		.sign = false,
 	},
 	{
-		.name		=	"UBDEV01",
-		.kern_start	=	0x9f050000,
-		.kern_entry	=	0x80002000,
-		.firmware_max_length=	0x006A0000,
+		.name = "UBDEV01",
+		.fw_layout = {
+			.kern_start	=	0x9f050000,
+			.kern_entry	=	0x80002000,
+			.firmware_max_length=	0x006A0000,
+		},
+		.sign = false,
 	},
-	{	.name		=	"",
+	{
+		.name = "WA",
+		.fw_layout = {
+			.kern_start	=	0x9f050000,
+			.kern_entry	=	0x80002000,
+			.firmware_max_length=	0x00F60000,
+		},
+		.sign = true,
+	},
+	{
+		.name = "",
 	},
 };
 
@@ -116,8 +157,20 @@ typedef struct image_info {
 	char outputfile[PATH_MAX];
 	u_int32_t	part_count;
 	part_data_t parts[MAX_SECTIONS];
+	struct fw_info* fwinfo;
 } image_info_t;
 
+static struct fw_info* get_fwinfo(char* board_name) {
+	struct fw_info *fwinfo = fw_info;
+	while(strlen(fwinfo->name)) {
+		if(strcmp(fwinfo->name, board_name) == 0) {
+			return fwinfo;
+		}
+		fwinfo++;
+	}
+	return NULL;
+}
+
 static void write_header(void* mem, const char *magic, const char* version)
 {
 	header_t* header = mem;
@@ -142,6 +195,17 @@ static void write_signature(void* mem, u_int32_t sig_offset)
 	sign->pad = 0L;
 }
 
+static void write_signature_rsa(void* mem, u_int32_t sig_offset)
+{
+	/* write signature */
+	signature_rsa_t* sign = (signature_rsa_t*)(mem + sig_offset);
+	memset(sign, 0, sizeof(signature_rsa_t));
+
+	memcpy(sign->magic, MAGIC_ENDS, MAGIC_LENGTH);
+//	sign->crc = htonl(crc32(0L,(unsigned char *)mem, sig_offset));
+	sign->pad = 0L;
+}
+
 static int write_part(void* mem, part_data_t* d)
 {
 	char* addr;
@@ -237,17 +301,9 @@ static int create_image_layout(const char* kernelfile, const char* rootfsfile, c
 	part_data_t* kernel = &im->parts[0];
 	part_data_t* rootfs = &im->parts[1];
 
-	fw_layout_t* p;
+	fw_layout_t* p = &im->fwinfo->fw_layout;
 
-	p = &fw_layout_data[0];
-	while (*p->name && (strcmp(p->name, board_name) != 0))
-		p++;
-	if (!*p->name) {
-		printf("BUG! Unable to find default fw layout!\n");
-		exit(-1);
-	}
-
-	printf("board = %s\n", p->name);
+	printf("board = %s\n", im->fwinfo->name);
 	strcpy(kernel->partition_name, "kernel");
 	kernel->partition_index = 1;
 	kernel->partition_baseaddr = p->kern_start;
@@ -330,7 +386,12 @@ static int build_image(image_info_t* im)
 	int i;
 
 	// build in-memory buffer
-	mem_size = sizeof(header_t) + sizeof(signature_t);
+	mem_size = sizeof(header_t);
+	if(im->fwinfo->sign) {
+		mem_size += sizeof(signature_rsa_t);
+	} else {
+		mem_size += sizeof(signature_t);
+	}
 	for (i = 0; i < im->part_count; ++i)
 	{
 		part_data_t* d = &im->parts[i];
@@ -359,7 +420,11 @@ static int build_image(image_info_t* im)
 		ptr += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
 	}
 	// write signature
-	write_signature(mem, mem_size - sizeof(signature_t));
+	if(im->fwinfo->sign) {
+		write_signature_rsa(mem, mem_size - sizeof(signature_rsa_t));
+	} else {
+		write_signature(mem, mem_size - sizeof(signature_t));
+	}
 
 	// write in-memory buffer into file
 	if ((f = fopen(im->outputfile, "w")) == NULL)
@@ -388,6 +453,7 @@ int main(int argc, char* argv[])
 	char board_name[PATH_MAX];
 	int o, rc;
 	image_info_t im;
+	struct fw_info *fwinfo;
 
 	memset(&im, 0, sizeof(im));
 	memset(kernelfile, 0, sizeof(kernelfile));
@@ -447,6 +513,14 @@ int main(int argc, char* argv[])
 		return -2;
 	}
 
+	if ((fwinfo = get_fwinfo(board_name)) == NULL) {
+		ERROR("Invalid baord name '%s'\n", board_name);
+		usage(argv[0]);
+		return -2;
+	}
+
+	im.fwinfo = fwinfo;
+
 	if ((rc = create_image_layout(kernelfile, rootfsfile, board_name, &im)) != 0)
 	{
 		ERROR("Failed creating firmware layout description - error code: %d\n", rc);