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:
parent
eb78d4882b
commit
fb6b0911fd
10
pam_yubico.c
10
pam_yubico.c
@ -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
54
util.c
@ -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
6
util.h
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user