mirror of
https://github.com/Yubico/yubico-pam.git
synced 2025-01-19 16:52:17 +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
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <ykclient.h>
|
|
||||||
#include <ykcore.h>
|
|
||||||
#include <ykdef.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_LIBLDAP
|
#ifdef HAVE_LIBLDAP
|
||||||
/* Some functions like ldap_init, ldap_simple_bind_s, ldap_unbind are
|
/* Some functions like ldap_init, ldap_simple_bind_s, ldap_unbind are
|
||||||
deprecated but still available. We will drop support for 'ldapserver'
|
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;
|
char *userfile = NULL, *tmpfile = NULL;
|
||||||
FILE *f = NULL;
|
FILE *f = NULL;
|
||||||
char challenge[CR_CHALLENGE_SIZE + 1];
|
unsigned char challenge[CR_CHALLENGE_SIZE + 1];
|
||||||
char challenge_hex[sizeof(challenge) * 2 + 1], expected_response[CR_RESPONSE_SIZE * 2 + 1];
|
unsigned char challenge_hex[sizeof(challenge) * 2 + 1], expected_response[CR_RESPONSE_SIZE * 2 + 1];
|
||||||
int r, slot, ret, fd;
|
int r, slot, ret, fd;
|
||||||
|
|
||||||
unsigned char response[CR_RESPONSE_SIZE + 16]; /* Need some extra bytes in this read buffer */
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
yubikey_hex_decode(challenge, challenge_hex, strlen(challenge_hex));
|
if (slot != 1 && slot != 2) {
|
||||||
len = strlen(challenge_hex) / 2;
|
|
||||||
if (slot == 1) {
|
|
||||||
yk_cmd = SLOT_CHAL_HMAC1;
|
|
||||||
} else if (slot == 2) {
|
|
||||||
yk_cmd = SLOT_CHAL_HMAC2;
|
|
||||||
} else {
|
|
||||||
D(("Invalid slot input : %i", slot));
|
D(("Invalid slot input : %i", slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!yk_init())
|
if (! init_yubikey(&yk)) {
|
||||||
|
D(("Failed initializing YubiKey"));
|
||||||
goto out;
|
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;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (!yk_write_to_key(yk, yk_cmd, challenge, len))
|
yubikey_hex_decode(challenge, challenge_hex, sizeof(challenge));
|
||||||
goto out;
|
len = strlen(challenge_hex) / 2;
|
||||||
|
|
||||||
if (! yk_read_response_from_key(yk, slot, flags,
|
if (! challenge_response(yk, slot, challenge, len, true, flags, false,
|
||||||
&response, sizeof(response),
|
response, sizeof(response), &response_len)) {
|
||||||
CR_RESPONSE_SIZE,
|
D(("Challenge-response FAILED"));
|
||||||
&response_len))
|
|
||||||
goto out;
|
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);
|
yubikey_hex_encode(response_hex, (char *)response, response_len);
|
||||||
|
|
||||||
if (strcmp(response_hex, expected_response) == 0) {
|
if (strcmp(response_hex, expected_response) == 0) {
|
||||||
ret = PAM_SUCCESS;
|
ret = PAM_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
D(("Unexpected C/R response : %s", response_hex));
|
D(("Unexpected C/R response : %s != %s", response_hex, expected_response));
|
||||||
ret = PAM_AUTH_ERR;
|
ret = PAM_AUTH_ERR;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -490,22 +487,19 @@ do_challenge_response(struct cfg *cfg, const char *username)
|
|||||||
goto out;
|
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;
|
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 */
|
/* the yk_* functions leave 'junk' in errno */
|
||||||
errno = 0;
|
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(challenge_hex, 0, sizeof(challenge_hex));
|
||||||
memset(response_hex, 0, sizeof(response_hex));
|
memset(response_hex, 0, sizeof(response_hex));
|
||||||
yubikey_hex_encode(challenge_hex, (char *)challenge, CR_CHALLENGE_SIZE);
|
yubikey_hex_encode(challenge_hex, (char *)challenge, CR_CHALLENGE_SIZE);
|
||||||
|
105
util.c
105
util.c
@ -39,8 +39,13 @@
|
|||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <ykclient.h>
|
||||||
|
#include <ykcore.h>
|
||||||
|
#include <ykstatus.h>
|
||||||
|
#include <ykdef.h>
|
||||||
|
|
||||||
/* Fill buf with len bytes of random data */
|
/* 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;
|
FILE *u;
|
||||||
int i, res;
|
int i, res;
|
||||||
@ -59,7 +64,7 @@ static int generate_random(char *buf, int len)
|
|||||||
int
|
int
|
||||||
get_user_cfgfile_path(const char *common_path, const char *filename, const char *username, char **fn)
|
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.
|
* from a system wide directory.
|
||||||
*
|
*
|
||||||
* Format is hex(challenge):hex(response):slot num
|
* 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;
|
*fn = userfile;
|
||||||
return (userfile >= 0);
|
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.
|
* 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 generate_random(char *buf, int len);
|
||||||
int get_user_cfgfile_path(const char *common_path, const char *filename, const char *username, char **fn);
|
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