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 <tobleminer@gmail.com>
master
Tobias Schramm 2018-01-24 01:38:14 +01:00 committed by Mathias Kresin
parent 4b9882eb92
commit 8f697e406a
2 changed files with 129 additions and 47 deletions

View File

@ -24,6 +24,7 @@
#define MAGIC_HEADER "OPEN" #define MAGIC_HEADER "OPEN"
#define MAGIC_PART "PART" #define MAGIC_PART "PART"
#define MAGIC_END "END." #define MAGIC_END "END."
#define MAGIC_ENDS "ENDS"
#define MAGIC_LENGTH 4 #define MAGIC_LENGTH 4
@ -57,6 +58,13 @@ typedef struct signature {
u_int32_t pad; u_int32_t pad;
} __attribute__ ((packed)) signature_t; } __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 VERSION "1.2"
#define INFO(...) fprintf(stdout, __VA_ARGS__) #define INFO(...) fprintf(stdout, __VA_ARGS__)

View File

@ -29,65 +29,106 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <limits.h> #include <limits.h>
#include <stdbool.h>
#include "fw.h" #include "fw.h"
typedef struct fw_layout_data { typedef struct fw_layout_data {
char name[PATH_MAX];
u_int32_t kern_start; u_int32_t kern_start;
u_int32_t kern_entry; u_int32_t kern_entry;
u_int32_t firmware_max_length; u_int32_t firmware_max_length;
} fw_layout_t; } 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", .name = "XS2",
.kern_start = 0xbfc30000, .fw_layout = {
.kern_entry = 0x80041000, .kern_start = 0xbfc30000,
.firmware_max_length= 0x00390000, .kern_entry = 0x80041000,
.firmware_max_length= 0x00390000,
},
.sign = false,
}, },
{ {
.name = "XS5", .name = "XS5",
.kern_start = 0xbe030000, .fw_layout = {
.kern_entry = 0x80041000, .kern_start = 0xbe030000,
.firmware_max_length= 0x00390000, .kern_entry = 0x80041000,
.firmware_max_length= 0x00390000,
},
.sign = false,
}, },
{ {
.name = "RS", .name = "RS",
.kern_start = 0xbf030000, .fw_layout = {
.kern_entry = 0x80060000, .kern_start = 0xbf030000,
.firmware_max_length= 0x00B00000, .kern_entry = 0x80060000,
.firmware_max_length= 0x00B00000,
},
.sign = false,
}, },
{ {
.name = "RSPRO", .name = "RSPRO",
.kern_start = 0xbf030000, .fw_layout = {
.kern_entry = 0x80060000, .kern_start = 0xbf030000,
.firmware_max_length= 0x00F00000, .kern_entry = 0x80060000,
.firmware_max_length= 0x00F00000,
},
.sign = false,
}, },
{ {
.name = "LS-SR71", .name = "LS-SR71",
.kern_start = 0xbf030000, .fw_layout = {
.kern_entry = 0x80060000, .kern_start = 0xbf030000,
.firmware_max_length= 0x00640000, .kern_entry = 0x80060000,
.firmware_max_length= 0x00640000,
},
.sign = false,
}, },
{ {
.name = "XS2-8", .name = "XS2-8",
.kern_start = 0xa8030000, .fw_layout = {
.kern_entry = 0x80041000, .kern_start = 0xa8030000,
.firmware_max_length= 0x006C0000, .kern_entry = 0x80041000,
.firmware_max_length= 0x006C0000,
},
.sign = false,
}, },
{ {
.name = "XM", .name = "XM",
.kern_start = 0x9f050000, .fw_layout = {
.kern_entry = 0x80002000, .kern_start = 0x9f050000,
.firmware_max_length= 0x00760000, .kern_entry = 0x80002000,
.firmware_max_length= 0x00760000,
},
.sign = false,
}, },
{ {
.name = "UBDEV01", .name = "UBDEV01",
.kern_start = 0x9f050000, .fw_layout = {
.kern_entry = 0x80002000, .kern_start = 0x9f050000,
.firmware_max_length= 0x006A0000, .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]; char outputfile[PATH_MAX];
u_int32_t part_count; u_int32_t part_count;
part_data_t parts[MAX_SECTIONS]; part_data_t parts[MAX_SECTIONS];
struct fw_info* fwinfo;
} image_info_t; } 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) static void write_header(void* mem, const char *magic, const char* version)
{ {
header_t* header = mem; header_t* header = mem;
@ -142,6 +195,17 @@ static void write_signature(void* mem, u_int32_t sig_offset)
sign->pad = 0L; 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) static int write_part(void* mem, part_data_t* d)
{ {
char* addr; 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* kernel = &im->parts[0];
part_data_t* rootfs = &im->parts[1]; part_data_t* rootfs = &im->parts[1];
fw_layout_t* p; fw_layout_t* p = &im->fwinfo->fw_layout;
p = &fw_layout_data[0]; printf("board = %s\n", im->fwinfo->name);
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);
strcpy(kernel->partition_name, "kernel"); strcpy(kernel->partition_name, "kernel");
kernel->partition_index = 1; kernel->partition_index = 1;
kernel->partition_baseaddr = p->kern_start; kernel->partition_baseaddr = p->kern_start;
@ -330,7 +386,12 @@ static int build_image(image_info_t* im)
int i; int i;
// build in-memory buffer // 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) for (i = 0; i < im->part_count; ++i)
{ {
part_data_t* d = &im->parts[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); ptr += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
} }
// write signature // 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 // write in-memory buffer into file
if ((f = fopen(im->outputfile, "w")) == NULL) if ((f = fopen(im->outputfile, "w")) == NULL)
@ -388,6 +453,7 @@ int main(int argc, char* argv[])
char board_name[PATH_MAX]; char board_name[PATH_MAX];
int o, rc; int o, rc;
image_info_t im; image_info_t im;
struct fw_info *fwinfo;
memset(&im, 0, sizeof(im)); memset(&im, 0, sizeof(im));
memset(kernelfile, 0, sizeof(kernelfile)); memset(kernelfile, 0, sizeof(kernelfile));
@ -447,6 +513,14 @@ int main(int argc, char* argv[])
return -2; 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) if ((rc = create_image_layout(kernelfile, rootfsfile, board_name, &im)) != 0)
{ {
ERROR("Failed creating firmware layout description - error code: %d\n", rc); ERROR("Failed creating firmware layout description - error code: %d\n", rc);