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