예제 #1
0
/**
 * @param pPswd2check modhex encoded
 */
bool YubikoOtpKeyConfig::checkOtp(const std::string& pPswd2check) {
	BOOST_LOG_NAMED_SCOPE("YubikoOtpKeyConfig::checkPassword");
	yubikey_token_st myToken;
	yubikey_parse(reinterpret_cast<const uint8_t*>(pPswd2check.c_str()),
			this->getSecretKeyArray().data(), &myToken);
	BOOST_LOG_TRIVIAL(debug)<< "Key token:";
	logDebug_token(getToken());
	BOOST_LOG_TRIVIAL(debug)<< "Decrypted token:";
	logDebug_token(myToken);
	if (strncmp(reinterpret_cast<const char*>(&getToken().uid),
			reinterpret_cast<char*>(&myToken.uid), YUBIKEY_UID_SIZE) == 0) {
		BOOST_LOG_TRIVIAL(debug)<< "UID is same.";
		uint16_t myComputedCrc = computeCrc(myToken);
		if(myToken.crc!=myComputedCrc) {
			BOOST_LOG_TRIVIAL(debug)<< "Decrypted CRC is wrong: "
			<< myComputedCrc <<"!=" << myToken.crc;
			return false;
		}
		if(myToken.ctr > getToken().ctr) {
			BOOST_LOG_TRIVIAL(debug)<< "Decrypted counter is bigger than stored value: "
			<< int(myToken.ctr) <<">" << int(getToken().ctr) << " reseting use counter & clock.";
			getToken().use= myToken.use;
			copyAndSaveToken(myToken);
			BOOST_LOG_TRIVIAL(debug)<< "OTP OK (use counter reset)!";
			return true;
		} else {
			if(myToken.ctr < getToken().ctr) {
				BOOST_LOG_TRIVIAL(debug)<< "Decrypted counter is smaller than stored value: "
				<< int(myToken.ctr) <<"<" << int(getToken().ctr) << " returning false.";
				return false;
			}
		}
		BOOST_LOG_TRIVIAL(debug)<< "Counter is "<< int(myToken.ctr)<<".";
		if(myToken.use <= getToken().use) {
			BOOST_LOG_TRIVIAL(debug)<< "Decrypted use counter is wrong: "
			<< int(myToken.use) <<"<=" << int(getToken().use);
			return false;
		}
		UTimestamp myTstmp;
		myTstmp.tstp.tstph=myToken.tstph;
		myTstmp.tstp.tstpl=myToken.tstpl;
		if(myTstmp.tstp_int<=getTimestamp().tstp_int) {
			BOOST_LOG_TRIVIAL(debug)<< "Decrypted timer is smaller than stored value: "
			<< myTstmp.tstp_int <<"<=" << getTimestamp().tstp_int << " returning false.";
			return false;
		} else {
			BOOST_LOG_TRIVIAL(debug)<< "Decrypted timer int value: "
			<< myTstmp.tstp_int <<".";
		}
		copyAndSaveToken(myToken);
		BOOST_LOG_TRIVIAL(debug)<< "OTP OK!";
		return true;
	}
	return false;
}
예제 #2
0
int check_user_token(char *user, char *token, sqlite3 *db)
{
  char *request;
  sqlite3_stmt *ppStmt;
  entry_st entry;
  yubikey_token_st tok;
  int id, rc;

  request = sqlite3_mprintf("SELECT id FROM tokens WHERE user=%Q;", user);

  rc = sqlite3_prepare_v2(db, request, -1,
			  &ppStmt, NULL);
  sqlite3_free(request);
  if(check_error("Error in preparing SELECT", rc, db))
    return CHK_FAIL;

  rc = sqlite3_step(ppStmt);
  if (rc != SQLITE_ROW)
    {
      sqlite3_finalize(ppStmt);
      return CHK_UNKNOWN;
    }
 if (strlen(token) != 32)
   {
     sqlite3_finalize(ppStmt);
     return CHK_FAIL;
   }

  while (rc == SQLITE_ROW)
    {
      id = sqlite3_column_int(ppStmt, 0);
      get_entry_from_id(id, &entry, db);
      yubikey_parse ((uint8_t *) token, entry.aes_bin, &tok);
      rc = check_token(&tok, entry.uid, entry.counter, entry.session);
      if (rc == CHK_OK)
	{
	  rc = update_db(db, id, &tok);
	  sqlite3_finalize(ppStmt);
	  return rc;
	}
      rc = sqlite3_step(ppStmt);
    }
  sqlite3_finalize(ppStmt);
  return CHK_FAIL;
}
예제 #3
0
static void
otp_test1 (void)
{
  yubikey_token_st tok;
  char out[1024];
  uint8_t key[16 + 1];

  /* Test OTP */

  memcpy ((void *) &tok,
	  "\x16\xe1\xe5\xd9\xd3\x99\x10\x04\x45\x20\x07\xe3\x02\x00\x00", 16);
  memcpy (key, "abcdef0123456789", 16);

  yubikey_generate ((void *) &tok, key, out);
  yubikey_parse ((uint8_t *) out, key, &tok);

  assert (memcmp (&tok,
		  "\x16\xe1\xe5\xd9\xd3\x99\x10\x04\x45\x20\x07\xe3\x02\x00\x00",
		  16) == 0);
  printf ("OTP-1 success\n");
}
예제 #4
0
파일: ykparse.c 프로젝트: Yubico/yubico-c
int
main (int argc, char *argv[])
{
    uint8_t buf[128];
    uint8_t key[YUBIKEY_KEY_SIZE];
    char *aeskey, *token;
    yubikey_token_st tok;

    /* Parse command line parameters. */
    if (argc <= 2)
    {
        printf ("Usage: %s <aeskey> <token>\n", argv[0]);
        printf (" AESKEY:\tHex encoded AES-key.\n");
        printf (" TOKEN:\t\tModHex encoded token.\n");
        return EXIT_FAILURE;
    }

    aeskey = argv[1];
    token = argv[2];

    if (strlen (aeskey) != 32)
    {
        printf ("error: Hex encoded AES-key must be 32 characters.\n");
        return EXIT_FAILURE;
    }

    if (strlen (token) > 32)
    {
        printf ("warning: overlong token, ignoring prefix: %.*s\n",
                (int) strlen (token) - 32, token);
        token = token + (strlen (token) - 32);
    }

    if (strlen (token) != 32)
    {
        printf ("error: ModHex encoded token must be 32 characters.\n");
        return EXIT_FAILURE;
    }

    /* Debug. */
    printf ("Input:\n");
    printf ("  token: %s\n", token);

    yubikey_modhex_decode ((char *) key, token, YUBIKEY_KEY_SIZE);

    {
        size_t i;
        printf ("          ");
        for (i = 0; i < YUBIKEY_KEY_SIZE; i++)
            printf ("%02x ", key[i] & 0xFF);
        printf ("\n");
    }

    printf ("  aeskey: %s\n", aeskey);

    yubikey_hex_decode ((char *) key, aeskey, YUBIKEY_KEY_SIZE);

    {
        size_t i;
        printf ("          ");
        for (i = 0; i < YUBIKEY_KEY_SIZE; i++)
            printf ("%02x ", key[i] & 0xFF);
        printf ("\n");
    }

    /* Pack up dynamic password, decrypt it and verify checksum */
    yubikey_parse ((uint8_t *) token, key, &tok);

    printf ("Output:\n");
    {
        size_t i;
        printf ("          ");
        for (i = 0; i < YUBIKEY_BLOCK_SIZE; i++)
            printf ("%02x ", ((uint8_t *) & tok)[i] & 0xFF);
        printf ("\n");
    }

    printf ("\nStruct:\n");
    /* Debug */
    {
        size_t i;
        printf ("  uid: ");
        for (i = 0; i < YUBIKEY_UID_SIZE; i++)
            printf ("%02x ", tok.uid[i] & 0xFF);
        printf ("\n");
    }
    printf ("  counter: %d (0x%04x)\n", tok.ctr, tok.ctr);
    printf ("  timestamp (low): %d (0x%04x)\n", tok.tstpl, tok.tstpl);
    printf ("  timestamp (high): %d (0x%02x)\n", tok.tstph, tok.tstph);
    printf ("  session use: %d (0x%02x)\n", tok.use, tok.use);
    printf ("  random: %d (0x%02x)\n", tok.rnd, tok.rnd);
    printf ("  crc: %d (0x%04x)\n", tok.crc, tok.crc);

    printf ("\nDerived:\n");
    printf ("  cleaned counter: %d (0x%04x)\n",
            yubikey_counter (tok.ctr), yubikey_counter (tok.ctr));
    yubikey_modhex_encode ((char *) buf, (char *) tok.uid, YUBIKEY_UID_SIZE);
    printf ("  modhex uid: %s\n", buf);
    printf ("  triggered by caps lock: %s\n",
            yubikey_capslock (tok.ctr) ? "yes" : "no");
    printf ("  crc: %04X\n", yubikey_crc16 ((void *) &tok, YUBIKEY_KEY_SIZE));

    printf ("  crc check: ");
    if (yubikey_crc_ok_p ((uint8_t *) & tok))
    {
        printf ("ok\n");
        return EXIT_SUCCESS;
    }

    printf ("fail\n");
    return EXIT_FAILURE;
}
예제 #5
0
/** Decrypt a Yubikey OTP AES block
 *
 * @param inst Module configuration.
 * @param passcode string to decrypt.
 * @return one of the RLM_RCODE_* constants.
 */
rlm_rcode_t rlm_yubikey_decrypt(rlm_yubikey_t *inst, REQUEST *request, char const *passcode)
{
	uint32_t counter;
	yubikey_token_st token;

	DICT_ATTR const *da;

	char private_id[(YUBIKEY_UID_SIZE * 2) + 1];
	VALUE_PAIR *key, *vp;

	da = dict_attrbyname("Yubikey-Key");
	if (!da) {
		REDEBUG("Dictionary missing entry for 'Yubikey-Key'");
		return RLM_MODULE_FAIL;
	}

	key = pairfind(request->config_items, da->attr, da->vendor, TAG_ANY);
	if (!key) {
		REDEBUG("Yubikey-Key attribute not found in control list, can't decrypt OTP data");
		return RLM_MODULE_INVALID;
	}

	if (key->length != YUBIKEY_KEY_SIZE) {
		REDEBUG("Yubikey-Key length incorrect, expected %u got %zu", YUBIKEY_KEY_SIZE, key->length);
		return RLM_MODULE_INVALID;
	}

	yubikey_parse((uint8_t const *) passcode + inst->id_len, key->vp_octets, &token);

	/*
	 *	Apparently this just uses byte offsets...
	 */
	if (!yubikey_crc_ok_p((uint8_t *) &token)) {
		REDEBUG("Decrypting OTP token data failed, rejecting");
		return RLM_MODULE_REJECT;
	}

	RDEBUG("Token data decrypted successfully");

	if (request->log.lvl && request->log.func) {
		(void) fr_bin2hex((char *) &private_id, (uint8_t*) &token.uid, YUBIKEY_UID_SIZE);
		RDEBUG2("Private ID	: 0x%s", private_id);
		RDEBUG2("Session counter   : %u", yubikey_counter(token.ctr));
		RDEBUG2("# used in session : %u", token.use);
		RDEBUG2("Token timestamp    : %u",
			(token.tstph << 16) | token.tstpl);
		RDEBUG2("Random data       : %u", token.rnd);
		RDEBUG2("CRC data          : 0x%x", token.crc);
	}

	/*
	 *	Private ID used for validation purposes
	 */
	vp = pairmake(request, &request->packet->vps, "Yubikey-Private-ID", NULL, T_OP_SET);
	if (!vp) {
		REDEBUG("Failed creating Yubikey-Private-ID");

		return RLM_MODULE_FAIL;
	}
	pairmemcpy(vp, token.uid, YUBIKEY_UID_SIZE);

	/*
	 *	Token timestamp
	 */
	vp = pairmake(request, &request->packet->vps, "Yubikey-Timestamp", NULL, T_OP_SET);
	if (!vp) {
		REDEBUG("Failed creating Yubikey-Timestamp");

		return RLM_MODULE_FAIL;
	}
	vp->vp_integer = (token.tstph << 16) | token.tstpl;
	vp->length = 4;

	/*
	 *	Token random
	 */
	vp = pairmake(request, &request->packet->vps, "Yubikey-Random", NULL, T_OP_SET);
	if (!vp) {
		REDEBUG("Failed creating Yubikey-Random");

		return RLM_MODULE_FAIL;
	}
	vp->vp_integer = token.rnd;
	vp->length = 4;

	/*
	 *	Combine the two counter fields together so we can do
	 *	replay attack checks.
	 */
	counter = (yubikey_counter(token.ctr) << 16) | token.use;

	vp = pairmake(request, &request->packet->vps, "Yubikey-Counter", NULL, T_OP_SET);
	if (!vp) {
		REDEBUG("Failed creating Yubikey-Counter");

		return RLM_MODULE_FAIL;
	}
	vp->vp_integer = counter;
	vp->length = 4;

	/*
	 *	Now we check for replay attacks
	 */
	vp = pairfind(request->config_items, vp->da->attr, vp->da->vendor, TAG_ANY);
	if (!vp) {
		RWDEBUG("Yubikey-Counter not found in control list, skipping replay attack checks");
		return RLM_MODULE_OK;
	}

	if (counter <= vp->vp_integer) {
		REDEBUG("Replay attack detected! Counter value %u, is lt or eq to last known counter value %u",
			counter, vp->vp_integer);
		return RLM_MODULE_REJECT;
	}

	return RLM_MODULE_OK;
}
예제 #6
0
int
main (void)
{
  char buf[1024];
  size_t i;
  int rc;
  yubikey_token_st tok;


  /* Test Modhex */
  yubikey_modhex_encode (buf, "test", 4);
  printf ("modhex-encode(\"test\") = %s\n", buf);
  if (strcmp (buf, "ifhgieif") != 0)
    {
      printf ("ModHex failure\n");
      return 1;
    }
  printf ("Modhex-1 success\n");

  printf ("modhex-decode(\"%s\") = ", buf);
  yubikey_modhex_decode (buf, buf, strlen ((char *) buf));
  printf ("%.*s\n", 4, buf);
  if (memcmp (buf, "test", 4) != 0)
    {
      printf ("ModHex failure\n");
      return 1;
    }
  printf ("Modhex-2 success\n");

  strcpy (buf, "cbdefghijklnrtuv");
  rc = yubikey_modhex_p (buf);
  printf ("hex-p(\"%s\") = %d\n", buf, rc);
  if (!rc)
    {
      printf ("Hex_p failure\n");
      return 1;
    }
  printf ("Hex-3 success\n");

  strcpy (buf, "0123Xabc");
  rc = yubikey_hex_p (buf);
  printf ("hex-p(\"%s\") = %d\n", buf, rc);
  if (rc)
    {
      printf ("Hex_p failure\n");
      return 1;
    }
  printf ("Hex-3 success\n");

  /* Test Hex */

  yubikey_hex_encode (buf, "test", 4);
  printf ("hex-encode(\"test\") = %s\n", buf);
  if (strcmp (buf, "74657374") != 0)
    {
      printf ("Hex failure\n");
      return 1;
    }
  printf ("Hex-1 success\n");

  printf ("hex-decode(\"%s\") = ", buf);
  yubikey_hex_decode (buf, buf, strlen ((char *) buf));
  printf ("%.*s\n", 4, buf);
  if (memcmp (buf, "test", 4) != 0)
    {
      printf ("Hex failure\n");
      return 1;
    }
  printf ("Hex-2 success\n");

  strcpy (buf, "0123456789abcdef");
  rc = yubikey_hex_p (buf);
  printf ("hex-p(\"%s\") = %d\n", buf, rc);
  if (!rc)
    {
      printf ("Hex_p failure\n");
      return 1;
    }
  printf ("Hex-3 success\n");

  strcpy (buf, "0123Xabc");
  rc = yubikey_hex_p (buf);
  printf ("hex-p(\"%s\") = %d\n", buf, rc);
  if (rc)
    {
      printf ("Hex_p failure\n");
      return 1;
    }
  printf ("Hex-3 success\n");

  /* Test AES */

  {
    uint8_t buf[1024];
    char out[1024];
    uint8_t key[16 + 1];

    memcpy (buf, "0123456789abcdef\0", 17);
    memcpy (key, "abcdef0123456789\0", 17);
    printf ("aes-decrypt (data=%s, key=%s)\n => ", (char *) buf,
	    (char *) key);
    yubikey_aes_decrypt (buf, key);
    for (i = 0; i < 16; i++)
      printf ("%02x", buf[i] & 0xFF);
    printf ("\n");

    if (memcmp (buf,
		"\x83\x8a\x46\x7f\x34\x63\x95\x51"
		"\x75\x5b\xd3\x2a\x4a\x2f\x15\xe1", 16) != 0)
      {
	printf ("AES failure\n");
	return 1;
      }
    printf ("AES-1 success\n");

    yubikey_aes_encrypt (buf, key);
    if (memcmp (buf, "0123456789abcdef", 16) != 0)
      {
	printf ("AES encryption failure\n");
	return 1;
      }
    printf ("AES-2 success\n");

    /* Test OTP */

    memcpy ((void *) &tok,
	    "\x16\xe1\xe5\xd9\xd3\x99\x10\x04\x45\x20\x07\xe3\x02\x00\x00",
	    16);
    memcpy (key, "abcdef0123456789", 16);

    yubikey_generate ((void *) &tok, key, out);
    yubikey_parse ((uint8_t *) out, key, &tok);

    if (memcmp
	(&tok, "\x16\xe1\xe5\xd9\xd3\x99\x10\x04\x45\x20\x07\xe3\x02\x00\x00",
	 16) != 0)
      {
	printf ("OTP generation - parse failure\n");
	return 1;
      }
    printf ("OTP-1 success\n");
  }

  return 0;
}
static int yubikey_auth_core(myConf_t *myConf, REQUEST *request)
{
    int passLen = 0, session = 0, counter = 0, i = 0;
    MD5_CTX ctx;
    int result = 0;
    char *filename = "/usr/local/etc/raddb/yubico/users";

    //get password by removing the last 32 characters of the password
    if (strlen(request->password->vp_strvalue) <= 32)
    {
        DEBUG("rlm_yubikey: Password too short.");
        return RLM_MODULE_REJECT;
    }

    passLen = strlen(request->password->vp_strvalue) - 32;
    strncpy(myConf->pass, request->password->vp_strvalue, passLen);
    myConf->pass[passLen] = '\0';
    strncpy(myConf->token, request->password->vp_strvalue + passLen, 32);
    myConf->token[32] = '\0';

    //md5 stuff
    MD5Init(&ctx);
    DEBUG("rlm_yubikey: length: %d, string: %s", passLen, myConf->pass);
    MD5Update(&ctx, (unsigned char *)myConf->pass, passLen);
    MD5Final(&ctx);
    MD5toString(&ctx, myConf->md5ComputedString);
    myConf->md5ComputedString[32] = '\0';
    DEBUG("rlm_yubikey: MD5string of your pass: %s", myConf->md5ComputedString);
    DEBUG("rlm_yubikey: Username: %s", request->username->vp_strvalue);

    //read file
    result = config_read_file(&(myConf->config), filename);
    if (result != CONFIG_TRUE)
    {
        DEBUG("rlm_yubikey: Failed to parse configuration file: config_read_file (&config, filename);");
        DEBUG("config_error_text()= %s and config_error_line()=%d", config_error_text(&(myConf->config)), config_error_line(&(myConf->config)));
        return RLM_MODULE_FAIL;
    }

    //parse file
    myConf->config_setting = config_lookup(&(myConf->config), USERS_PATH);
    if (myConf->config_setting == NULL)
    {
        DEBUG("rlm_yubikey: Failed to parse configuration file: config_lookup failed to find the users node");
        return RLM_MODULE_FAIL;
    }

    //go through the list of users
    for (i = 0; i < config_setting_length(myConf->config_setting); i++)
    {
        DEBUG("Trying i: %d", i);
        config_setting_t *tmpSetting = NULL;
        tmpSetting = config_setting_get_elem(myConf->config_setting, i);
        if (tmpSetting == NULL)
        {
            DEBUG("rlm_yubikey: Failed to parse configuration file: config_setting_get_elem(config_setting,i);");
            return RLM_MODULE_FAIL;
        }

        if ((config_setting_get_string_elem(tmpSetting, 0) == NULL) ||
                (config_setting_get_string_elem(tmpSetting, 1) == NULL) ||
                (config_setting_get_string_elem(tmpSetting, 2) == NULL))
        {
            DEBUG("rlm_yubikey: Failed to parse configuration file while reading the username/password/aeskey triplet ");
            return RLM_MODULE_FAIL;
        }

        //check usernames are equal
        if (strcmp(request->username->vp_strvalue, config_setting_get_string_elem(tmpSetting, 0)) != 0)
        {
            //users do not match. No need to debug this
            //Go to next iteration
            continue;
        }

        //check passwords are equal
        if (strcmp(myConf->md5ComputedString, config_setting_get_string_elem(tmpSetting, 1)) != 0)
        {
            //passwords do not match. We debug
            DEBUG("rlm_yubikey: Password does not match for user %s", request->username->vp_strvalue);
            //Go to next iteration
            continue;
        }

        //check aes stuff - mostly copied from the ykdebug.c that comes with the low-level yubikey library
        uint8_t buf[128];
        const char *aeskey = config_setting_get_string_elem(tmpSetting, 2);
        char *token = myConf->token;
        uint8_t key[YUBIKEY_KEY_SIZE];
        yubikey_token_st tok;

        yubikey_modhex_decode((char*) key, token, YUBIKEY_KEY_SIZE);
        DEBUG("rlm_yubikey:  aeskey: %s", aeskey);

        yubikey_hex_decode((char*) key, aeskey, YUBIKEY_KEY_SIZE);

        /* Pack up dynamic password, decrypt it and verify checksum */
        yubikey_parse((uint8_t*) token, key, &tok);

        DEBUG("rlm_yubikey: Struct:");
        size_t i;
        char *tmp = (char*) malloc(1024);
        for (i = 0; i < YUBIKEY_UID_SIZE; i++)
        {
            sprintf(tmp + i, "%c ", tok.uid[i] & 0xFF);
        }
        tmp[YUBIKEY_UID_SIZE + i] = 0;
        DEBUG("rlm_yubikey:   uid:%s", tmp);
        free(tmp);

        DEBUG("rlm_yubikey:   counter: %d (0x%04x)", tok.ctr, tok.ctr);
        DEBUG("rlm_yubikey:   timestamp (low): %d (0x%04x)", tok.tstpl, tok.tstpl);
        DEBUG("rlm_yubikey:   timestamp (high): %d (0x%02x)", tok.tstph, tok.tstph);
        DEBUG("rlm_yubikey:   session use: %d (0x%02x)", tok.use, tok.use);
        DEBUG("rlm_yubikey:   random: %d (0x%02x)", tok.rnd, tok.rnd);
        DEBUG("rlm_yubikey:   crc: %d (0x%04x)", tok.crc, tok.crc);
        DEBUG("rlm_yubikey: Derived:");
        DEBUG("rlm_yubikey:   cleaned counter: %d (0x%04x)",yubikey_counter(tok.ctr), yubikey_counter(tok.ctr));

        yubikey_modhex_encode((char*) buf, (char*) tok.uid, YUBIKEY_UID_SIZE);

        DEBUG("rlm_yubikey:   modhex uid: %s", buf);
        DEBUG("rlm_yubikey:   triggered by caps lock: %s", yubikey_capslock(tok.ctr) ? "yes" : "no");
        DEBUG("rlm_yubikey:   crc: %04X", yubikey_crc16((void*) & tok, YUBIKEY_KEY_SIZE));
        DEBUG("rlm_yubikey:   crc check: ");
        if (yubikey_crc_ok_p((uint8_t*) & tok))
        {
            DEBUG("rlm_yubikey:   ok");

            char *tmppath = KEYS_PATH;
            char *path = (char*) malloc(strlen(tmppath) + 32 + 1);
            strcpy(path, tmppath);
            strcat(path, aeskey);


            myConf->config_setting = config_lookup(&(myConf->config), path);
            if (myConf->config_setting == NULL)
            {
                DEBUG("rlm_yubikey: Error parsing file: %s not found", path);
                return RLM_MODULE_FAIL;
            }

            //checking counter and session and update them if necessary
            counter = config_setting_get_int_elem(myConf->config_setting, 0);
            session = config_setting_get_int_elem(myConf->config_setting, 1);
            DEBUG("rlm_yubikey: Read counter: %d, session: %d", counter, session);

            if ((tok.ctr < counter)||((tok.ctr == counter) && (tok.use <= session)))
            {
                DEBUG("rlm_yubikey: someone tried to login with an old generated hash");
                return RLM_MODULE_REJECT;
            }

            //updating config file with counter and session
            config_setting_set_int_elem(myConf->config_setting, 0, tok.ctr);
            config_setting_set_int_elem(myConf->config_setting, 1, tok.use);


            DEBUG("rlm_yubikey: Written element: %ld", config_setting_get_int_elem(myConf->config_setting, 0));
            DEBUG("rlm_yubikey: Written element: %ld", config_setting_get_int_elem(myConf->config_setting, 1));
            if (CONFIG_FALSE == config_write_file(&(myConf->config), filename))
            {
                DEBUG("rlm_yubikey: Failed to write the file.");
                return RLM_MODULE_FAIL;
            }

            return RLM_MODULE_OK;
        }
        DEBUG("rlm_yubikey:   fail");
    }
    DEBUG("rlm_yubikey: Authenticating with password %s", request->password->vp_strvalue);
    return RLM_MODULE_REJECT;
}
static int
yubikey_login(const char *username, const char *password)
{
	char fn[MAXPATHLEN];
	char hexkey[33], key[YUBIKEY_KEY_SIZE];
	char hexuid[13], uid[YUBIKEY_UID_SIZE];
	FILE *f;
	yubikey_token_st tok;
	u_int32_t last_ctr = 0, ctr;
	int r, i = 0, mapok = 0, crcok = 0;

	snprintf(fn, sizeof(fn), "%s/%s.uid", path, username);
	if ((f = fopen(fn, "r")) == NULL) {
		syslog(LOG_ERR, "user %s: fopen: %s: %m", username, fn);
		return (AUTH_FAILED);
	}
	if (fscanf(f, "%12s", hexuid) != 1) {
		syslog(LOG_ERR, "user %s: fscanf: %s: %m", username, fn);
		fclose(f);
		return (AUTH_FAILED);
	}
	fclose(f);

	snprintf(fn, sizeof(fn), "%s/%s.key", path, username);
	if ((f = fopen(fn, "r")) == NULL) {
		syslog(LOG_ERR, "user %s: fopen: %s: %m", username, fn);
		return (AUTH_FAILED);
	}
	if (fscanf(f, "%32s", hexkey) != 1) {
		syslog(LOG_ERR, "user %s: fscanf: %s: %m", username, fn);
		fclose(f);
		return (AUTH_FAILED);
	}
	fclose(f);
	if (strlen(hexkey) != 32) {
		syslog(LOG_ERR, "user %s: key len != 32", username);
		return (AUTH_FAILED);
	}

	snprintf(fn, sizeof(fn), "%s/%s.ctr", path, username);
	if ((f = fopen(fn, "r")) != NULL) {
		if (fscanf(f, "%u", &last_ctr) != 1)
			last_ctr = 0;
		fclose(f);
	}

	yubikey_hex_decode(uid, hexuid, YUBIKEY_UID_SIZE);
	yubikey_hex_decode(key, hexkey, YUBIKEY_KEY_SIZE);

	/* 
	 * Cycle through the key mapping table.
         * XXX brute force, unoptimized; a lookup table for valid mappings may
	 * be appropriate.
	 */
	while (1) {
		r = yubikey_parse((uint8_t *)password, (uint8_t *)key, &tok, i++);
		switch (r) {
		case EMSGSIZE:
			syslog(LOG_INFO, "user %s failed: password too short.",
			    username);
			return (AUTH_FAILED);
		case EINVAL: 	/* keyboard mapping invalid */
			continue;
		case 0:		/* found a valid keyboard mapping */
			mapok++;
			if (!yubikey_crc_ok_p((uint8_t *)&tok))
				continue;	/* try another one */
			crcok++;
			syslog(LOG_DEBUG, "user %s: crc %04x ok",
			    username, tok.crc);

			if (memcmp(tok.uid, uid, YUBIKEY_UID_SIZE)) {
				char h[13];

				yubikey_hex_encode(h, (const char *)tok.uid,
				    YUBIKEY_UID_SIZE);
				syslog(LOG_DEBUG, "user %s: uid %s != %s",
				    username, h, hexuid);
				continue;	/* try another one */
			}
			break; /* uid matches */
		case -1:
			syslog(LOG_INFO, "user %s: could not decode password "
			    "with any keymap (%d crc ok)",
			    username, crcok);
			return (AUTH_FAILED);
		default: 
			syslog(LOG_DEBUG, "user %s failed: %s",
			    username, strerror(r));
			return (AUTH_FAILED);
		}
		break; /* only reached through the bottom of case 0 */
	}

	syslog(LOG_INFO, "user %s uid %s: %d matching keymaps (%d checked), "
	    "%d crc ok", username, hexuid, mapok, i, crcok);

	ctr = ((u_int32_t)yubikey_counter(tok.ctr) << 8) | tok.use;
	if (ctr <= last_ctr) {
		syslog(LOG_INFO, "user %s: counter %u.%u <= %u.%u "
		    "(REPLAY ATTACK!)", username, ctr / 256, ctr % 256,
		    last_ctr / 256, last_ctr % 256);
		return (AUTH_FAILED);
	}
	syslog(LOG_INFO, "user %s: counter %u.%u > %u.%u",
	    username, ctr / 256, ctr % 256, last_ctr / 256, last_ctr % 256);
	umask(S_IRWXO);
	if ((f = fopen(fn, "w")) == NULL) {
		syslog(LOG_ERR, "user %s: fopen: %s: %m", username, fn);
		return (AUTH_FAILED);
	}
	fprintf(f, "%u", ctr);
	fclose(f);

	return (AUTH_OK);
}
예제 #9
0
/*
 *	Authenticate the user with the given password.
 */
static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
{
	rlm_yubikey_t *inst = instance;
	
	char *passcode;
	size_t i, len;
	uint32_t counter;

	const DICT_ATTR *da;	
	VALUE_PAIR *key, *vp;
	yubikey_token_st token;
	
	char private_id[(YUBIKEY_UID_SIZE * 2) + 1];
	
	/*
	 *	Can't do yubikey auth if there's no password.
	 */
	if (!request->password || (request->password->da->attr != PW_USER_PASSWORD)) {
		RDEBUGE("No Clear-Text password in the request. Can't do Yubikey authentication.");
		return RLM_MODULE_FAIL;
	}
	
	passcode = request->password->vp_strvalue;
	len = request->password->length;
	/*
	 *	Verify the passcode is the correct length (in its raw
	 *	modhex encoded form).
	 *
	 *	<public_id (6-16 bytes)> + <aes-block (32 bytes)>
	 */
	if (len != (inst->id_len + 32)) {
		RDEBUGE("User-Password value is not the correct length, expected %u, got %zu", inst->id_len + 32, len);
		return RLM_MODULE_FAIL;	
	}

	for (i = inst->id_len; i < len; i++) {
		if (!is_modhex(*passcode)) {
			RDEBUG2("User-Password (aes-block) value contains non modhex chars");
			return RLM_MODULE_FAIL;	
		}
	}
	
	da = dict_attrbyname("Yubikey-Key");
	key = pairfind(request->config_items, da->attr, da->vendor, TAG_ANY);
	if (!key) {
		RDEBUGE("Yubikey-Key attribute not found in control list, can't decrypt OTP data");
		return RLM_MODULE_FAIL;
	}

	if (key->length != YUBIKEY_KEY_SIZE) {
		RDEBUGE("Yubikey-Key length incorrect, expected %u got %zu", YUBIKEY_KEY_SIZE, key->length);
		return RLM_MODULE_FAIL;	
	}
	
	yubikey_parse(request->password->vp_octets + inst->id_len,
		      key->vp_octets, &token);

	/*
	 *	Apparently this just uses byte offsets...
	 */
	if (!yubikey_crc_ok_p((uint8_t *) &token)) {
		RDEBUGE("Decrypting OTP token data failed, rejecting");	
		return RLM_MODULE_REJECT;
	}
	
	RDEBUG("Token data decrypted successfully");
	
	if (request->options && request->radlog) {
		(void) fr_bin2hex((uint8_t*) &token.uid,
				  (char *) &private_id, YUBIKEY_UID_SIZE);
		RDEBUG2("Private ID	: 0x%s", private_id);
		RDEBUG2("Session counter   : %u", yubikey_counter(token.ctr));
		RDEBUG2("# used in session : %u", token.use);
		RDEBUG2("Token timetamp    : %u",
			(token.tstph << 16) | token.tstpl);
		RDEBUG2("Random data       : %u", token.rnd);
		RDEBUG2("CRC data          : 0x%x", token.crc);
	}

	/*
	 *	Private ID used for validation purposes
	 */
	vp = pairmake(request, &request->packet->vps, "Yubikey-Private-ID", NULL, T_OP_SET);	
	memcpy(vp->vp_octets, token.uid, YUBIKEY_UID_SIZE);
	vp->length = YUBIKEY_UID_SIZE;
	
	/*
	 *	Token timestamp
	 */
	vp = pairmake(request, &request->packet->vps, "Yubikey-Timestamp", NULL, T_OP_SET);
	vp->vp_integer = (token.tstph << 16) | token.tstpl;
	vp->length = 4;
	
	/*
	 *	Token random
	 */
	vp = pairmake(request, &request->packet->vps, "Yubikey-Random", NULL, T_OP_SET);
	vp->vp_integer = token.rnd;
	vp->length = 4;
	
	/*
	 *	Combine the two counter fields together so we can do
	 *	replay attack checks.
	 */
	counter = (yubikey_counter(token.ctr) << 16) | token.use;
	
	vp = pairmake(request, &request->packet->vps, "Yubikey-Counter", NULL, T_OP_SET);
	vp->vp_integer = counter;
	vp->length = 4;
	
	/*
	 *	Now we check for replay attacks
	 */
	vp = pairfind(request->config_items, vp->da->attr, vp->da->vendor, TAG_ANY);
	if (!vp) {
		RDEBUGW("Yubikey-Counter not found in control list, skipping replay attack checks");
		return RLM_MODULE_OK;
	}

	if (counter <= vp->vp_integer) {
		RDEBUGE("Replay attack detected! Counter value %u, is lt or eq to last known counter value %u",
			counter, vp->vp_integer);
		return RLM_MODULE_REJECT;	
	}

	return RLM_MODULE_OK;
}