mkfwimage: Add image type definition for WA images
authorTobias Schramm <tobleminer@gmail.com>
Wed, 24 Jan 2018 00:38:14 +0000 (01:38 +0100)
committerMathias Kresin <dev@kresin.me>
Sun, 7 Oct 2018 08:46:20 +0000 (10:46 +0200)
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>
tools/firmware-utils/src/fw.h
tools/firmware-utils/src/mkfwimage.c

index e37859c..44f8d85 100644 (file)
@@ -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__)
index d8d5239..2b84d3d 100644 (file)
 #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);