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>
#define MAGIC_HEADER "OPEN"
#define MAGIC_PART "PART"
#define MAGIC_END "END."
#define MAGIC_HEADER "OPEN"
#define MAGIC_PART "PART"
#define MAGIC_END "END."
+#define MAGIC_ENDS "ENDS"
u_int32_t pad;
} __attribute__ ((packed)) signature_t;
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__)
#define VERSION "1.2"
#define INFO(...) fprintf(stdout, __VA_ARGS__)
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "fw.h"
typedef struct fw_layout_data {
#include "fw.h"
typedef struct fw_layout_data {
u_int32_t kern_start;
u_int32_t kern_entry;
u_int32_t firmware_max_length;
} fw_layout_t;
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 = "WA",
+ .fw_layout = {
+ .kern_start = 0x9f050000,
+ .kern_entry = 0x80002000,
+ .firmware_max_length= 0x00F60000,
+ },
+ .sign = true,
+ },
+ {
+ .name = "",
char outputfile[PATH_MAX];
u_int32_t part_count;
part_data_t parts[MAX_SECTIONS];
char outputfile[PATH_MAX];
u_int32_t part_count;
part_data_t parts[MAX_SECTIONS];
+ struct fw_info* fwinfo;
+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;
static void write_header(void* mem, const char *magic, const char* version)
{
header_t* header = mem;
+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;
static int write_part(void* mem, part_data_t* d)
{
char* addr;
part_data_t* kernel = &im->parts[0];
part_data_t* rootfs = &im->parts[1];
part_data_t* kernel = &im->parts[0];
part_data_t* rootfs = &im->parts[1];
+ 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;
strcpy(kernel->partition_name, "kernel");
kernel->partition_index = 1;
kernel->partition_baseaddr = p->kern_start;
int i;
// build in-memory buffer
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];
for (i = 0; i < im->part_count; ++i)
{
part_data_t* d = &im->parts[i];
ptr += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
}
// write signature
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)
// write in-memory buffer into file
if ((f = fopen(im->outputfile, "w")) == NULL)
char board_name[PATH_MAX];
int o, rc;
image_info_t im;
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));
memset(&im, 0, sizeof(im));
memset(kernelfile, 0, sizeof(kernelfile));
+ 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);
if ((rc = create_image_layout(kernelfile, rootfsfile, board_name, &im)) != 0)
{
ERROR("Failed creating firmware layout description - error code: %d\n", rc);