/// /// Check if the specified slot has been configured /// __declspec(dllexport) int IsSlotConfigured(int slot, bool* result) { YK_INFO info; YK_KEY* key; key = yk_open_first_key(); if (key == NULL) { _lastError = yk_errno; return ERROR_CANNOT_OPEN_KEY; } yk_get_status(key, &info.status); if (slot == 1 && (info.status.touchLevel & CONFIG1_VALID) != 0) { *result = true; } else if (slot == 2 && (info.status.touchLevel & CONFIG2_VALID) != 0) { *result = true; } else { *result = false; } yk_close_key(key); return 0; }
void YubiKeyWriter::doChallengeResponse(const QString challenge, QString &response, int slot, bool hmac) { YubiKeyFinder::getInstance()->stop(); YK_KEY *yk = 0; bool error = false; qDebug() << "Challenge to slot " << slot << " with challenge: " << challenge; try { int yk_cmd; QByteArray chal_array = challenge.toLatin1(); const unsigned char *chal = reinterpret_cast<const unsigned char*>(chal_array.constData()); unsigned char resp[64]; memset(resp, 0, sizeof(resp)); if (!(yk = yk_open_first_key())) { throw 0; } 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: throw 0; break; } if(! yk_challenge_response(yk, yk_cmd, 1, challenge.length(), chal, sizeof(resp), resp)) { throw 0; } // 20 (160 bits) for hmac-sha1 and 16 (128 bits) for yubico mode if(hmac == true) { response = YubiKeyUtil::qstrHexEncode(resp, 20); } else { response = YubiKeyUtil::qstrModhexEncode(resp, 16); } emit diagnostics(QString("Successful challenge response with slot %1").arg(slot)); } catch(...) { error = true; } if (yk && !yk_close_key(yk)) { error = true; } YubiKeyFinder::getInstance()->start(); if(error) { qDebug() << "Challenge response failed."; QString errMsg = reportError(true); } }
int init_yubikey(YK_KEY **yk) { if (!yk_init()) return 0; if (!(*yk = yk_open_first_key())) return 0; return 1; }
void YubiKeyWriter::deleteConfig(int slot, const QString accCode) { bool error = false; YK_KEY *yk = NULL; YKP_CONFIG *cfg = ykp_alloc(); YubiKeyFinder::getInstance()->stop(); try { if (!(yk = yk_open_first_key())) { throw 0; } unsigned char accessCode[MAX_SIZE]; size_t accessCodeLen = 0; if(accCode.length() > 0) { int rc = encodeAccessCode(accCode, accessCode, &accessCodeLen); if (rc <= 0) { qDebug() << "Invalid access code: " << accCode; throw 0; } } // write NULL to delete config if (!yk_write_config(yk, NULL, slot, accessCodeLen > 0 ? accessCode : NULL)) { qDebug() << "Failed to delete."; throw 0; } emit configWritten(true, NULL); qDebug() << "successfully deleted slot " << slot; emit diagnostics(QString("Deleted slot %1").arg(slot)); } catch(...) { error = true; } if (cfg) { ykp_free_config(cfg); } if (yk && !yk_close_key(yk)) { error = true; } YubiKeyFinder::getInstance()->start(); if(error) { qDebug() << "Failed to delete configuration in slot" << slot; QString errMsg = reportError(); emit configWritten(false, errMsg); } }
/// /// Perform a ChallengeResponse operation on specified slot /// __declspec(dllexport) int ChallengeResponse(uint32_t slot, BOOL may_block, const unsigned char *challenge, uint32_t challenge_len, unsigned char *response, uint32_t response_len) { uint8_t command; YK_KEY* key; int result; if (slot == 1) { command = SLOT_CHAL_HMAC1; } else if (slot == 2) { command = SLOT_CHAL_HMAC2; } else { // invalid slot return ERROR_INVALID_SLOT; } if (challenge_len > 64) { // cannot be bigger than 64 bytes return ERROR_CHALLENGE_TOO_BIG; } key = yk_open_first_key(); if (key == NULL) { return ERROR_CANNOT_OPEN_KEY; } result = 0; if (!yk_challenge_response(key, command, may_block, challenge_len, challenge, response_len, response)) { _lastError = yk_errno; result = ERROR_IN_CHALLENGE_RESPONSE; } yk_close_key(key); return result; }
void YubiKeyWriter::writeNdef(bool uri, const QString language, const QString payload, const QString accCode, int slot) { YubiKeyFinder::getInstance()->stop(); YK_KEY *yk = 0; YK_NDEF *ndef = ykp_alloc_ndef(); bool error = false; qDebug() << "Writing ndef " << payload << " of type " << uri; try { if(accCode.length() > 0) { unsigned char accessCode[MAX_SIZE]; size_t accessCodeLen = 0; int rc = encodeAccessCode(accCode, accessCode, &accessCodeLen); if (rc <= 0) { qDebug() << "Invalid access code: " << accCode; throw 0; } ykp_set_ndef_access_code(ndef, accessCode); } QByteArray payload_array = payload.toUtf8(); const char *ndef_payload = payload_array.constData(); qDebug() << "payload: " << ndef_payload; if (!(yk = yk_open_first_key())) { throw 0; } if(uri) { if(!ykp_construct_ndef_uri(ndef, ndef_payload)) { throw 0; } } else { QByteArray lang_array = language.toUtf8(); const char *lang = lang_array.constData(); if(!ykp_construct_ndef_text(ndef, ndef_payload, lang, false)) { throw 0; } } qDebug() << "writing the ndef."; if(! yk_write_ndef2(yk, ndef, slot)) { throw 0; } emit configWritten(true, NULL); emit diagnostics(QString("Wrote NDEF for slot %1").arg(slot)); } catch(...) { error = true; } if(ndef && !ykp_free_ndef(ndef)) { error = true; } if (yk && !yk_close_key(yk)) { error = true; } YubiKeyFinder::getInstance()->start(); if(error) { qDebug() << "Writing NDEF failed."; QString errMsg = reportError(); emit configWritten(false, errMsg); } }
void YubiKeyWriter::exportConfig(YubiKeyConfig *ykConfig) { YubiKeyFinder::getInstance()->stop(); YK_KEY *yk = 0; YK_STATUS *ykst = YubiKeyFinder::getInstance()->status(); YKP_CONFIG *cfg = ykp_alloc(); bool error = false; qDebug() << "-------------------------"; qDebug() << "Starting write config"; qDebug() << "-------------------------"; try { if (!(yk = yk_open_first_key())) { throw 0; } ykp_configure_version(cfg, ykst); qDebug() << "writer:configuration slot:" << ykConfig->configSlot(); bool useAccessCode; unsigned char accessCode[MAX_SIZE]; if(!assembleConfig(ykConfig, cfg, &useAccessCode, accessCode)) { throw 0; } m_filename = QFileDialog::getSaveFileName(NULL, tr("Export File"), m_filename, tr("Yubico cfg format (*.ycfg)"), NULL); char data[1024]; int len = ykp_export_config(cfg, data, 1024, YKP_FORMAT_YCFG); if(!len) { throw 0; } QFile file(m_filename); if(!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { throw 0; } if(!file.write(data, len)) { throw 0; } file.close(); QSettings settings; settings.setValue(SG_EXPORT_FILENAME, m_filename); emit configWritten(true, NULL); emit diagnostics(QString("Exported config to file %1").arg(m_filename)); } catch(...) { error = true; } if (cfg) { ykp_free_config(cfg); } if (yk && !yk_close_key(yk)) { error = true; } YubiKeyFinder::getInstance()->start(); if(error) { qDebug() << "Config not exported"; QString errMsg = reportError(); emit configWritten(false, errMsg); } }
void YubiKeyWriter::writeConfig(YubiKeyConfig *ykConfig) { YubiKeyFinder::getInstance()->stop(); YK_KEY *yk = 0; YK_STATUS *ykst = YubiKeyFinder::getInstance()->status(); YKP_CONFIG *cfg = ykp_alloc(); bool error = false; qDebug() << "-------------------------"; qDebug() << "Starting write config"; qDebug() << "-------------------------"; try { if (!(yk = yk_open_first_key())) { throw 0; } else if (!yk_get_status(yk, ykst)) { throw 0; } ykp_configure_version(cfg, ykst); qDebug() << "writer:configuration slot:" << ykConfig->configSlot(); bool useAccessCode; unsigned char accessCode[MAX_SIZE]; if(!assembleConfig(ykConfig, cfg, &useAccessCode, accessCode)) { throw 0; } //Log configuration... qDebug() << "-------------------------"; qDebug() << "Config data to be written to key configuration..."; char conf_buf[1024]; ykp_export_config(cfg, conf_buf, 1024, YKP_FORMAT_LEGACY); qDebug() << conf_buf; qDebug() << "-------------------------"; // Write configuration... if (!yk_write_command(yk, ykp_core_config(cfg), ykp_command(cfg), useAccessCode ? accessCode : NULL)) { qDebug() << "Failure"; throw 0; } qDebug() << "Success... config written"; emit diagnostics(QString("Successfully wrote config to slot %1").arg(ykp_config_num(cfg))); YubiKeyLogger::logConfig(ykConfig); emit configWritten(true, NULL); } catch(...) { error = true; } if (cfg) { ykp_free_config(cfg); } if (yk && !yk_close_key(yk)) { error = true; } YubiKeyFinder::getInstance()->start(); if(error) { qDebug() << "Config not written"; QString errMsg = reportError(); emit configWritten(false, errMsg); } qDebug() << "-------------------------"; qDebug() << "Stopping write config"; qDebug() << "-------------------------"; }
int main(int argc, char **argv) { YK_KEY *yk = 0; bool error = true; int exit_code = 0; /* Options */ bool verbose = false; bool may_block = true; char *otp_fmt_raw = "%%0%uu\n"; char otp_fmt_str[6]; int slot = 1; int digits = 6; // default to 6 digit OTP output int step = 30; // defaultto 30 second step unsigned int result; ykp_errno = 0; yk_errno = 0; if (! parse_args(argc, argv, &slot, &digits, &step, &verbose, &may_block, &exit_code)) goto err; if (!yk_init()) { exit_code = 1; goto err; } if (!(yk = yk_open_first_key())) { exit_code = 1; goto err; } if (! check_firmware(yk, verbose)) { exit_code = 1; goto err; } if (! totp_challenge(yk, slot, digits, step, may_block, verbose, &result)) { exit_code = 1; goto err; } sprintf(otp_fmt_str, otp_fmt_raw, digits); // create a print mask to zero padding to the right number of digits printf(otp_fmt_str, result); exit_code = 0; error = false; err: if (error || exit_code != 0) { report_yk_error(); } if (yk && !yk_close_key(yk)) { report_yk_error(); exit_code = 2; } if (!yk_release()) { report_yk_error(); exit_code = 2; } exit(exit_code); }
int main(int argc, char **argv) { YK_KEY *yk = 0; bool error = true; int exit_code = 0; /* Options */ bool serial_dec = false; bool serial_modhex = false; bool serial_hex = false; bool version = false; bool touch_level = false; bool pgm_seq = false; bool slot1 = false; bool slot2 = false; bool vid = false; bool pid = false; bool quiet = false; yk_errno = 0; if (! parse_args(argc, argv, &serial_dec, &serial_modhex, &serial_hex, &version, &touch_level, &pgm_seq, &quiet, &slot1, &slot2, &vid, &pid, &exit_code)) exit(exit_code); if (!yk_init()) { exit_code = 1; goto err; } if (!(yk = yk_open_first_key())) { exit_code = 1; goto err; } if(serial_dec || serial_modhex || serial_hex) { unsigned int serial; int ret = yk_get_serial(yk, 1, 0, &serial); if(!ret) { exit_code = 1; goto err; } if(serial_dec) { if(!quiet) printf("serial: "); printf("%d\n", serial); } if(serial_modhex || serial_hex) { char buf[64]; char hex_serial[64]; char modhex_serial[64]; char *ptr = buf; int chars = snprintf(buf + 1, 63, "%x", serial); if(chars % 2 == 1) { buf[0] = '0'; } else { ptr += 1; } if(serial_hex) { if(!quiet) printf("serial_hex: "); printf("%s\n", ptr); } if(serial_modhex) { yubikey_hex_decode(hex_serial, ptr, strlen(ptr)); yubikey_modhex_encode(modhex_serial, hex_serial, strlen(hex_serial)); if(!quiet) printf("serial_modhex: "); printf("%s\n", modhex_serial); } } } if(version || touch_level || pgm_seq || slot1 || slot2) { YK_STATUS *st = ykds_alloc(); if(!yk_get_status(yk, st)) { ykds_free(st); exit_code = 1; goto err; } if(version) { if(!quiet) printf("version: "); printf("%d.%d.%d\n", ykds_version_major(st), ykds_version_minor(st), ykds_version_build(st)); } if(touch_level) { if(!quiet) printf("touch_level: "); printf("%d\n", ykds_touch_level(st)); } if(pgm_seq) { if(!quiet) printf("programming_sequence: "); printf("%d\n", ykds_pgm_seq(st)); } if(slot1) { if(!quiet) printf("slot1_status: "); printf("%d\n", (ykds_touch_level(st) & CONFIG1_VALID) == CONFIG1_VALID); } if(slot2) { if(!quiet) printf("slot2_status: "); printf("%d\n", (ykds_touch_level(st) & CONFIG2_VALID) == CONFIG2_VALID); } ykds_free(st); } if(vid || pid) { int vendor_id, product_id; if(!yk_get_key_vid_pid(yk, &vendor_id, &product_id)) { exit_code = 1; goto err; } if(vid) { if(!quiet) printf("vendor_id: "); printf("%x\n", vendor_id); } if(pid) { if(!quiet) printf("product_id: "); printf("%x\n", product_id); } } exit_code = 0; error = false; err: if (error || exit_code != 0) { report_yk_error(); } if (yk && !yk_close_key(yk)) { report_yk_error(); exit_code = 2; } if (!yk_release()) { report_yk_error(); exit_code = 2; } exit(exit_code); }
int main(int argc, char** argv) { char showmessage = 1; if((argc == 2) && (strcmp(argv[1], "-y") == 0)) showmessage = 0; if(showmessage == 1) { puts("--------------------------------------------"); puts("Hi! You're going to crack the access code of"); puts("a Yubikey. As soon as the appropriate code "); puts("is found, the AES key will be set to zeros."); puts("Brute forcing the code can take a very long "); puts("time, and with long I mean like more than a "); puts("year."); puts("(By the way you can bypass this message by "); puts("passing the -y option to the program.) "); puts("--------------------------------------------"); puts("Type \"start\" to continue."); char acknowledge[256]; fgets(acknowledge, 256, stdin); if(strcmp(acknowledge, "start\n") != 0) { puts("Quitting."); return EXIT_SUCCESS; } } yk = 0; unsigned char access_code[6]; const char* aeshash="00000000000000000000000000000000"; YKP_CONFIG *cfg = ykp_create_config(); YK_STATUS *st = ykds_alloc(); if(!yk_init()) { fputs("Failed to init Yubikey.\n", stderr); return EXIT_FAILURE; } if(!(yk = yk_open_first_key())) { fputs("No Yubikey found.\n", stderr); return EXIT_FAILURE; } if(!yk_get_status(yk,st)) { fputs("Failed to get status of the Yubikey.\n", stderr); return EXIT_FAILURE; } printf("Found Yubikey. Version: %d.%d.%d Touch level: %d\n", ykds_version_major(st), ykds_version_minor(st), ykds_version_build(st), ykds_touch_level(st)); if(!ykp_configure_for(cfg, 1, st)) { printf("Can't set configuration to 1.\n"); return EXIT_FAILURE; } if(ykp_AES_key_from_hex(cfg, aeshash)) { fputs("Bad AES key. WTF did you do to my source?", stderr); return EXIT_FAILURE; } coreconfig = ykp_core_config(cfg); coreconfignum = ykp_config_num(cfg); bruteforce(access_code, 5); if(st) free(st); if(!yk_close_key(yk)) { fputs("Can't close Yubikey! What the hell are you doing over there?", stderr); return EXIT_FAILURE; } if(!yk_release()) { fputs("Can't release Yubikey.", stderr); return EXIT_FAILURE; } if(cfg) ykp_free_config(cfg); return EXIT_SUCCESS; }
int main(int argc, char **argv) { YK_KEY *yk = 0; bool error = true; int exit_code = 0; /* Options */ bool serial_dec = false; bool serial_modhex = false; bool serial_hex = false; bool version = false; bool touch_level = false; bool pgm_seq = false; bool quiet = false; yk_errno = 0; if (! parse_args(argc, argv, &serial_dec, &serial_modhex, &serial_hex, &version, &touch_level, &pgm_seq, &quiet, &exit_code)) exit(exit_code); if (!yk_init()) { exit_code = 1; goto err; } if (!(yk = yk_open_first_key())) { exit_code = 1; goto err; } if(serial_dec || serial_modhex || serial_hex) { unsigned int serial; int ret = yk_get_serial(yk, 1, 0, &serial); if(!ret) { exit_code = 1; goto err; } if(serial_dec) { if(!quiet) printf("serial: "); printf("%d\n", serial); } if(serial_hex) { if(!quiet) printf("serial_hex: "); printf("%x\n", serial); } if(serial_modhex) { char buf[64]; char hex_serial[64]; char modhex_serial[64]; snprintf(buf, 64, "%x", serial); yubikey_hex_decode(hex_serial, buf, strlen(buf)); yubikey_modhex_encode(modhex_serial, hex_serial, strlen(hex_serial)); if(!quiet) printf("serial_modhex: "); printf("%s\n", modhex_serial); } } if(version || touch_level || pgm_seq) { YK_STATUS *st = ykds_alloc(); if(!yk_get_status(yk, st)) { ykds_free(st); exit_code = 1; goto err; } if(version) { if(!quiet) printf("version: "); printf("%d.%d.%d\n", ykds_version_major(st), ykds_version_minor(st), ykds_version_build(st)); } if(touch_level) { if(!quiet) printf("touch_level: "); printf("%d\n", ykds_touch_level(st)); } if(pgm_seq) { if(!quiet) printf("programming_sequence: "); printf("%d\n", ykds_pgm_seq(st)); } ykds_free(st); } exit_code = 0; error = false; err: if (error || exit_code != 0) { report_yk_error(); } if (yk && !yk_close_key(yk)) { report_yk_error(); exit_code = 2; } if (!yk_release()) { report_yk_error(); exit_code = 2; } exit(exit_code); }
int main(int argc, char **argv) { unsigned int version = 0, help = 0; char challenge_old[CHALLENGELEN + 1], challenge_new[CHALLENGELEN + 1], response_old[RESPONSELEN], response_new[RESPONSELEN], passphrase_old[PASSPHRASELEN + 1], passphrase_new[PASSPHRASELEN + 1]; const char * tmp; char challengefilename[sizeof(CHALLENGEDIR) + 11 /* "/challenge-" */ + 10 /* unsigned int in char */ + 1], challengefiletmpname[sizeof(CHALLENGEDIR) + 11 /* "/challenge-" */ + 10 /* unsigned int in char */ + 7 /* -XXXXXX */ + 1]; int challengefile = 0, challengefiletmp = 0; struct timeval tv; int i; size_t len; int8_t rc = EXIT_FAILURE; /* cryptsetup */ const char * device_name; int8_t luks_slot = -1; struct crypt_device *cryptdevice; crypt_status_info cryptstatus; crypt_keyslot_info cryptkeyslot; char * passphrase = NULL; /* keyutils */ key_serial_t key; void * payload = NULL; char * second_factor = NULL, * new_2nd_factor = NULL, * new_2nd_factor_verify = NULL; /* yubikey */ YK_KEY * yk; uint8_t yk_slot = SLOT_CHAL_HMAC2; unsigned int serial = 0; /* iniparser */ dictionary * ini; char section_ykslot[10 /* unsigned int in char */ + 1 + sizeof(CONFYKSLOT) + 1]; char section_luksslot[10 + 1 + sizeof(CONFLUKSSLOT) + 1]; /* get command line options */ while ((i = getopt_long(argc, argv, optstring, options_long, NULL)) != -1) switch (i) { case 'h': help++; break; case 'n': case 'N': if (new_2nd_factor != NULL) { fprintf(stderr, "We already have a new second factor. Did you specify it twice?\n"); goto out10; } if (optarg == NULL) { /* N */ if ((new_2nd_factor = ask_secret("new second factor")) == NULL) goto out10; if ((new_2nd_factor_verify = ask_secret("new second factor for verification")) == NULL) goto out10; if (strcmp(new_2nd_factor, new_2nd_factor_verify) != 0) { fprintf(stderr, "Verification failed, given strings do not match.\n"); goto out10; } } else { /* n */ new_2nd_factor = strdup(optarg); memset(optarg, '*', strlen(optarg)); } break; case 's': case 'S': if (second_factor != NULL) { fprintf(stderr, "We already have a second factor. Did you specify it twice?\n"); goto out10; } if (optarg == NULL) { /* S */ second_factor = ask_secret("current second factor"); } else { /* s */ second_factor = strdup(optarg); memset(optarg, '*', strlen(optarg)); } break; case 'V': version++; break; } if (version > 0) printf("%s: %s v%s (compiled: " __DATE__ ", " __TIME__ ")\n", argv[0], PROGNAME, VERSION); if (help > 0) fprintf(stderr, "usage: %s [-h|--help] [-n|--new-2nd-factor <new-2nd-factor>] [-N|--ask-new-2nd-factor]\n" " [-s|--2nd-factor <2nd-factor>] [-S|--ask-2nd-factor] [-V|--version]\n", argv[0]); if (version > 0 || help > 0) return EXIT_SUCCESS; /* initialize random seed */ gettimeofday(&tv, NULL); srand(tv.tv_usec * tv.tv_sec); /* initialize static buffers */ memset(challenge_old, 0, CHALLENGELEN + 1); memset(challenge_new, 0, CHALLENGELEN + 1); memset(response_old, 0, RESPONSELEN); memset(response_new, 0, RESPONSELEN); memset(passphrase_old, 0, PASSPHRASELEN + 1); memset(passphrase_new, 0, PASSPHRASELEN + 1); if ((ini = iniparser_load(CONFIGFILE)) == NULL) { fprintf(stderr, "Could not parse configuration file.\n"); goto out10; } if ((device_name = iniparser_getstring(ini, "general:" CONFDEVNAME, NULL)) == NULL) { /* read from crypttab? */ /* get device from currently open devices? */ fprintf(stderr, "Could not read LUKS device from configuration file.\n"); goto out20; } /* init and open first Yubikey */ if (yk_init() == 0) { perror("yk_init() failed"); goto out20; } if ((yk = yk_open_first_key()) == NULL) { fprintf(stderr, "No Yubikey available.\n"); goto out30; } /* read the serial number from key */ if (yk_get_serial(yk, 0, 0, &serial) == 0) { perror("yk_get_serial() failed"); goto out40; } /* get the yk slot */ sprintf(section_ykslot, "%d:" CONFYKSLOT, serial); yk_slot = iniparser_getint(ini, "general:" CONFYKSLOT, yk_slot); yk_slot = iniparser_getint(ini, section_ykslot, yk_slot); switch (yk_slot) { case 1: case SLOT_CHAL_HMAC1: yk_slot = SLOT_CHAL_HMAC1; break; case 2: case SLOT_CHAL_HMAC2: default: yk_slot = SLOT_CHAL_HMAC2; break; } /* get the luks slot */ sprintf(section_luksslot, "%d:" CONFLUKSSLOT, serial); luks_slot = iniparser_getint(ini, section_luksslot, luks_slot); if (luks_slot < 0) { fprintf(stderr, "Please set LUKS key slot for Yubikey with serial %d!\n" "Add something like this to " CONFIGFILE ":\n\n" "[%d]\nluks slot = 1\n", serial, serial); goto out40; } if (second_factor == NULL) { /* get second factor from key store */ if ((key = request_key("user", "ykfde-2f", NULL, 0)) < 0) fprintf(stderr, "Failed requesting key. That's ok if you do not use\n" "second factor. Give it manually if required.\n"); if (key > -1) { /* if we have a key id we have a key - so this should succeed */ if (keyctl_read_alloc(key, &payload) < 0) { perror("Failed reading payload from key"); goto out40; } second_factor = payload; } else second_factor = strdup(""); } /* warn when second factor is not enabled in config */ if ((*second_factor != 0 || new_2nd_factor != NULL) && iniparser_getboolean(ini, "general:" CONF2NDFACTOR, 0) == 0) fprintf(stderr, "Warning: Processing second factor, but not enabled in config!\n"); /* get random number and limit to printable ASCII character (32 to 126) */ for(i = 0; i < CHALLENGELEN; i++) challenge_new[i] = (rand() % (126 - 32)) + 32; /* these are the filenames for challenge * we need this for reading and writing */ sprintf(challengefilename, CHALLENGEDIR "/challenge-%d", serial); sprintf(challengefiletmpname, CHALLENGEDIR "/challenge-%d-XXXXXX", serial); /* write new challenge to file */ if ((challengefiletmp = mkstemp(challengefiletmpname)) < 0) { fprintf(stderr, "Could not open file %s for writing.\n", challengefiletmpname); goto out40; } if (write(challengefiletmp, challenge_new, CHALLENGELEN) < 0) { fprintf(stderr, "Failed to write challenge to file.\n"); goto out50; } challengefiletmp = close(challengefiletmp); /* now that the new challenge has been written to file... * add second factor to new challenge */ tmp = new_2nd_factor ? new_2nd_factor : second_factor; len = strlen(tmp); memcpy(challenge_new, tmp, len < MAX2FLEN ? len : MAX2FLEN); /* do challenge/response and encode to hex */ if (yk_challenge_response(yk, yk_slot, true, CHALLENGELEN, (unsigned char *) challenge_new, RESPONSELEN, (unsigned char *) response_new) == 0) { perror("yk_challenge_response() failed"); goto out50; } yubikey_hex_encode((char *) passphrase_new, (char *) response_new, SHA1_DIGEST_SIZE); /* get status of crypt device * We expect this to be active (or busy). It is the actual root device, no? */ cryptstatus = crypt_status(cryptdevice, device_name); if (cryptstatus != CRYPT_ACTIVE && cryptstatus != CRYPT_BUSY) { fprintf(stderr, "Device %s is invalid or inactive.\n", device_name); goto out50; } /* initialize crypt device */ if (crypt_init_by_name(&cryptdevice, device_name) < 0) { fprintf(stderr, "Device %s failed to initialize.\n", device_name); goto out60; } cryptkeyslot = crypt_keyslot_status(cryptdevice, luks_slot); if (cryptkeyslot == CRYPT_SLOT_INVALID) { fprintf(stderr, "Key slot %d is invalid.\n", luks_slot); goto out60; } else if (cryptkeyslot == CRYPT_SLOT_ACTIVE || cryptkeyslot == CRYPT_SLOT_ACTIVE_LAST) { /* read challenge from file */ if ((challengefile = open(challengefilename, O_RDONLY)) < 0) { perror("Failed opening challenge file for reading"); goto out60; } if (read(challengefile, challenge_old, CHALLENGELEN) < 0) { perror("Failed reading challenge from file"); goto out60; } challengefile = close(challengefile); /* finished reading challenge */ /* copy the second factor */ len = strlen(second_factor); memcpy(challenge_old, second_factor, len < MAX2FLEN ? len : MAX2FLEN); /* do challenge/response and encode to hex */ if (yk_challenge_response(yk, yk_slot, true, CHALLENGELEN, (unsigned char *) challenge_old, RESPONSELEN, (unsigned char *) response_old) == 0) { perror("yk_challenge_response() failed"); goto out60; } yubikey_hex_encode((char *) passphrase_old, (char *) response_old, SHA1_DIGEST_SIZE); if (crypt_keyslot_change_by_passphrase(cryptdevice, luks_slot, luks_slot, passphrase_old, PASSPHRASELEN, passphrase_new, PASSPHRASELEN) < 0) { fprintf(stderr, "Could not update passphrase for key slot %d.\n", luks_slot); goto out60; } if (unlink(challengefilename) < 0) { fprintf(stderr, "Failed to delete old challenge file.\n"); goto out60; } } else { /* ck == CRYPT_SLOT_INACTIVE */ if ((passphrase = ask_secret("existing LUKS passphrase")) == NULL) goto out60; if (crypt_keyslot_add_by_passphrase(cryptdevice, luks_slot, passphrase, strlen(passphrase), passphrase_new, PASSPHRASELEN) < 0) { fprintf(stderr, "Could not add passphrase for key slot %d.\n", luks_slot); goto out60; } } if (rename(challengefiletmpname, challengefilename) < 0) { fprintf(stderr, "Failed to rename new challenge file.\n"); goto out60; } rc = EXIT_SUCCESS; out60: /* free crypt context */ crypt_free(cryptdevice); out50: /* close the challenge file */ if (challengefile) close(challengefile); if (challengefiletmp) close(challengefiletmp); if (access(challengefiletmpname, F_OK) == 0) unlink(challengefiletmpname); out40: /* close Yubikey */ if (yk_close_key(yk) == 0) perror("yk_close_key() failed"); out30: /* release Yubikey */ if (yk_release() == 0) perror("yk_release() failed"); out20: /* free iniparser dictionary */ iniparser_freedict(ini); out10: /* wipe response (cleartext password!) from memory */ /* This is statically allocated and always save to wipe! */ memset(challenge_old, 0, CHALLENGELEN + 1); memset(challenge_new, 0, CHALLENGELEN + 1); memset(response_old, 0, RESPONSELEN); memset(response_new, 0, RESPONSELEN); memset(passphrase_old, 0, PASSPHRASELEN + 1); memset(passphrase_new, 0, PASSPHRASELEN + 1); free(passphrase); free(new_2nd_factor_verify); free(new_2nd_factor); free(second_factor); return rc; }
/// /// Set the ChallengeResponse key on specified slot /// __declspec(dllexport) int SetChallengeResponse(uint32_t slot, const unsigned char* secret, uint32_t keysize, BOOL userpress, unsigned char* access_code) { YK_CONFIG config; uint8_t command; YK_KEY* key; int result = 0; memset(&config, 0, sizeof(config)); if (slot == 1) { command = SLOT_CONFIG; } else if (slot == 2) { command = SLOT_CONFIG2; } else { // invalid slot return ERROR_INVALID_SLOT; } if (keysize == KEY_SIZE_OATH) { // put first 16 in key and last 4 in uid memcpy(config.key, secret, KEY_SIZE); memcpy(config.uid, secret + KEY_SIZE, keysize - KEY_SIZE); config.tktFlags |= TKTFLAG_CHAL_RESP; config.cfgFlags |= CFGFLAG_CHAL_HMAC; config.cfgFlags |= CFGFLAG_HMAC_LT64; } else if (keysize == KEY_SIZE) { memcpy(config.key, secret, KEY_SIZE); config.tktFlags |= TKTFLAG_CHAL_RESP; config.cfgFlags |= CFGFLAG_CHAL_YUBICO; } else { // invalid key size return ERROR_INVALID_KEYSIZE; } if (userpress) { config.cfgFlags |= CFGFLAG_CHAL_BTN_TRIG; } key = yk_open_first_key(); if (key == NULL) { // cannot open _lastError = yk_errno; return ERROR_CANNOT_OPEN_KEY; } if (!yk_write_command(key, &config, command, access_code ? access_code : NULL)) { result = ERROR_WRITING_SLOT; _lastError = yk_errno; } yk_close_key(key); return result; }
/* 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; }
int main(int argc, char **argv) { char challenge_old[CHALLENGELEN + 1], challenge_new[CHALLENGELEN + 1], repose_old[RESPONSELEN], repose_new[RESPONSELEN], passphrase_old[PASSPHRASELEN + 1], passphrase_new[PASSPHRASELEN + 1]; char challengefilename[sizeof(CHALLENGEDIR) + 11 /* "/challenge-" */ + 10 /* unsigned int in char */ + 1], challengefiletmpname[sizeof(CHALLENGEDIR) + 11 /* "/challenge-" */ + 10 /* unsigned int in char */ + 7 /* -XXXXXX */ + 1]; int challengefile = 0, challengefiletmp = 0; struct timeval tv; int i; int8_t rc = EXIT_FAILURE; /* cryptsetup */ char * device_name; int8_t luks_slot = -1; struct crypt_device *cd; crypt_status_info cs; crypt_keyslot_info ck; /* yubikey */ YK_KEY * yk; uint8_t yk_slot = SLOT_CHAL_HMAC2; unsigned int serial = 0; /* iniparser */ dictionary * ini; char section_ykslot[10 /* unsigned int in char */ + 1 + sizeof(CONFYKSLOT) + 1]; char section_luksslot[10 /* unsigned int in char */ + 1 + sizeof(CONFLUKSSLOT) + 1]; /* initialize random seed */ gettimeofday(&tv, NULL); srand(tv.tv_usec * tv.tv_sec); memset(challenge_old, 0, CHALLENGELEN + 1); memset(challenge_new, 0, CHALLENGELEN + 1); memset(repose_old, 0, RESPONSELEN); memset(repose_new, 0, RESPONSELEN); memset(passphrase_old, 0, PASSPHRASELEN + 1); memset(passphrase_new, 0, PASSPHRASELEN + 1); if ((ini = iniparser_load(CONFIGFILE)) == NULL) { rc = EXIT_FAILURE; fprintf(stderr, "Could not parse configuration file.\n"); goto out10; } if ((device_name = iniparser_getstring(ini, "general:" CONFDEVNAME, NULL)) == NULL) { rc = EXIT_FAILURE; /* read from crypttab? */ /* get device from currently open devices? */ fprintf(stderr, "Could not read LUKS device from configuration file.\n"); goto out20; } /* init and open first Yubikey */ if ((rc = yk_init()) < 0) { perror("yk_init() failed"); goto out20; } if ((yk = yk_open_first_key()) == NULL) { rc = EXIT_FAILURE; perror("yk_open_first_key() failed"); goto out30; } /* read the serial number from key */ if ((rc = yk_get_serial(yk, 0, 0, &serial)) < 0) { perror("yk_get_serial() failed"); goto out40; } /* get the yk slot */ sprintf(section_ykslot, "%d:" CONFYKSLOT, serial); yk_slot = iniparser_getint(ini, "general:" CONFYKSLOT, yk_slot); yk_slot = iniparser_getint(ini, section_ykslot, yk_slot); switch (yk_slot) { case 1: case SLOT_CHAL_HMAC1: yk_slot = SLOT_CHAL_HMAC1; break; case 2: case SLOT_CHAL_HMAC2: default: yk_slot = SLOT_CHAL_HMAC2; break; } /* get the luks slot */ sprintf(section_luksslot, "%d:" CONFLUKSSLOT, serial); luks_slot = iniparser_getint(ini, section_luksslot, luks_slot); if (luks_slot < 0) { rc = EXIT_FAILURE; fprintf(stderr, "Please set LUKS key slot for Yubikey with serial %d!\n", serial); printf("Add something like this to " CONFIGFILE ":\n\n[%d]\nluks slot = 1\n", serial); goto out40; } /* get random number and limit to printable ASCII character (32 to 126) */ for(i = 0; i < CHALLENGELEN; i++) challenge_new[i] = (rand() % (126 - 32)) + 32; /* do challenge/response and encode to hex */ if ((rc = yk_challenge_response(yk, yk_slot, true, CHALLENGELEN, (unsigned char *)challenge_new, RESPONSELEN, (unsigned char *)repose_new)) < 0) { perror("yk_challenge_response() failed"); goto out40; } yubikey_hex_encode((char *)passphrase_new, (char *)repose_new, 20); /* initialize crypt device */ if ((rc = crypt_init_by_name(&cd, device_name)) < 0) { fprintf(stderr, "Device %s failed to initialize.\n", device_name); goto out40; } /* these are the filenames for challenge * we need this for reading and writing */ sprintf(challengefilename, CHALLENGEDIR "/challenge-%d", serial); sprintf(challengefiletmpname, CHALLENGEDIR "/challenge-%d-XXXXXX", serial); /* write new challenge to file */ if ((rc = challengefiletmp = mkstemp(challengefiletmpname)) < 0) { fprintf(stderr, "Could not open file %s for writing.\n", challengefiletmpname); goto out50; } if ((rc = write(challengefiletmp, challenge_new, CHALLENGELEN)) < 0) { fprintf(stderr, "Failed to write challenge to file.\n"); goto out60; } challengefiletmp = close(challengefiletmp); /* get status of crypt device * We expect this to be active (or busy). It is the actual root device, no? */ cs = crypt_status(cd, device_name); if (cs != CRYPT_ACTIVE && cs != CRYPT_BUSY) { rc = EXIT_FAILURE; fprintf(stderr, "Device %s is invalid or inactive.\n", device_name); goto out60; } ck = crypt_keyslot_status(cd, luks_slot); if (ck == CRYPT_SLOT_INVALID) { rc = EXIT_FAILURE; fprintf(stderr, "Key slot %d is invalid.\n", luks_slot); goto out60; } else if (ck == CRYPT_SLOT_ACTIVE || ck == CRYPT_SLOT_ACTIVE_LAST) { /* read challenge from file */ if ((rc = challengefile = open(challengefilename, O_RDONLY)) < 0) { perror("Failed opening challenge file for reading"); goto out60; } if ((rc = read(challengefile, challenge_old, CHALLENGELEN)) < 0) { perror("Failed reading challenge from file"); goto out60; } challengefile = close(challengefile); /* finished reading challenge */ /* do challenge/response and encode to hex */ if ((rc = yk_challenge_response(yk, yk_slot, true, CHALLENGELEN, (unsigned char *)challenge_old, RESPONSELEN, (unsigned char *)repose_old)) < 0) { perror("yk_challenge_response() failed"); goto out60; } yubikey_hex_encode((char *)passphrase_old, (char *)repose_old, 20); if ((rc = crypt_keyslot_change_by_passphrase(cd, luks_slot, luks_slot, passphrase_old, PASSPHRASELEN, passphrase_new, PASSPHRASELEN)) < 0) { fprintf(stderr, "Could not update passphrase for key slot %d.\n", luks_slot); goto out60; } if ((rc = unlink(challengefilename)) < 0) { fprintf(stderr, "Failed to delete old challenge file.\n"); goto out60; } } else { /* ck == CRYPT_SLOT_INACTIVE */ if ((rc = crypt_keyslot_add_by_passphrase(cd, luks_slot, NULL, 0, passphrase_new, PASSPHRASELEN)) < 0) { fprintf(stderr, "Could add passphrase for key slot %d.\n", luks_slot); goto out60; } } if ((rc = rename(challengefiletmpname, challengefilename)) < 0) { fprintf(stderr, "Failed to rename new challenge file.\n"); goto out60; } rc = EXIT_SUCCESS; out60: /* close the challenge file */ if (challengefile) close(challengefile); if (challengefiletmp) close(challengefiletmp); if (access(challengefiletmpname, F_OK) == 0 ) unlink(challengefiletmpname); out50: /* free crypt context */ crypt_free(cd); out40: /* close Yubikey */ if (!yk_close_key(yk)) perror("yk_close_key() failed"); out30: /* release Yubikey */ if (!yk_release()) perror("yk_release() failed"); out20: /* free iniparser dictionary */ iniparser_freedict(ini); out10: /* wipe response (cleartext password!) from memory */ /* This is statically allocated and always save to wipe! */ memset(challenge_old, 0, CHALLENGELEN + 1); memset(challenge_new, 0, CHALLENGELEN + 1); memset(repose_old, 0, RESPONSELEN); memset(repose_new, 0, RESPONSELEN); memset(passphrase_old, 0, PASSPHRASELEN + 1); memset(passphrase_new, 0, PASSPHRASELEN + 1); return rc; }