void _check_success(int rc, YKP_CONFIG *cfg, unsigned char expected[], int caller_line) { struct config_st *ycfg; bool config_matches_expected = false; if (rc != 1) { fprintf(stderr, "TEST FAILED (line %i of %s)\n", caller_line, __FILE__); fprintf(stderr, "Error returned : %i/%i (%s)\n", rc, ykp_errno, ykp_strerror(ykp_errno)); } assert(rc == 1); ycfg = (struct config_st *) ykp_core_config(cfg); /* insert CRC */ ycfg->crc = ~yubikey_crc16 ((unsigned char *) ycfg, offsetof(struct config_st, crc)); ycfg->crc = yk_endian_swap_16(ycfg->crc); config_matches_expected = ! memcmp(expected, ycfg, sizeof(*ycfg)); if (! config_matches_expected) { fprintf(stderr, "TEST FAILED (line %i of %s)\n", caller_line, __FILE__); _yktest_hexdump ("BAD MATCH :\n", ycfg, sizeof(*ycfg), 7); _yktest_hexdump ("EXPECTED :\n", expected, sizeof(*ycfg), 7); } assert(config_matches_expected == true); }
int yk_get_status(YK_KEY *k, YK_STATUS *status) { unsigned int status_count = 0; if (!yk_read_from_key(k, 0, status, sizeof(YK_STATUS), &status_count)) return 0; if (status_count != sizeof(YK_STATUS)) { yk_errno = YK_EWRONGSIZ; return 0; } status->touchLevel = yk_endian_swap_16(status->touchLevel); return 1; }
int yk_write_command(YK_KEY *yk, YK_CONFIG *cfg, uint8_t command, unsigned char *acc_code) { unsigned char buf[sizeof(YK_CONFIG) + ACC_CODE_SIZE]; /* Update checksum and insert config block in buffer if present */ memset(buf, 0, sizeof(buf)); if (cfg) { cfg->crc = ~yubikey_crc16 ((unsigned char *) cfg, sizeof(YK_CONFIG) - sizeof(cfg->crc)); cfg->crc = yk_endian_swap_16(cfg->crc); memcpy(buf, cfg, sizeof(YK_CONFIG)); } /* Append current access code if present */ if (acc_code) memcpy(buf + sizeof(YK_CONFIG), acc_code, ACC_CODE_SIZE); return _yk_write(yk, command, buf, sizeof(buf)); }
/* * Send something to the YubiKey. The command, as well as the slot, is * given in the 'slot' parameter (e.g. SLOT_CHAL_HMAC2 to send a HMAC-SHA1 * challenge to slot 2). */ int yk_write_to_key(YK_KEY *yk, uint8_t slot, const void *buf, int bufcount) { YK_FRAME frame; unsigned char repbuf[FEATURE_RPT_SIZE]; int i, seq; unsigned char *ptr, *end; if (bufcount > sizeof(frame.payload)) { yk_errno = YK_EWRONGSIZ; return 0; } /* Insert data and set slot # */ memset(&frame, 0, sizeof(frame)); memcpy(frame.payload, buf, bufcount); frame.slot = slot; /* Append slot checksum */ i = yubikey_crc16 (frame.payload, sizeof(frame.payload)); frame.crc = yk_endian_swap_16(i); /* Chop up the data into parts that fits into the payload of a feature report. Set the sequence number | 0x80 in the end of the feature report. When the Yubikey has processed it, it will clear this byte, signaling that the next part can be sent */ ptr = (unsigned char *) &frame; end = (unsigned char *) &frame + sizeof(frame); #ifdef YK_DEBUG fprintf(stderr, "YK_DEBUG: Write %i bytes to YubiKey :\n", bufcount); #endif for (seq = 0; ptr < end; seq++) { int all_zeros = 1; /* Ignore parts that are all zeroes except first and last to speed up the transfer */ for (i = 0; i < (FEATURE_RPT_SIZE - 1); i++) { if ((repbuf[i] = *ptr++)) all_zeros = 0; } if (all_zeros && (seq > 0) && (ptr < end)) continue; /* sequence number goes into lower bits of last byte */ repbuf[i] = seq | SLOT_WRITE_FLAG; /* When the Yubikey clears the SLOT_WRITE_FLAG, the * next part can be sent. */ if (! yk_wait_for_key_status(yk, slot, 0, WAIT_FOR_WRITE_FLAG, false, SLOT_WRITE_FLAG, NULL)) return 0; #ifdef YK_DEBUG _yk_hexdump(repbuf, FEATURE_RPT_SIZE); #endif if (!_ykusb_write(yk, REPORT_TYPE_FEATURE, 0, (char *)repbuf, FEATURE_RPT_SIZE)) return 0; } return 1; }
int yk_write_config(YK_KEY *yk, YK_CONFIG *cfg, int confnum, unsigned char *acc_code) { unsigned char buf[sizeof(YK_CONFIG) + ACC_CODE_SIZE]; YK_STATUS stat; int seq; uint8_t slot; /* Get current sequence # from status block */ if (!yk_get_status(yk, &stat /*, 0*/)) return 0; seq = stat.pgmSeq; /* Update checksum and insert config block in buffer if present */ memset(buf, 0, sizeof(buf)); if (cfg) { cfg->crc = ~yubikey_crc16 ((unsigned char *) cfg, sizeof(YK_CONFIG) - sizeof(cfg->crc)); cfg->crc = yk_endian_swap_16(cfg->crc); memcpy(buf, cfg, sizeof(YK_CONFIG)); } /* Append current access code if present */ if (acc_code) memcpy(buf + sizeof(YK_CONFIG), acc_code, ACC_CODE_SIZE); /* Write to Yubikey */ switch(confnum) { case 1: slot = SLOT_CONFIG; break; case 2: slot = SLOT_CONFIG2; break; } if (!yk_write_to_key(yk, slot, buf, sizeof(buf))) return 0; /* When the Yubikey clears the SLOT_WRITE_FLAG, it has processed the last write. * This wait can't be done in yk_write_to_key since some users of that function * want to get the bytes in the status message, but when writing configuration * we don't expect any data back. */ yk_wait_for_key_status(yk, slot, 0, WAIT_FOR_WRITE_FLAG, false, SLOT_WRITE_FLAG, NULL); /* Verify update */ if (!yk_get_status(yk, &stat /*, 0*/)) return 0; yk_errno = YK_EWRITEERR; if (cfg) { return stat.pgmSeq != seq; } return stat.pgmSeq == 0; }