1
0
mirror of https://github.com/Yubico/yubico-pam.git synced 2025-02-21 15:54:41 +01:00

use pbkdf2 to process the exepected response

this bumps the version on the state file to 2
old files can still be read but new files will use the new format
This commit is contained in:
Klas Lindfors 2013-09-18 09:58:47 +02:00
parent eb78d4882b
commit fb6b0911fd
3 changed files with 61 additions and 9 deletions

View File

@ -47,6 +47,7 @@
#if HAVE_CR
/* for yubikey_hex_decode and yubikey_hex_p */
#include <yubikey.h>
#include <ykpbkdf2.h>
#endif /* HAVE_CR */
/* Libtool defines PIC for shared objects */
@ -553,8 +554,13 @@ do_challenge_response(pam_handle_t *pamh, struct cfg *cfg, const char *username)
*/
yubikey_hex_encode(response_hex, buf, response_len);
if(state.salt_len > 0) { // the expected response has gone through pbkdf2
YK_PRF_METHOD prf_method = {20, yk_hmac_sha1};
yk_pbkdf2(response_hex, state.salt, state.salt_len, state.iterations,
buf, response_len, &prf_method);
}
if (memcmp(buf, state.response, response_len) == 0) {
if (memcmp(buf, state.response, state.response_len) == 0) {
ret = PAM_SUCCESS;
} else {
DBG(("Unexpected C/R response : %s", response_hex));
@ -579,7 +585,7 @@ do_challenge_response(pam_handle_t *pamh, struct cfg *cfg, const char *username)
/* 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) {
if (memcmp(buf, state.response, state.response_len) == 0) {
errstr = "Same response for second challenge, YubiKey should be reconfigured with the option HMAC_LT64";
goto out;
}

54
util.c
View File

@ -43,6 +43,7 @@
#if HAVE_CR
/* for yubikey_hex_decode and yubikey_hex_p */
#include <yubikey.h>
#include <ykpbkdf2.h>
#endif /* HAVE_CR */
int
@ -237,6 +238,8 @@ load_chalresp_state(FILE *f, CR_STATE *state, bool verbose)
* Format is hex(challenge):hex(response):slot num
*/
char challenge_hex[CR_CHALLENGE_SIZE * 2 + 1], response_hex[CR_RESPONSE_SIZE * 2 + 1];
char salt_hex[CR_SALT_SIZE * 2 + 1];
unsigned int iterations;
int slot;
int r;
@ -248,14 +251,34 @@ load_chalresp_state(FILE *f, CR_STATE *state, bool verbose)
* 40 is twice the size of CR_RESPONSE_SIZE
* (twice because we hex encode the challenge and response)
*/
r = fscanf(f, "v1:%126[0-9a-z]:%40[0-9a-z]:%d", &challenge_hex[0], &response_hex[0], &slot);
if (r != 3) {
D(("Could not parse contents of chalresp_state file (%i)", r));
goto out;
r = fscanf(f, "v2:%126[0-9a-z]:%40[0-9a-z]:%64[0-9a-z]:%d:%d", challenge_hex, response_hex, salt_hex, &iterations, &slot);
if(r == 5) {
if (! yubikey_hex_p(salt_hex)) {
D(("Invalid salt hex input : %s", salt_hex));
goto out;
}
if(verbose) {
D(("Challenge: %s, hashed response: %s, salt: %s, iterations: %d, slot: %d",
challenge_hex, response_hex, salt_hex, iterations, slot));
}
yubikey_hex_decode(state->salt, salt_hex, sizeof(state->challenge));
state->salt_len = strlen(salt_hex) / 2;
state->iterations = iterations;
} else {
r = fscanf(f, "v1:%126[0-9a-z]:%40[0-9a-z]:%d", challenge_hex, response_hex, &slot);
if (r != 3) {
D(("Could not parse contents of chalresp_state file (%i)", r));
goto out;
}
if (verbose) {
D(("Challenge: %s, expected response: %s, slot: %d", challenge_hex, response_hex, slot));
}
}
if (verbose)
D(("Challenge: %s, expected response: %s, slot: %d", challenge_hex, response_hex, slot));
if (! yubikey_hex_p(challenge_hex)) {
D(("Invalid challenge hex input : %s", challenge_hex));
@ -290,14 +313,31 @@ int
write_chalresp_state(FILE *f, CR_STATE *state)
{
char challenge_hex[CR_CHALLENGE_SIZE * 2 + 1], response_hex[CR_RESPONSE_SIZE * 2 + 1];
char salt_hex[CR_SALT_SIZE * 2 + 1], hashed_hex[CR_RESPONSE_SIZE * 2 + 1];
unsigned char salt[CR_SALT_SIZE], hash[CR_RESPONSE_SIZE];
YK_PRF_METHOD prf_method = {20, yk_hmac_sha1};
unsigned int iterations = CR_DEFAULT_ITERATIONS;
int fd;
memset(challenge_hex, 0, sizeof(challenge_hex));
memset(response_hex, 0, sizeof(response_hex));
memset(salt_hex, 0, sizeof(salt_hex));
memset(hashed_hex, 0, sizeof(hashed_hex));
yubikey_hex_encode(challenge_hex, (char *)state->challenge, state->challenge_len);
yubikey_hex_encode(response_hex, (char *)state->response, state->response_len);
if(state->iterations > 0) {
iterations = state->iterations;
}
generate_random(salt, CR_SALT_SIZE);
yk_pbkdf2(response_hex, salt, CR_SALT_SIZE, iterations,
hash, CR_RESPONSE_SIZE, &prf_method);
yubikey_hex_encode(hashed_hex, (char *)hash, CR_RESPONSE_SIZE);
yubikey_hex_encode(salt_hex, (char *)salt, CR_SALT_SIZE);
rewind(f);
fd = fileno(f);
@ -307,7 +347,7 @@ write_chalresp_state(FILE *f, CR_STATE *state)
if (ftruncate(fd, 0))
goto out;
fprintf(f, "v1:%s:%s:%d\n", challenge_hex, response_hex, state->slot);
fprintf(f, "v2:%s:%s:%s:%d:%d\n", challenge_hex, hashed_hex, salt_hex, iterations, state->slot);
if (fflush(f) < 0)
goto out;

6
util.h
View File

@ -67,13 +67,19 @@ int get_user_cfgfile_path(const char *common_path, const char *filename, const c
*/
#define CR_CHALLENGE_SIZE 63
#define CR_RESPONSE_SIZE 20
#define CR_SALT_SIZE 32
#define CR_DEFAULT_ITERATIONS 10000
struct chalresp_state {
char challenge[CR_CHALLENGE_SIZE];
uint8_t challenge_len;
char response[CR_RESPONSE_SIZE];
uint8_t response_len;
char salt[CR_SALT_SIZE];
uint8_t salt_len;
uint8_t slot;
uint32_t iterations;
};
typedef struct chalresp_state CR_STATE;