/* Read the factory programmed serial number from a YubiKey. * The possibility to retreive the serial number might be disabled * using configuration, so it should not be considered a fatal error * to not be able to read the serial number using this function. * * Serial number reading might also be configured to require user * interaction (YubiKey button press) on startup, in which case flags * might have to have YK_FLAG_MAYBLOCK set - haven't tried that. * * The slot parameter is here for future purposes only. */ int yk_get_serial(YK_KEY *yk, uint8_t slot, unsigned int flags, unsigned int *serial) { unsigned char buf[FEATURE_RPT_SIZE * 2]; unsigned int response_len = 0; unsigned int expect_bytes = 0; memset(buf, 0, sizeof(buf)); if (!yk_write_to_key(yk, SLOT_DEVICE_SERIAL, &buf, 0)) return 0; expect_bytes = 4; if (! yk_read_response_from_key(yk, slot, flags, &buf, sizeof(buf), expect_bytes, &response_len)) return 0; /* Serial number is stored in big endian byte order, despite * everything else in the YubiKey being little endian - for * some good reason I don't remember. */ *serial = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3]); return 1; }
int yk_get_capabilities(YK_KEY *yk, uint8_t slot, unsigned int flags, unsigned char *capabilities, unsigned int *len) { unsigned int response_len = 0; if (!yk_write_to_key(yk, SLOT_YK4_CAPABILITIES, capabilities, 0)) return 0; if (! yk_read_response_from_key(yk, slot, flags, capabilities, *len, 0, /* we have no idea how much data we'll get */ &response_len)) return 0; /* the first data of the capabilities string is the length */ response_len = capabilities[0]; response_len++; /* validate the length we got back from the hardware */ if (response_len > *len) { yk_errno = YK_EWRONGSIZ; return 0; } *len = response_len; return 1; }
int challenge_response(YK_KEY *yk, int slot, char *challenge, unsigned int len, bool hmac, unsigned int flags, bool verbose, char *response, int res_size, unsigned int *res_len) { int yk_cmd; unsigned int response_len = 0; unsigned int expect_bytes = 0; if (res_size < sizeof(64 + 16)) return 0; memset(response, 0, res_size); if (verbose) { fprintf(stderr, "Sending %i bytes %s challenge to slot %i\n", len, (hmac == true)?"HMAC":"Yubico", slot); //_yk_hexdump(challenge, len); } switch(slot) { case 1: yk_cmd = (hmac == true) ? SLOT_CHAL_HMAC1 : SLOT_CHAL_OTP1; break; case 2: yk_cmd = (hmac == true) ? SLOT_CHAL_HMAC2 : SLOT_CHAL_OTP2; break; default: return 0; } if (!yk_write_to_key(yk, yk_cmd, challenge, len)) return 0; if (verbose) { fprintf(stderr, "Reading response...\n"); } /* HMAC responses are 160 bits, Yubico 128 */ expect_bytes = (hmac == true) ? 20 : 16; if (! yk_read_response_from_key(yk, slot, flags, response, res_size, expect_bytes, &response_len)) return 0; if (hmac && response_len > 20) response_len = 20; if (! hmac && response_len > 16) response_len = 16; *res_len = response_len; return 1; }
/* * This function is for doing HMAC-SHA1 or Yubico challenge-response with a key. */ int yk_challenge_response(YK_KEY *yk, uint8_t yk_cmd, int may_block, unsigned int challenge_len, const unsigned char *challenge, unsigned int response_len, unsigned char *response) { unsigned int flags = 0; unsigned int bytes_read = 0; unsigned int expect_bytes = 0; switch(yk_cmd) { case SLOT_CHAL_HMAC1: case SLOT_CHAL_HMAC2: expect_bytes = 20; break; case SLOT_CHAL_OTP1: case SLOT_CHAL_OTP2: expect_bytes = 16; break; default: yk_errno = YK_EINVALIDCMD; return 0; } if (may_block) flags |= YK_FLAG_MAYBLOCK; if (! yk_write_to_key(yk, yk_cmd, challenge, challenge_len)) { return 0; } if (! yk_read_response_from_key(yk, yk_cmd, flags, response, response_len, expect_bytes, &bytes_read)) { return 0; } return 1; }
/* Returns 0 on error and length of response on success * slot = 1 or 2 (slot on yubikey) * challenge = challenge data (must be 32 bytes) * response = 64 byte buffer */ int yubi_hmac_challenge_response(unsigned char slot, unsigned char *challenge, unsigned char *response) { YK_KEY *yk = NULL; bool error = true; int exit_code = 0; int yk_cmd; unsigned int response_len = 0; if (!yk_init()) { printf("\nykchalresp.c:%d ykp_errno: %d yk_errno: %d\n", __LINE__, ykp_errno, yk_errno); exit_code = 2; goto err; } ykp_errno = 0; yk_errno = 0; if (!(yk = yk_open_first_key())) { printf("\nykchalresp.c:%d ykp_errno: %d yk_errno: %d\n", __LINE__, ykp_errno, yk_errno); exit_code = 1; goto err; } memset(response, 0, 64); switch(slot) { case 1: yk_cmd = SLOT_CHAL_HMAC1; break; case 2: yk_cmd = SLOT_CHAL_HMAC2; break; default: goto err; } while (! ( yk_write_to_key(yk, yk_cmd, challenge, 32) && yk_read_response_from_key(yk, slot, YK_FLAG_MAYBLOCK, response, 64, 20, &response_len) ) ) { if (yk_errno == 4) { yk_errno = 0; sleep(1); continue; } else { printf("\nykchalresp.c:%d ykp_errno: %d yk_errno: %d\n", __LINE__, ykp_errno, yk_errno); exit_code = 4; goto err; } } if (response_len > 20) { memset(&response[20], 0, 44); response_len = 20; } exit_code = 0; error = false; err: if (error || exit_code != 0) { report_yk_error(); #ifdef DEBUG SDMCKT_debug_tracking(__FILE__,__LINE__); #endif } if (yk && !yk_close_key(yk)) { report_yk_error(); #ifdef DEBUG SDMCKT_debug_tracking(__FILE__,__LINE__); #endif } if (!yk_release()) { report_yk_error(); #ifdef DEBUG SDMCKT_debug_tracking(__FILE__,__LINE__); #endif } if (response_len == 0) { memset(response, 0, 64); #ifdef DEBUG SDMCKT_debug_tracking(__FILE__,__LINE__); #endif } return response_len; }