comparison main.c @ 47:747695bd4e0d

add printhmac support fix timer for new speed bootid command rebootpi command
author Matt Johnston <matt@ucc.asn.au>
date Mon, 01 Jul 2013 22:15:40 +0800
parents b1c27f1d6289
children
comparison
equal deleted inserted replaced
46:b1c27f1d6289 47:747695bd4e0d
35 35
36 // TICK should be 8 or less (8 untested). all timers need 36 // TICK should be 8 or less (8 untested). all timers need
37 // to be a multiple. 37 // to be a multiple.
38 38
39 #define TICK 1 39 #define TICK 1
40 #define SLEEP_COMPARE (F_CPU/256) // == 19200 for 4915200mhz 40 #define SLEEP_COMPARE (F_CPU/1024) // == 10800 for 11059200hz
41 #define NKEYS 10 41 #define NKEYS 10
42 #define HMACLEN 20 42 #define HMACLEN 20
43 #define AESLEN 16 43 #define AESLEN 16
44 #define KEYLEN HMACLEN 44 #define KEYLEN HMACLEN
45 // 64 bits is enough for a realtime challenge 45 // 64 bits is enough for a realtime challenge
46 #define CHALLEN 8 46 #define CHALLEN 8
47 #define HMAC_PRINT_LEN 3
47 48
48 #define BAUD 115200 49 #define BAUD 115200
49 #define UBRR ((F_CPU)/(16*(BAUD))-1) 50 #define UBRR ((F_CPU)/(16*(BAUD))-1)
50 51
51 #define PORT_PI_BOOT PORTD 52 #define PORT_PI_BOOT PORTD
87 // all timeouts should be a multiple of TICK 88 // all timeouts should be a multiple of TICK
88 static uint32_t watchdog_long_limit = WATCHDOG_LONG_DEFAULT; 89 static uint32_t watchdog_long_limit = WATCHDOG_LONG_DEFAULT;
89 static uint32_t watchdog_short_limit = 0; 90 static uint32_t watchdog_short_limit = 0;
90 static uint32_t newboot_limit = NEWBOOT_DEFAULT; 91 static uint32_t newboot_limit = NEWBOOT_DEFAULT;
91 92
92 // avr proves itself 93 // key index 0 is special, used internally for bootid
93 static uint8_t avr_keys[NKEYS][KEYLEN] = {{0}}; 94 static uint8_t avr_keys[NKEYS][KEYLEN] = {{0}};
94 95
95 // ---- Atomic guards required accessing these variables 96 // ---- Atomic guards required accessing these variables
96 // clock_epoch in seconds 97 // clock_epoch in seconds
97 static uint32_t clock_epoch; 98 static uint32_t clock_epoch;
122 // flips between 0 and 1 each watchdog_long_hit, so eventually a 123 // flips between 0 and 1 each watchdog_long_hit, so eventually a
123 // working firmware should boot. set back to 0 for each 'alive' 124 // working firmware should boot. set back to 0 for each 'alive'
124 // command 125 // command
125 static uint8_t long_reboot_mode = 0; 126 static uint8_t long_reboot_mode = 0;
126 127
127 static uint8_t boot_id_set = 0;
128 static uint8_t boot_id[HMACLEN]; 128 static uint8_t boot_id[HMACLEN];
129 129
130 static uint8_t readpos; 130 static uint8_t readpos;
131 static char readbuf[150]; 131 static char readbuf[150];
132 static uint8_t have_cmd; 132 static uint8_t have_cmd;
138 static uint16_t adc_5v(uint16_t vcc); 138 static uint16_t adc_5v(uint16_t vcc);
139 static uint16_t adc_temp(); 139 static uint16_t adc_temp();
140 static void set_pi_boot_normal(uint8_t normal); 140 static void set_pi_boot_normal(uint8_t normal);
141 static void adc_random(uint8_t admux, 141 static void adc_random(uint8_t admux,
142 uint8_t *out, uint16_t num, uint32_t *tries); 142 uint8_t *out, uint16_t num, uint32_t *tries);
143 143 void printhex(uint8_t *id, uint8_t n, FILE *stream);
144 static void cmd_rebootpi();
145
146 uint8_t uart_hmac_print;
147 uint32_t uart_hmac_counter;
148 hmac_sha1_ctx_t uart_hmac_ctx;
149 uint8_t uart_hmac_buf[SHA1_BLOCK_BITS/8];
150 uint8_t uart_hmac_index;
144 static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, 151 static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,
145 _FDEV_SETUP_WRITE); 152 _FDEV_SETUP_WRITE);
153 static FILE _rawstdout = FDEV_SETUP_STREAM(uart_putchar, NULL,
154 _FDEV_SETUP_WRITE);
155 static FILE *raw_stdout = &_rawstdout;
146 156
147 // thanks to http://projectgus.com/2010/07/eeprom-access-with-arduino/ 157 // thanks to http://projectgus.com/2010/07/eeprom-access-with-arduino/
148 #define eeprom_read_to(dst_p, eeprom_field, dst_size) eeprom_read_block((dst_p), (void *)offsetof(struct __eeprom_data, eeprom_field), (dst_size)) 158 #define eeprom_read_to(dst_p, eeprom_field, dst_size) eeprom_read_block((dst_p), (void *)offsetof(struct __eeprom_data, eeprom_field), (dst_size))
149 #define eeprom_read(dst, eeprom_field) eeprom_read_to((&dst), eeprom_field, sizeof(dst)) 159 #define eeprom_read(dst, eeprom_field) eeprom_read_to((&dst), eeprom_field, sizeof(dst))
150 #define eeprom_write_from(src_p, eeprom_field, src_size) eeprom_write_block((src_p), (void *)offsetof(struct __eeprom_data, eeprom_field), (src_size)) 160 #define eeprom_write_from(src_p, eeprom_field, src_size) eeprom_write_block((src_p), (void *)offsetof(struct __eeprom_data, eeprom_field), (src_size))
226 TCCR1A = _BV(COM1A0); 236 TCCR1A = _BV(COM1A0);
227 #ifdef SIM_DEBUG 237 #ifdef SIM_DEBUG
228 // systemclock/8 238 // systemclock/8
229 TCCR1B = _BV(CS11); 239 TCCR1B = _BV(CS11);
230 #else 240 #else
231 // systemclock/256 241 // systemclock/1024
232 TCCR1B = _BV(CS12); 242 TCCR1B = _BV(CS12) | _BV(CS10);
233 #endif 243 #endif
234 TCNT1 = 0; 244 TCNT1 = 0;
235 OCR1A = SLEEP_COMPARE; 245 OCR1A = SLEEP_COMPARE;
236 // interrupt 246 // interrupt
237 TIMSK1 = _BV(OCIE1A); 247 TIMSK1 = _BV(OCIE1A);
256 static char sim_out[140]; 266 static char sim_out[140];
257 static uint8_t sim_idx = 0; 267 static uint8_t sim_idx = 0;
258 static uint8_t last_sim_idx = 0; 268 static uint8_t last_sim_idx = 0;
259 #endif 269 #endif
260 270
271 static void
272 reset_uart_hmac(void)
273 {
274 uart_hmac_counter++;
275 uint8_t key[KEYLEN + sizeof(boot_id) + sizeof(uart_hmac_counter)];
276 uint8_t *k = key;
277 memcpy(k, avr_keys[0], KEYLEN);
278 k += KEYLEN;
279 memcpy(k, boot_id, sizeof(boot_id));
280 k += sizeof(boot_id);
281 memcpy(k, &uart_hmac_counter, sizeof(uart_hmac_counter));
282
283 hmac_sha1_init(&uart_hmac_ctx, key, 8*sizeof(key));
284 uart_hmac_index = 0;
285 }
286
287 static void
288 uart_hmac(char c)
289 {
290 if (c == '\r' || c == '\n')
291 {
292 hmac_sha1_lastBlock(&uart_hmac_ctx, uart_hmac_buf, 8*uart_hmac_index);
293 uint8_t hmac_out[HMACLEN];
294 hmac_sha1_final(hmac_out, &uart_hmac_ctx);
295
296 if (uart_hmac_print)
297 {
298 fputc(' ', raw_stdout);
299 printhex((uint8_t*)&uart_hmac_counter, sizeof(uart_hmac_counter), raw_stdout);
300 fputc(' ', raw_stdout);
301 printhex(hmac_out, HMAC_PRINT_LEN, raw_stdout);
302 }
303
304 reset_uart_hmac();
305
306 return;
307 }
308
309 if (uart_hmac_index == sizeof(uart_hmac_buf))
310 {
311 hmac_sha1_nextBlock(&uart_hmac_ctx, uart_hmac_buf);
312 uart_hmac_index = 0;
313 }
314
315 uart_hmac_buf[uart_hmac_index] = c;
316 uart_hmac_index++;
317 }
318
319 static void
320 cmd_printhmac(const char *arg)
321 {
322 uart_hmac_print = (strtoul(arg, NULL, 10) != 0);
323 if (uart_hmac_print)
324 {
325 printf_P(PSTR("hmac printing on\n"));
326 }
327 else
328 {
329 printf_P(PSTR("hmac printing off\n"));
330 }
331 }
332
261 int 333 int
262 uart_putchar(char c, FILE *stream) 334 uart_putchar(char c, FILE *stream)
263 { 335 {
336 if (stream != raw_stdout)
337 {
338 uart_hmac(c);
339 }
264 // XXX could perhaps sleep in the loop for power. 340 // XXX could perhaps sleep in the loop for power.
265 if (c == '\n') 341 if (c == '\n')
266 { 342 {
267 loop_until_bit_is_set(UCSR0A, UDRE0); 343 loop_until_bit_is_set(UCSR0A, UDRE0);
268 UDR0 = '\r'; 344 UDR0 = '\r';
629 { 705 {
630 printf_P(PSTR("FAIL: Bad input\n")); 706 printf_P(PSTR("FAIL: Bad input\n"));
631 return; 707 return;
632 } 708 }
633 709
710 if (key_index == 0)
711 {
712 printf_P(PSTR("Can't use key index 0\n"));
713 return;
714 }
715
634 #ifndef SIM_DEBUG 716 #ifndef SIM_DEBUG
635 long_delay(200); 717 long_delay(200);
636 #endif 718 #endif
637 719
638 hmac_sha1(outdata, avr_keys[key_index], KEYLEN*8, indata, sizeof(indata)*8); 720 hmac_sha1(outdata, avr_keys[key_index], KEYLEN*8, indata, sizeof(indata)*8);
648 uint8_t output[AESLEN]; 730 uint8_t output[AESLEN];
649 uint8_t key_index; 731 uint8_t key_index;
650 if (parse_key(params, &key_index, indata, sizeof(indata)) != 0) 732 if (parse_key(params, &key_index, indata, sizeof(indata)) != 0)
651 { 733 {
652 printf_P(PSTR("FAIL: Bad input\n")); 734 printf_P(PSTR("FAIL: Bad input\n"));
735 return;
736 }
737
738 if (key_index == 0)
739 {
740 printf_P(PSTR("Can't use key index 0\n"));
653 return; 741 return;
654 } 742 }
655 743
656 #ifndef SIM_DEBUG 744 #ifndef SIM_DEBUG
657 long_delay(200); 745 long_delay(200);
760 adc_random(0x44, rnd, sizeof(rnd), &tries); 848 adc_random(0x44, rnd, sizeof(rnd), &tries);
761 hmac_sha1(out, buildid, sizeof(buildid)*8, rnd, sizeof(rnd)*8); 849 hmac_sha1(out, buildid, sizeof(buildid)*8, rnd, sizeof(rnd)*8);
762 } 850 }
763 851
764 static void 852 static void
853 cmd_newbootid()
854 {
855 get_random(boot_id);
856 reset_uart_hmac();
857 printf_P(PSTR("bootid cleared\n"));
858 }
859
860 static void
765 cmd_bootid(const char *arg) 861 cmd_bootid(const char *arg)
766 { 862 {
767 uint8_t hmac[HMACLEN]; 863 uint8_t hmac[HMACLEN];
768 uint8_t input[CHALLEN+sizeof(boot_id)]; 864 uint8_t input[CHALLEN+sizeof(boot_id)];
769 865
770 if (!boot_id_set)
771 {
772 _Static_assert(sizeof(boot_id) == HMACLEN, "boot_id size correct");
773 get_random(boot_id);
774 boot_id_set = 1;
775 }
776
777 if (strlen(arg) != CHALLEN*2) 866 if (strlen(arg) != CHALLEN*2)
778 { 867 {
779 printf_P(PSTR("Bad challenge\n")); 868 printf_P(PSTR("Bad challenge\n"));
780 } 869 }
781 for (int i = 0, p = 0; i < CHALLEN; i++, p += 2) 870 for (int i = 0, p = 0; i < CHALLEN; i++, p += 2)
1060 LOCAL_PSTR(oldboot); 1149 LOCAL_PSTR(oldboot);
1061 LOCAL_PSTR(status); 1150 LOCAL_PSTR(status);
1062 LOCAL_PSTR(random); 1151 LOCAL_PSTR(random);
1063 LOCAL_PSTR(prog); 1152 LOCAL_PSTR(prog);
1064 LOCAL_PSTR(bootid); 1153 LOCAL_PSTR(bootid);
1154 LOCAL_PSTR(newbootid);
1155 LOCAL_PSTR(rebootpi);
1156 LOCAL_PSTR(printhmac);
1065 LOCAL_HELP(set_params, "<long_limit> <short_limit> <newboot_limit>"); 1157 LOCAL_HELP(set_params, "<long_limit> <short_limit> <newboot_limit>");
1066 LOCAL_HELP(set_key, "20_byte_hex>"); 1158 LOCAL_HELP(set_key, "20_byte_hex>");
1067 LOCAL_HELP(oneshot, "<timeout>"); 1159 LOCAL_HELP(oneshot, "<timeout>");
1068 LOCAL_HELP(prog, "<password>"); 1160 LOCAL_HELP(prog, "<password>");
1069 LOCAL_HELP(random, "<admux> <nbytes>"); 1161 LOCAL_HELP(random, "<admux> <nbytes>");
1070 LOCAL_HELP(hmac, "<key_index> <20_byte_hex_data>"); 1162 LOCAL_HELP(hmac, "<key_index> <20_byte_hex_data>");
1071 LOCAL_HELP(decrypt, "<key_index> <20_byte_hmac|16_byte_aes_block>"); 1163 LOCAL_HELP(decrypt, "<key_index> <20_byte_hmac|16_byte_aes_block>");
1072 LOCAL_HELP(bootid, "<8_byte_challenge>") 1164 LOCAL_HELP(bootid, "<8_byte_challenge>")
1165 LOCAL_HELP(printhmac, "<0|1>")
1073 1166
1074 static const struct handler { 1167 static const struct handler {
1075 PGM_P name; 1168 PGM_P name;
1076 void(*cmd)(const char *param); 1169 void(*cmd)(const char *param);
1077 // existence of arg_help indicates if the cmd takes a parameter. 1170 // existence of arg_help indicates if the cmd takes a parameter.
1089 {set_params_str, cmd_set_params, set_params_help}, 1182 {set_params_str, cmd_set_params, set_params_help},
1090 {set_key_str, cmd_set_avr_key, set_key_help}, 1183 {set_key_str, cmd_set_avr_key, set_key_help},
1091 {random_str, cmd_random, random_help}, 1184 {random_str, cmd_random, random_help},
1092 {vcc_str, cmd_vcc, NULL}, 1185 {vcc_str, cmd_vcc, NULL},
1093 {reset_str, cmd_reset, NULL}, 1186 {reset_str, cmd_reset, NULL},
1187 {rebootpi_str, cmd_rebootpi, NULL},
1094 {prog_str, cmd_prog, prog_help}, 1188 {prog_str, cmd_prog, prog_help},
1095 {bootid_str, cmd_bootid, bootid_help}, 1189 {bootid_str, cmd_bootid, bootid_help},
1190 {newbootid_str, cmd_newbootid, NULL},
1191 {printhmac_str, cmd_printhmac, printhmac_help},
1096 }; 1192 };
1097 1193
1098 if (readbuf[0] == '\0') 1194 if (readbuf[0] == '\0')
1099 { 1195 {
1100 return; 1196 return;
1249 1345
1250 static void 1346 static void
1251 reboot_pi() 1347 reboot_pi()
1252 { 1348 {
1253 printf_P(PSTR("Real reboot now\n")); 1349 printf_P(PSTR("Real reboot now\n"));
1254 boot_id_set = 0; 1350 cmd_newbootid();
1255 // pull it low for 200ms 1351 // pull it low for 200ms
1256 PORT_PI_RESET &= ~_BV(PIN_PI_RESET); 1352 PORT_PI_RESET &= ~_BV(PIN_PI_RESET);
1257 DDR_PI_RESET |= _BV(PIN_PI_RESET); 1353 DDR_PI_RESET |= _BV(PIN_PI_RESET);
1258 long_delay(200); 1354 long_delay(200);
1259 1355
1260 PORT_PI_WARNING &= ~_BV(PIN_PI_WARNING); 1356 PORT_PI_WARNING &= ~_BV(PIN_PI_WARNING);
1261 DDR_PI_RESET &= ~_BV(PIN_PI_RESET); 1357 DDR_PI_RESET &= ~_BV(PIN_PI_RESET);
1262 } 1358 }
1263 1359
1264 static void 1360 static void
1361 cmd_rebootpi()
1362 {
1363 printf_P(PSTR("Rebooting.\n"));
1364 long_delay(1000);
1365 reboot_pi();
1366 }
1367
1368
1369 static void
1265 wait_reboot_pi() 1370 wait_reboot_pi()
1266 { 1371 {
1267 PORT_PI_WARNING |= _BV(PIN_PI_WARNING); 1372 PORT_PI_WARNING |= _BV(PIN_PI_WARNING);
1268 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) 1373 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
1269 { 1374 {
1394 wdt_disable(); 1499 wdt_disable();
1395 } 1500 }
1396 1501
1397 int main(void) 1502 int main(void)
1398 { 1503 {
1399 _Static_assert(F_CPU % 256 == 0, "clock prescaler remainder 0"); 1504 _Static_assert(F_CPU % 1024 == 0, "clock prescaler remainder 0");
1400 _Static_assert(NEWBOOT_MAX < WATCHDOG_LONG_MIN, "newboot max shorter than watchdog min"); 1505 _Static_assert(NEWBOOT_MAX < WATCHDOG_LONG_MIN, "newboot max shorter than watchdog min");
1401 _Static_assert((F_CPU)%(16*(BAUD)) == 0, "baud rate good multiple"); 1506 _Static_assert((F_CPU)%(16*(BAUD)) == 0, "baud rate good multiple");
1402 1507
1403 setup_chip(); 1508 setup_chip();
1404 blink(); 1509 blink();
1405 1510
1406 stdout = &mystdout; 1511 stdout = raw_stdout;
1407 uart_on(); 1512 uart_on();
1408 1513
1409 long_delay(500); 1514 long_delay(500);
1410 printf_P(PSTR("Pi Watchdog\nMatt Johnston [email protected]\n")); 1515 printf_P(PSTR("Pi Watchdog\nMatt Johnston [email protected]\n"));
1411 1516
1412 set_pi_boot_normal(0); 1517 set_pi_boot_normal(0);
1413 1518
1414 load_params(); 1519 load_params();
1520
1521 cmd_newbootid();
1522 reset_uart_hmac();
1523 stdout = &mystdout;
1415 1524
1416 setup_tick_counter(); 1525 setup_tick_counter();
1417 1526
1418 sei(); 1527 sei();
1419 1528