Mercurial > pihelp
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 |