Exemplo n.º 1
0
///
/// 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;
}
Exemplo n.º 2
0
int
main(int argc, char **argv)
{
  YK_KEY *yk = NULL;
  bool error = true;
  int exit_code = 0;

  /* Options */
  bool verbose = false;
  char *action = ACTION_ADD_HMAC_CHALRESP;
  int slot = 1;

  ykp_errno = 0;
  yk_errno = 0;

  if (! parse_args(argc, argv,
		   &slot, &verbose,
		   &action,
		   &exit_code))
    goto err;

  exit_code = 1;

  if (! strcmp(action, ACTION_ADD_HMAC_CHALRESP)) {
    /*
     * Set up challenge-response login authentication
     */
    if (! init_yubikey (&yk))
      goto err;

    if (! check_firmware_version(yk, verbose, false))
      goto err;

    if (! do_add_hmac_chalresp (yk, slot, verbose, NULL, &exit_code))
      goto err;
  } else {
    fprintf (stderr, "Unknown action '%s'\n", action);
    goto err;
  }

  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);
}
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);
    }
}
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);
    }
}
Exemplo n.º 5
0
YK_KEY *yk_open_first_key(void)
{
	YK_KEY *yk = _ykusb_open_device(YUBICO_VID, YUBIKEY_PID);
	int rc = yk_errno;

	if (yk) {
		YK_STATUS st;

		if (!yk_get_status(yk, &st)) {
			rc = yk_errno;
			yk_close_key(yk);
			yk = NULL;
		}
	}
	yk_errno = rc;
	return yk;
}
Exemplo n.º 6
0
///
/// 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;
}
Exemplo n.º 7
0
YK_KEY *yk_open_first_key(void)
{
	int pids[] = {YUBIKEY_PID, NEO_OTP_PID, NEO_OTP_CCID_PID};

	YK_KEY *yk = _ykusb_open_device(YUBICO_VID, pids, sizeof(pids));
	int rc = yk_errno;

	if (yk) {
		YK_STATUS st;

		if (!yk_get_status(yk, &st)) {
			rc = yk_errno;
			yk_close_key(yk);
			yk = NULL;
		}
	}
	yk_errno = rc;
	return yk;
}
Exemplo n.º 8
0
///
/// Get the Info about the first YubiKey
///
__declspec(dllexport) int GetInfo(YK_INFO *info)
{
	int pid;
	YK_KEY* key = yk_open_first_key_with_pid(&pid);
	if (key == NULL)
	{
		_lastError = yk_errno;
		return ERROR_CANNOT_OPEN_KEY;
	}

	yk_get_status(key, &info->status);

	yk_get_serial(key, 0, 0, &info->serial);

	info->pid = pid;

	yk_close_key(key);

	return 0;
}
Exemplo n.º 9
0
YK_KEY *yk_open_key(int index)
{
	int pids[] = {YUBIKEY_PID, NEO_OTP_PID, NEO_OTP_CCID_PID,
		NEO_OTP_U2F_PID, NEO_OTP_U2F_CCID_PID, YK4_OTP_PID,
		YK4_OTP_U2F_PID, YK4_OTP_CCID_PID, YK4_OTP_U2F_CCID_PID,
		PLUS_U2F_OTP_PID};

	YK_KEY *yk = _ykusb_open_device(YUBICO_VID, pids, sizeof(pids) / sizeof(int), index);
	int rc = yk_errno;

	if (yk) {
		YK_STATUS st;

		if (!yk_get_status(yk, &st)) {
			rc = yk_errno;
			yk_close_key(yk);
			yk = NULL;
		}
	}
	yk_errno = rc;
	return yk;
}
Exemplo n.º 10
0
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;
}
Exemplo n.º 11
0
/* 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;
}
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::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() << "-------------------------";
}
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);
    }
}
Exemplo n.º 15
0
static int
do_challenge_response(pam_handle_t *pamh, struct cfg *cfg, const char *username)
{
  char *userfile = NULL, *tmpfile = NULL;
  FILE *f = NULL;
  char buf[CR_RESPONSE_SIZE + 16], response_hex[CR_RESPONSE_SIZE * 2 + 1];
  int ret, fd;

  unsigned int flags = 0;
  unsigned int response_len = 0;
  YK_KEY *yk = NULL;
  CR_STATE state;

  char *errstr = NULL;

  struct passwd *p;
  struct stat st;

  ret = PAM_AUTH_ERR;
  flags |= YK_FLAG_MAYBLOCK;

  if (! init_yubikey(&yk)) {
    D(("Failed initializing YubiKey"));
    goto out;
  }

  if (! check_firmware_version(yk, false, true)) {
    D(("YubiKey does not support Challenge-Response (version 2.2 required)"));
    goto out;
  }


  if (! get_user_challenge_file (yk, cfg->chalresp_path, username, &userfile)) {
    D(("Failed getting user challenge file for user %s", username));
    goto out;
  }

  DBG(("Loading challenge from file %s", userfile));

  p = getpwnam (username);
  if (p == NULL) {
      DBG (("getpwnam: %s", strerror(errno)));
      goto out;
  }

  /* Drop privileges before opening user file. */
  if (drop_privileges(p, pamh) < 0) {
      D (("could not drop privileges"));
      goto out;
  }

  fd = open(userfile, O_RDONLY, 0);
  if (fd < 0) {
      DBG (("Cannot open file: %s (%s)", userfile, strerror(errno)));
      goto out;
  }

  if (fstat(fd, &st) < 0) {
      DBG (("Cannot stat file: %s (%s)", userfile, strerror(errno)));
      close(fd);
      goto out;
  }

  if (!S_ISREG(st.st_mode)) {
      DBG (("%s is not a regular file", userfile));
      close(fd);
      goto out;
  }

  f = fdopen(fd, "r");
  if (f == NULL) {
      DBG (("fdopen: %s", strerror(errno)));
      close(fd);
      goto out;
  }

  if (! load_chalresp_state(f, &state, cfg->debug))
    goto out;

  if (fclose(f) < 0) {
    f = NULL;
    goto out;
  }
  f = NULL;

  if (restore_privileges(pamh) < 0) {
      DBG (("could not restore privileges"));
      goto out;
  }

  if (! challenge_response(yk, state.slot, state.challenge, state.challenge_len,
			   true, flags, false,
			   buf, sizeof(buf), &response_len)) {
    D(("Challenge-response FAILED"));
    goto out;
  }

  /*
   * Check YubiKey response against the expected response
   */

  yubikey_hex_encode(response_hex, buf, response_len);

  if (memcmp(buf, state.response, response_len) == 0) {
    ret = PAM_SUCCESS;
  } else {
    D(("Unexpected C/R response : %s", response_hex));
    goto out;
  }

  DBG(("Got the expected response, generating new challenge (%i bytes).", CR_CHALLENGE_SIZE));

  errstr = "Error generating new challenge, please check syslog or contact your system administrator";
  if (generate_random(state.challenge, sizeof(state.challenge))) {
    D(("Failed generating new challenge!"));
    goto out;
  }

  errstr = "Error communicating with Yubikey, please check syslog or contact your system administrator";
  if (! challenge_response(yk, state.slot, state.challenge, CR_CHALLENGE_SIZE,
			   true, flags, false,
			   buf, sizeof(buf), &response_len)) {
    D(("Second challenge-response FAILED"));
    goto out;
  }

  /* There is a bug that makes the YubiKey 2.2 send the same response for all challenges
     unless HMAC_LT64 is set, check for that here */
  if (memcmp(buf, state.response, response_len) == 0) {
    errstr = "Same response for second challenge, YubiKey should be reconfigured with the option HMAC_LT64";
    goto out;
  }

  /* the yk_* functions leave 'junk' in errno */
  errno = 0;

  /*
   * Write the challenge and response we will expect the next time to the state file.
   */
  if (response_len > sizeof(state.response)) {
    D(("Got too long response ??? (%u/%lu)", response_len, (unsigned long) sizeof(state.response)));
    goto out;
  }
  memcpy (state.response, buf, response_len);
  state.response_len = response_len;

  /* Drop privileges before creating new challenge file. */
  if (drop_privileges(p, pamh) < 0) {
      D (("could not drop privileges"));
      goto out;
  }

  /* Write out the new file */
  tmpfile = malloc(strlen(userfile) + 1 + 4);
  if (! tmpfile)
    goto out;
  strcpy(tmpfile, userfile);
  strcat(tmpfile, ".tmp");

  fd = open(tmpfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
  if (fd < 0) {
      DBG (("Cannot open file: %s (%s)", tmpfile, strerror(errno)));
      goto out;
  }

  f = fdopen(fd, "w");
  if (! f) {
    close(fd);
    goto out;
  }

  errstr = "Error updating Yubikey challenge, please check syslog or contact your system administrator";
  if (! write_chalresp_state (f, &state))
    goto out;
  if (fclose(f) < 0) {
    f = NULL;
    goto out;
  }
  f = NULL;
  if (rename(tmpfile, userfile) < 0) {
    goto out;
  }

  if (restore_privileges(pamh) < 0) {
      DBG (("could not restore privileges"));
      goto out;
  }

  DBG(("Challenge-response success!"));
  errstr = NULL;
  errno = 0;

 out:
  if (yk_errno) {
    if (yk_errno == YK_EUSBERR) {
      syslog(LOG_ERR, "USB error: %s", yk_usb_strerror());
      D(("USB error: %s", yk_usb_strerror()));
    } else {
      syslog(LOG_ERR, "Yubikey core error: %s", yk_strerror(yk_errno));
      D(("Yubikey core error: %s", yk_strerror(yk_errno)));
    }
  }

  if (errstr)
    display_error(pamh, errstr);

  if (errno) {
    syslog(LOG_ERR, "Challenge response failed: %s", strerror(errno));
    D(("Challenge response failed: %s", strerror(errno)));
  }

  if (yk)
    yk_close_key(yk);
  yk_release();

  if (f)
    fclose(f);

  free(userfile);
  free(tmpfile);
  return ret;
}
Exemplo n.º 16
0
int
main(int argc, char **argv)
{
  YK_KEY *yk = NULL;
  bool error = true;
  int exit_code = 0;

  /* Options */
  bool verbose = false;
  char action[ACTION_MAX_LEN];
  char *ptr = action;
  char *output_dir = NULL;
  int slot = 1;
  unsigned int iterations = CR_DEFAULT_ITERATIONS;

  ykp_errno = 0;
  yk_errno = 0;

  strcpy (action, ACTION_ADD_HMAC_CHALRESP);

  if (! parse_args(argc, argv,
		   &slot, &verbose,
		   &ptr, &output_dir,
       &iterations))
    goto err;

  exit_code = 1;

  if (! strncmp(action, ACTION_ADD_HMAC_CHALRESP, ACTION_MAX_LEN)) {
    /*
     * Set up challenge-response login authentication
     */
    if (! init_yubikey (&yk))
      goto err;

    if (! check_firmware_version(yk, verbose, false))
      goto err;    

    if (! do_add_hmac_chalresp (yk, slot, verbose, output_dir, iterations, &exit_code))
      goto err;
  } else {
    fprintf (stderr, "Unknown action '%s'\n", action);
    goto err;
  }

  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);
}
Exemplo n.º 17
0
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);
}
Exemplo n.º 18
0
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);
}
Exemplo n.º 19
0
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;
}
Exemplo n.º 20
0
static int
do_challenge_response(pam_handle_t *pamh, struct cfg *cfg, const char *username)
{
    char *userfile = NULL, *tmpfile = NULL;
    FILE *f = NULL;
    unsigned char buf[CR_RESPONSE_SIZE + 16], response_hex[CR_RESPONSE_SIZE * 2 + 1];
    int ret;

    unsigned int flags = 0;
    unsigned int response_len = 0;
    unsigned int expect_bytes = 0;
    YK_KEY *yk = NULL;
    CR_STATE state;

    int len;
    char *errstr = NULL;

    ret = PAM_AUTH_ERR;
    flags |= YK_FLAG_MAYBLOCK;

    if (! init_yubikey(&yk)) {
        D(("Failed initializing YubiKey"));
        goto out;
    }

    if (! check_firmware_version(yk, false, true)) {
        D(("YubiKey does not support Challenge-Response (version 2.2 required)"));
        goto out;
    }


    if (! get_user_challenge_file (yk, cfg->chalresp_path, username, &userfile)) {
        D(("Failed getting user challenge file for user %s", username));
        goto out;
    }

    DBG(("Loading challenge from file %s", userfile));

    /* XXX should drop root privileges before opening file in user's home directory */
    f = fopen(userfile, "r");

    if (! load_chalresp_state(f, &state))
        goto out;

    if (fclose(f) < 0) {
        f = NULL;
        goto out;
    }

    if (! challenge_response(yk, state.slot, state.challenge, state.challenge_len,
                             true, flags, false,
                             buf, sizeof(buf), &response_len)) {
        D(("Challenge-response FAILED"));
        goto out;
    }

    /*
     * Check YubiKey response against the expected response
     */

    yubikey_hex_encode(response_hex, (char *)buf, response_len);

    if (memcmp(buf, state.response, response_len) == 0) {
        ret = PAM_SUCCESS;
    } else {
        D(("Unexpected C/R response : %s", response_hex));
        goto out;
    }

    DBG(("Got the expected response, generating new challenge (%i bytes).", CR_CHALLENGE_SIZE));

    errstr = "Error generating new challenge, please check syslog or contact your system administrator";
    if (generate_random(state.challenge, sizeof(state.challenge))) {
        D(("Failed generating new challenge!"));
        goto out;
    }

    errstr = "Error communicating with Yubikey, please check syslog or contact your system administrator";
    if (! challenge_response(yk, state.slot, state.challenge, CR_CHALLENGE_SIZE,
                             true, flags, false,
                             buf, sizeof(buf), &response_len)) {
        D(("Second challenge-response FAILED"));
        goto out;
    }

    /* the yk_* functions leave 'junk' in errno */
    errno = 0;

    /*
     * Write the challenge and response we will expect the next time to the state file.
     */
    if (response_len > sizeof(state.response)) {
        D(("Got too long response ??? (%i/%i)", response_len, sizeof(state.response)));
        goto out;
    }
    memcpy (state.response, buf, response_len);
    state.response_len = response_len;

    /* Write out the new file */
    tmpfile = malloc(strlen(userfile) + 1 + 4);
    if (! tmpfile)
        goto out;
    strcpy(tmpfile, userfile);
    strcat(tmpfile, ".tmp");

    f = fopen(tmpfile, "w");
    if (! f)
        goto out;

    errstr = "Error updating Yubikey challenge, please check syslog or contact your system administrator";
    if (! write_chalresp_state (f, &state))
        goto out;
    if (fclose(f) < 0) {
        f = NULL;
        goto out;
    }
    f = NULL;
    if (rename(tmpfile, userfile) < 0) {
        goto out;
    }

    DBG(("Challenge-response success!"));
    errstr = NULL;

out:
    if (yk_errno) {
        if (yk_errno == YK_EUSBERR) {
            syslog(LOG_ERR, "USB error: %s", yk_usb_strerror());
            D(("USB error: %s", yk_usb_strerror()));
        } else {
            syslog(LOG_ERR, "Yubikey core error: %s", yk_strerror(yk_errno));
            D(("Yubikey core error: %s", yk_strerror(yk_errno)));
        }
    }

    if (errstr)
        display_error(pamh, errstr);

    if (errno) {
        syslog(LOG_ERR, "Challenge response failed: %s", strerror(errno));
        D(("Challenge response failed: %s", strerror(errno)));
    }

    if (yk)
        yk_close_key(yk);
    yk_release();

    if (f)
        fclose(f);

    free(userfile);
    free(tmpfile);
    return ret;
}
Exemplo n.º 21
0
///
/// 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;
}
Exemplo n.º 22
0
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);
}
Exemplo n.º 23
0
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;
}