• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/sign_dlink_ru.c

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * This program is designed to sign firmware images so they are accepted
  4  * by D-Link DIR-882 R1 WebUIs.
  5  *
  6  * Copyright (C) 2020 Andrew Pikler
  7  */
  8 
  9 #include <stdlib.h>
 10 #include <stdint.h>
 11 #include <stdio.h>
 12 #include <string.h>
 13 #include <sys/types.h>
 14 #include <sys/stat.h>
 15 #include <fcntl.h>
 16 
 17 #include "md5.h"
 18 
 19 #define BUF_SIZE 4096
 20 #define MD5_HASH_LEN 16
 21 
 22 
 23 typedef struct _md5_digest_t {
 24         uint8_t digest[MD5_HASH_LEN];
 25 } md5_digest_t;
 26 
 27 typedef struct _salt_t {
 28         char* salt_ascii;
 29         uint8_t* salt_bin;
 30         size_t salt_bin_len;
 31 } salt_t;
 32 
 33 void read_file_bytes(FILE* f, MD5_CTX* md5_ctx) {
 34         uint8_t buf[BUF_SIZE];
 35         size_t bytes_read;
 36         rewind(f);
 37         
 38         while (0 != (bytes_read = fread(buf, sizeof(uint8_t), BUF_SIZE, f))) {
 39                 MD5_Update(md5_ctx, buf, bytes_read);
 40         }
 41 
 42         if (!feof(f)) {
 43                 printf("Error: expected to be at EOF\n");
 44                 exit(-1);
 45         }
 46 }
 47 
 48 void add_magic_bytes(FILE* f) {
 49         char magic_bytes[] = { 0x00, 0xc0, 0xff, 0xee };
 50         size_t magic_bytes_len = 4;
 51         fwrite(magic_bytes, magic_bytes_len, 1, f);
 52 }
 53 
 54 /**
 55  * Add the signature produced by this salt to the file
 56  * The signature consists by creating an MD5 digest wht the salt bytes plus
 57  * all of the bytes in the firmware file, then adding the magic bytes to the
 58  * file
 59  */
 60 void add_signature(FILE* f, salt_t* salt) {
 61         md5_digest_t digest;
 62         MD5_CTX md5_context;
 63 
 64         MD5_Init(&md5_context);
 65         MD5_Update(&md5_context, salt->salt_bin, salt->salt_bin_len);
 66         read_file_bytes(f, &md5_context);
 67         MD5_Final(digest.digest, &md5_context);
 68 
 69         fwrite(&digest.digest, sizeof(uint8_t), MD5_HASH_LEN, f);
 70         add_magic_bytes(f);
 71 }
 72 
 73 void add_version_suffix(FILE* f) {
 74         char* version_suffix = "c0ffeef0rge";
 75         fseek(f, 0, SEEK_END);
 76         fwrite(version_suffix, sizeof(char), strlen(version_suffix), f);
 77 }
 78 
 79 int asciihex_to_int(char c) {
 80         if(c >= '' && c <= 'F')
 81                 return c - '';
 82 
 83         if(c >= 'a' && c <= 'f')
 84                 return 10 + c - 'a';
 85         return -1;
 86 }
 87 
 88 /**
 89  * Verify this is a valid hex string to convert
 90  */
 91 void verify_valid_hex_str(char* s) {
 92         int i;
 93         int s_len = strlen(s);
 94         if (s_len == 0) {
 95                 printf("invalid empty salt: %s\n", s);
 96                 exit(-1);
 97         }
 98 
 99         if (s_len % 2 != 0) {
100                 printf("invalid odd len salt: %s\n", s);
101                 exit(-1);
102         }
103 
104         for (i = 0; i < s_len; ++i) {
105                 if (asciihex_to_int(s[i]) < 0) {
106                         printf("invalid salt (invalid hex char): %s\n", s);
107                         exit(-1);
108                 }
109         }
110 }
111 
112 /**
113  * Convert a hex ascii string to an allocated binary array. This array must be free'd
114  */
115 uint8_t* convert_hex_to_bin(char * s) {
116         int i;
117         int s_len = strlen(s);
118 
119         uint8_t* ret = malloc(s_len / 2);
120         for (i = 0; i < s_len; i += 2) {
121                 ret[i / 2] = (asciihex_to_int(s[i]) << 4) | asciihex_to_int(s[i + 1]);
122         }
123 
124         return ret;
125 }
126 
127 void init_salt(salt_t* salt, char * salt_ascii) {
128         salt->salt_ascii = salt_ascii;
129         salt->salt_bin = convert_hex_to_bin(salt_ascii);
130         salt->salt_bin_len = strlen(salt_ascii) / 2;
131 }
132 
133 void free_salt(salt_t* salt) {
134         free(salt->salt_bin);
135 }
136 
137 /**
138  * Verify that the arguments are valid, or exit with failure
139  */
140 void verify_args(int argc, char** argv) {
141         int i;
142 
143         if (argc < 3) {
144                 printf("Usage: %s <firmware file> <signing hash1> <signing hash2> ... <signing hash n>\n", argv[0]);
145                 exit(1);
146         }
147 
148         for (i = 2; i < argc; i++) {
149                 verify_valid_hex_str(argv[i]);
150         }
151 }
152 
153 FILE* make_out_file(char* filename) {
154         uint8_t buf[BUF_SIZE];
155         int bytes_read;
156         char* suffix = ".new";
157         int new_filename_len = strlen(filename) + strlen(suffix) + 1;
158         char* new_filename = malloc(new_filename_len);
159         strcpy(new_filename, filename);
160         strcat(new_filename, suffix);
161 
162         FILE* f = fopen(filename, "r+");
163         if (!f) {
164                 printf("cannot open file %s\n", filename);
165                 exit(2);
166         }
167 
168         FILE* out = fopen(new_filename, "w+");
169         free(new_filename);
170         if (!out) {
171                 printf("cannot open file %s\n", filename);
172                 exit(2);
173         }
174 
175         while (0 != (bytes_read = fread(buf, sizeof(uint8_t), BUF_SIZE, f))) {
176                 fwrite(buf, sizeof(uint8_t), bytes_read, out);
177         }
178         fclose(f);
179         return out;
180 }
181 
182 /**
183  * Sign the firmware file after all of our checks have completed
184  */
185 void sign_firmware(char* filename, char** salts, int num_salts) {
186         int i;
187         salt_t salt;
188         FILE* f = make_out_file(filename);
189 
190         // add a version suffix string - dlink versions do something similar before the first signature
191         add_version_suffix(f);
192 
193         //for each of the salts we are supplied with
194         for (i = 0; i < num_salts; i++) {
195                 char* salt_str = salts[i];
196                 // convert this str to binary
197                 init_salt(&salt, salt_str);
198 
199                 // add the signature to the firmware file produced from this salt
200                 add_signature(f, &salt);
201                 free_salt(&salt);
202                 printf("Signed with salt: %s\n", salt_str);
203         }
204 
205         fclose(f);
206 }
207 
208 
209 int main(int argc, char ** argv) {
210         verify_args(argc, argv);
211         sign_firmware(argv[1], argv+2, argc-2);
212         return 0;
213 }
214 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt