mirror of
https://github.com/Yubico/yubico-pam.git
synced 2025-01-19 07:52:23 +01:00
Move more challenge-response code to util.c.
This commit is contained in:
parent
c557249503
commit
721866df0b
66
pam_yubico.c
66
pam_yubico.c
@ -64,10 +64,6 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <ykclient.h>
|
||||
#include <ykcore.h>
|
||||
#include <ykdef.h>
|
||||
|
||||
#ifdef HAVE_LIBLDAP
|
||||
/* Some functions like ldap_init, ldap_simple_bind_s, ldap_unbind are
|
||||
deprecated but still available. We will drop support for 'ldapserver'
|
||||
@ -400,8 +396,8 @@ do_challenge_response(struct cfg *cfg, const char *username)
|
||||
{
|
||||
char *userfile = NULL, *tmpfile = NULL;
|
||||
FILE *f = NULL;
|
||||
char challenge[CR_CHALLENGE_SIZE + 1];
|
||||
char challenge_hex[sizeof(challenge) * 2 + 1], expected_response[CR_RESPONSE_SIZE * 2 + 1];
|
||||
unsigned char challenge[CR_CHALLENGE_SIZE + 1];
|
||||
unsigned char challenge_hex[sizeof(challenge) * 2 + 1], expected_response[CR_RESPONSE_SIZE * 2 + 1];
|
||||
int r, slot, ret, fd;
|
||||
|
||||
unsigned char response[CR_RESPONSE_SIZE + 16]; /* Need some extra bytes in this read buffer */
|
||||
@ -447,38 +443,39 @@ do_challenge_response(struct cfg *cfg, const char *username)
|
||||
goto out;
|
||||
}
|
||||
|
||||
yubikey_hex_decode(challenge, challenge_hex, strlen(challenge_hex));
|
||||
len = strlen(challenge_hex) / 2;
|
||||
if (slot == 1) {
|
||||
yk_cmd = SLOT_CHAL_HMAC1;
|
||||
} else if (slot == 2) {
|
||||
yk_cmd = SLOT_CHAL_HMAC2;
|
||||
} else {
|
||||
if (slot != 1 && slot != 2) {
|
||||
D(("Invalid slot input : %i", slot));
|
||||
}
|
||||
|
||||
if (!yk_init())
|
||||
if (! init_yubikey(&yk)) {
|
||||
D(("Failed initializing YubiKey"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(yk = yk_open_first_key()))
|
||||
if (! check_firmware_version(yk, false, true)) {
|
||||
D(("YubiKey does not support Challenge-Response (version 2.2 required)"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!yk_write_to_key(yk, yk_cmd, challenge, len))
|
||||
goto out;
|
||||
yubikey_hex_decode(challenge, challenge_hex, sizeof(challenge));
|
||||
len = strlen(challenge_hex) / 2;
|
||||
|
||||
if (! yk_read_response_from_key(yk, slot, flags,
|
||||
&response, sizeof(response),
|
||||
CR_RESPONSE_SIZE,
|
||||
&response_len))
|
||||
if (! challenge_response(yk, slot, challenge, len, true, flags, false,
|
||||
response, sizeof(response), &response_len)) {
|
||||
D(("Challenge-response FAILED"));
|
||||
goto out;
|
||||
/* response read includes some extra bytes (CRC etc.) */
|
||||
if (response_len > CR_RESPONSE_SIZE)
|
||||
response_len = CR_RESPONSE_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check YubiKey response against the expected response
|
||||
*/
|
||||
|
||||
yubikey_hex_encode(response_hex, (char *)response, response_len);
|
||||
|
||||
if (strcmp(response_hex, expected_response) == 0) {
|
||||
ret = PAM_SUCCESS;
|
||||
} else {
|
||||
D(("Unexpected C/R response : %s", response_hex));
|
||||
D(("Unexpected C/R response : %s != %s", response_hex, expected_response));
|
||||
ret = PAM_AUTH_ERR;
|
||||
goto out;
|
||||
}
|
||||
@ -490,22 +487,19 @@ do_challenge_response(struct cfg *cfg, const char *username)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!yk_write_to_key(yk, yk_cmd, challenge, CR_CHALLENGE_SIZE))
|
||||
if (! challenge_response(yk, slot, challenge, CR_CHALLENGE_SIZE, true, flags, false,
|
||||
response, sizeof(response), &response_len)) {
|
||||
D(("Second challenge-response FAILED"));
|
||||
goto out;
|
||||
|
||||
if (! yk_read_response_from_key(yk, slot, flags,
|
||||
&response, sizeof(response),
|
||||
CR_RESPONSE_SIZE,
|
||||
&response_len))
|
||||
goto out;
|
||||
|
||||
/* response read includes some extra bytes (CRC etc.) */
|
||||
if (response_len > CR_RESPONSE_SIZE)
|
||||
response_len = CR_RESPONSE_SIZE;
|
||||
}
|
||||
|
||||
/* the yk_* functions leave 'junk' in errno */
|
||||
errno = 0;
|
||||
|
||||
/*
|
||||
* Write the challenge and response we will expect the next time to the state file.
|
||||
*/
|
||||
|
||||
memset(challenge_hex, 0, sizeof(challenge_hex));
|
||||
memset(response_hex, 0, sizeof(response_hex));
|
||||
yubikey_hex_encode(challenge_hex, (char *)challenge, CR_CHALLENGE_SIZE);
|
||||
|
105
util.c
105
util.c
@ -39,8 +39,13 @@
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include <ykclient.h>
|
||||
#include <ykcore.h>
|
||||
#include <ykstatus.h>
|
||||
#include <ykdef.h>
|
||||
|
||||
/* Fill buf with len bytes of random data */
|
||||
static int generate_random(char *buf, int len)
|
||||
int generate_random(char *buf, int len)
|
||||
{
|
||||
FILE *u;
|
||||
int i, res;
|
||||
@ -59,7 +64,7 @@ static int generate_random(char *buf, int len)
|
||||
int
|
||||
get_user_cfgfile_path(const char *common_path, const char *filename, const char *username, char **fn)
|
||||
{
|
||||
/* Getting file from user home directory, i.e. ~/.yubico/challenge, or
|
||||
/* Getting file from user home directory, e.g. ~/.yubico/challenge, or
|
||||
* from a system wide directory.
|
||||
*
|
||||
* Format is hex(challenge):hex(response):slot num
|
||||
@ -83,3 +88,99 @@ get_user_cfgfile_path(const char *common_path, const char *filename, const char
|
||||
*fn = userfile;
|
||||
return (userfile >= 0);
|
||||
}
|
||||
|
||||
int
|
||||
check_firmware_version(YK_KEY *yk, bool verbose, bool quiet)
|
||||
{
|
||||
YK_STATUS *st = ykds_alloc();
|
||||
|
||||
if (!yk_get_status(yk, st)) {
|
||||
free(st);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("Firmware version %d.%d.%d\n",
|
||||
ykds_version_major(st),
|
||||
ykds_version_minor(st),
|
||||
ykds_version_build(st));
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
if (ykds_version_major(st) < 2 ||
|
||||
ykds_version_minor(st) < 2) {
|
||||
if (! quiet)
|
||||
fprintf(stderr, "Challenge-response not supported before YubiKey 2.2.\n");
|
||||
free(st);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(st);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
init_yubikey(YK_KEY **yk)
|
||||
{
|
||||
if (!yk_init())
|
||||
return 0;
|
||||
|
||||
if (!(*yk = yk_open_first_key()))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int challenge_response(YK_KEY *yk, int slot,
|
||||
unsigned char *challenge, unsigned int len,
|
||||
bool hmac, unsigned int flags, bool verbose,
|
||||
unsigned char *response, int res_size, int *res_len)
|
||||
{
|
||||
int yk_cmd;
|
||||
unsigned int response_len = 0;
|
||||
unsigned int expect_bytes = 0;
|
||||
|
||||
if (res_size < sizeof(64 + 16))
|
||||
return 0;
|
||||
|
||||
memset(response, 0, sizeof(response));
|
||||
|
||||
if (verbose) {
|
||||
fprintf(stderr, "Sending %i bytes %s challenge to slot %i\n", len, (hmac == true)?"HMAC":"Yubico", slot);
|
||||
//_yk_hexdump(challenge, len);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!yk_write_to_key(yk, yk_cmd, challenge, len))
|
||||
return 0;
|
||||
|
||||
if (verbose) {
|
||||
fprintf(stderr, "Reading response...\n");
|
||||
}
|
||||
|
||||
/* HMAC responses are 160 bits, Yubico 128 */
|
||||
expect_bytes = (hmac == true) ? 20 : 16;
|
||||
|
||||
if (! yk_read_response_from_key(yk, slot, flags,
|
||||
response, res_size,
|
||||
expect_bytes,
|
||||
&response_len))
|
||||
return 0;
|
||||
|
||||
if (hmac && response_len > 20)
|
||||
response_len = 20;
|
||||
if (! hmac && response_len > 16)
|
||||
response_len = 16;
|
||||
|
||||
*res_len = response_len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
12
util.h
12
util.h
@ -31,5 +31,17 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <ykclient.h>
|
||||
#include <ykcore.h>
|
||||
#include <ykstatus.h>
|
||||
#include <ykdef.h>
|
||||
|
||||
int generate_random(char *buf, int len);
|
||||
int get_user_cfgfile_path(const char *common_path, const char *filename, const char *username, char **fn);
|
||||
|
||||
int init_yubikey(YK_KEY **yk);
|
||||
int check_firmware_version(YK_KEY *yk, bool verbose, bool quiet);
|
||||
int challenge_response(YK_KEY *yk, int slot,
|
||||
unsigned char *challenge, unsigned int len,
|
||||
bool hmac, unsigned int flags, bool verbose,
|
||||
unsigned char *response, int res_size, int *res_len);
|
||||
|
Loading…
x
Reference in New Issue
Block a user