Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

new login style: yubikey-and-pwd

3 views
Skip to first unread message

Remi Locherer

unread,
Jan 4, 2014, 4:56:33 AM1/4/14
to te...@openbsd.org
This patch privides a new login style: yubikey-and-pwd. The idea is from
login_totp-and-pwd from the login_oath port.

I tried to keep the patch small and not touch to many things. But probably
it would be bette to chang more stuff (eg: there are now two backchannels:
*back from login_passwd.c and *f from login_yubikey.c).

It's likely that I got something wrong - I'm a novice in progamming c ;)

Remi


Index: Makefile
===================================================================
RCS file: /cvs/src/libexec/Makefile,v
retrieving revision 1.54
diff -u -p -r1.54 Makefile
--- Makefile 4 Dec 2013 20:49:28 -0000 1.54
+++ Makefile 3 Jan 2014 23:54:18 -0000
@@ -5,8 +5,8 @@

SUBDIR= comsat fingerd ftpd getty ld.so lockspool login_chpass \
login_lchpass login_passwd login_radius login_reject \
- login_skey login_tis login_token login_yubikey mail.local \
- makewhatis rpc.rquotad rpc.rstatd rpc.rusersd rpc.rwalld \
+ login_skey login_tis login_token login_yubikey login_yubikey-and-pwd \
+ mail.local makewhatis rpc.rquotad rpc.rstatd rpc.rusersd rpc.rwalld \
rpc.sprayd rshd security spamd spamd-setup spamlogd talkd \
tcpd uucpd

Index: login_yubikey/login_yubikey.c
===================================================================
RCS file: /cvs/src/libexec/login_yubikey/login_yubikey.c,v
retrieving revision 1.8
diff -u -p -r1.8 login_yubikey.c
--- login_yubikey/login_yubikey.c 27 Nov 2013 21:25:25 -0000 1.8
+++ login_yubikey/login_yubikey.c 4 Jan 2014 00:19:55 -0000
@@ -54,6 +54,12 @@
#define AUTH_OK 0
#define AUTH_FAILED -1

+#ifdef PASSWD
+#include <util.h>
+#include <common.h>
+FILE *back = NULL;
+#endif
+
static const char *path = "/var/db/yubikey";

static int clean_string(const char *);
@@ -67,6 +73,11 @@ main(int argc, char *argv[])
char *username, *password = NULL;
char response[1024];

+#ifdef PASSWD
+ char *wheel = NULL, *class = NULL;
+ int lastchance = 0;
+#endif
+
setpriority(PRIO_PROCESS, 0, 0);
openlog(NULL, LOG_ODELAY, LOG_AUTH);

@@ -151,7 +162,45 @@ main(int argc, char *argv[])
}
}

+#ifndef PASSWD
ret = yubikey_login(username, password);
+#endif
+#ifdef PASSWD
+ back = f;
+
+ /* the string issued by the yubikey is 44 bytes long */
+ int password_len = strlen(password) - 44, cnt;
+
+ /* exit if password_len is to short */
+ if ( password_len < 0 ) {
+ syslog(LOG_INFO, "user %s: reject", username);
+ fprintf(f, "%s\n", BI_REJECT);
+ closelog();
+ return (EXIT_SUCCESS);
+ }
+
+ char password_yubikey[44];
+ char password_pwd[password_len + 1]; // +1 for \0
+
+ /* copy x - 44 bytes (password) */
+ for ( cnt = 0 ; cnt < password_len ; cnt++ )
+ password_pwd[cnt] = password[cnt];
+ password_pwd[password_len] = '\0';
+
+ /* copy last 44 bytes (one-time password) */
+ for ( cnt = 0 ; cnt + password_len < strlen(password) ; cnt++ )
+ password_yubikey[cnt] = password[cnt+password_len];
+
+ ret = yubikey_login(username, password_yubikey);
+
+ /* only test the password if yubkey auth was successful */
+ if (ret == AUTH_OK)
+ ret = pwd_login(username, password_pwd, wheel, lastchance, class);
+
+ memset(password_yubikey, 0, strlen(password_yubikey));
+ memset(password_pwd, 0, strlen(password_pwd));
+#endif
+
memset(password, 0, strlen(password));
if (ret == AUTH_OK) {
syslog(LOG_INFO, "user %s: authorize", username);
Index: login_yubikey-and-pwd/Makefile
===================================================================
RCS file: login_yubikey-and-pwd/Makefile
diff -N login_yubikey-and-pwd/Makefile
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ login_yubikey-and-pwd/Makefile 4 Jan 2014 01:18:49 -0000
@@ -0,0 +1,23 @@
+# $OpenBSD$
+
+.include <bsd.own.mk>
+
+PROG= login_yubikey-and-pwd
+MAN= ${PROG}.8
+SRCS= login_passwd.c pwd_gensalt.c
+SRCS+= login_yubikey.c yubikey.c
+DPADD= ${LIBUTIL}
+LDADD+= -lutil
+
+CFLAGS+=-DPASSWD -Wall
+CFLAGS+=-I${.CURDIR}/../login_passwd
+CFLAGS+=-I${.CURDIR}/../../usr.bin/passwd
+
+.PATH: ${.CURDIR}/../login_passwd ${.CURDIR}/../../usr.bin/passwd ${.CURDIR}/../login_yubikey
+
+BINOWN= root
+BINGRP= auth
+BINMODE=2555
+BINDIR= /usr/libexec/auth
+
+.include <bsd.prog.mk>
Index: login_yubikey-and-pwd/login_yubikey-and-pwd.8
===================================================================
RCS file: login_yubikey-and-pwd/login_yubikey-and-pwd.8
diff -N login_yubikey-and-pwd/login_yubikey-and-pwd.8
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ login_yubikey-and-pwd/login_yubikey-and-pwd.8 3 Jan 2014 23:46:57 -0000
@@ -0,0 +1,96 @@
+.\" $OpenBSD$
+.\"
+.\" Copyright (c) 2010 Daniel Hartmeier <dan...@benzedrine.cx>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" - Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" - Redistributions in binary form must reproduce the above
+.\" copyright notice, this list of conditions and the following
+.\" disclaimer in the documentation and/or other materials provided
+.\" with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+.\" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd $Mdocdate: January 4 2014 $
+.Dt LOGIN_YUBIKEY-AND-PWD 8
+.Os
+.Sh NAME
+.Nm login_yubikey-and-pwd
+.Nd provide combined YubiKey and password authentication type
+.Sh SYNOPSIS
+.Nm login_yubikey-and-pwd
+.Op Fl dv
+.Op Fl s Ar service
+.Ar user
+.Op Ar class
+.Sh DESCRIPTION
+The
+.Nm
+utility is called by
+.Xr login 1 ,
+.Xr su 1 ,
+.Xr ftpd 8 ,
+and others to authenticate the
+.Ar user
+via a combination of password authentication and a YubiKey one-time
+password.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl d
+Debug mode.
+Output is sent to the standard output instead of the
+.Bx
+Authentication backchannel.
+.It Fl s Ar service
+Specify the service.
+Currently, only
+.Li challenge ,
+.Li login ,
+and
+.Li response
+are supported.
+The default protocol is
+.Em login .
+.It Fl v
+This option and its value are ignored.
+.El
+.Pp
+The
+.Ar user
+argument is the login name of the user to be authenticated.
+.Pp
+The optional
+.Ar class
+argument is accepted for consistency with the other login scripts but
+is not used.
+.Pp
+The user is prompted for a password which must be the conventional password
+and the one-time password from the YubiKey without any separators inbetween.
+.Pp
+The conventional password is validated as per
+.Xr login_passwd 8
+and the one-time password is validated as per
+.Xr login_yubikey 8 .
+.El
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr login.conf 5 ,
+.Xr login_passwd 8 ,
+.Xr login_yubikey 8



Remi Locherer

unread,
Jan 5, 2014, 7:11:12 AM1/5/14
to te...@openbsd.org
On Sat, Jan 04, 2014 at 10:55:39AM +0100, Remi Locherer wrote:
> This patch privides a new login style: yubikey-and-pwd. The idea is from
> login_totp-and-pwd from the login_oath port.
>
> I tried to keep the patch small and not touch to many things. But probably
> it would be bette to chang more stuff (eg: there are now two backchannels:
> *back from login_passwd.c and *f from login_yubikey.c).
>
> It's likely that I got something wrong - I'm a novice in progamming c ;)

New diff after feedback from Andres Perera. It removes these issues:
* decl after code
* c99 comment
* c99 dyn array, use malloc plz

Remi


Index: Makefile
===================================================================
RCS file: /cvs/src/libexec/Makefile,v
retrieving revision 1.54
diff -u -p -r1.54 Makefile
--- Makefile 4 Dec 2013 20:49:28 -0000 1.54
+++ Makefile 3 Jan 2014 23:54:18 -0000
@@ -5,8 +5,8 @@

SUBDIR= comsat fingerd ftpd getty ld.so lockspool login_chpass \
login_lchpass login_passwd login_radius login_reject \
- login_skey login_tis login_token login_yubikey mail.local \
- makewhatis rpc.rquotad rpc.rstatd rpc.rusersd rpc.rwalld \
+ login_skey login_tis login_token login_yubikey login_yubikey-and-pwd \
+ mail.local makewhatis rpc.rquotad rpc.rstatd rpc.rusersd rpc.rwalld \
rpc.sprayd rshd security spamd spamd-setup spamlogd talkd \
tcpd uucpd

Index: login_yubikey/login_yubikey.c
===================================================================
RCS file: /cvs/src/libexec/login_yubikey/login_yubikey.c,v
retrieving revision 1.8
diff -u -p -r1.8 login_yubikey.c
--- login_yubikey/login_yubikey.c 27 Nov 2013 21:25:25 -0000 1.8
+++ login_yubikey/login_yubikey.c 5 Jan 2014 12:01:11 -0000
@@ -54,6 +54,12 @@
#define AUTH_OK 0
#define AUTH_FAILED -1

+#ifdef PASSWD
+#include <util.h>
+#include <common.h>
+FILE *back = NULL;
+#endif
+
static const char *path = "/var/db/yubikey";

static int clean_string(const char *);
@@ -67,6 +73,14 @@ main(int argc, char *argv[])
char *username, *password = NULL;
char response[1024];

+#ifdef PASSWD
+ int password_pwd_len, cnt;
+ char *password_pwd = NULL;
+ char password_yubikey[44];
+ char *wheel = NULL, *class = NULL;
+ int lastchance = 0;
+#endif
+
setpriority(PRIO_PROCESS, 0, 0);
openlog(NULL, LOG_ODELAY, LOG_AUTH);

@@ -151,7 +165,45 @@ main(int argc, char *argv[])
}
}

+#ifndef PASSWD
ret = yubikey_login(username, password);
+#endif
+#ifdef PASSWD
+ back = f;
+
+ /* the string generated by yubikey is 44 bytes long */
+ password_pwd_len = strlen(password) - 44, cnt;
+
+ /* exit if password_pwd_len is to short */
+ if ( password_pwd_len < 0 ) {
+ syslog(LOG_INFO, "user %s: reject", username);
+ fprintf(f, "%s\n", BI_REJECT);
+ closelog();
+ return (EXIT_SUCCESS);
+ }
+
+ password_pwd = malloc(password_pwd_len + 1); /* +1 for \0 */
+
+ /* extract the password */
+ for ( cnt = 0 ; cnt < password_pwd_len ; cnt++ )
+ password_pwd[cnt] = password[cnt];
+ password_pwd[password_pwd_len] = '\0';
+
+ /* copy last 44 bytes (yubikey one-time password) */
+ for ( cnt = 0 ; cnt + password_pwd_len < strlen(password) ; cnt++ )
+ password_yubikey[cnt] = password[cnt+password_pwd_len];
+
+ ret = yubikey_login(username, password_yubikey);
+
+ /* only test the password if yubikey auth was successful */
+ if (ret == AUTH_OK)
+ ret = pwd_login(username, password_pwd, wheel, lastchance, class);
+
+ memset(password_yubikey, 0, strlen(password_yubikey));
+ memset(password_pwd, 0, strlen(password_pwd));
+ free(password_pwd);

Stuart Henderson

unread,
Jan 5, 2014, 7:26:49 AM1/5/14
to Remi Locherer, te...@openbsd.org
On 2014/01/05 13:10, Remi Locherer wrote:
> + /* only test the password if yubikey auth was successful */

This should be done even if Yubikey auth fails, to avoid disclosing
information due to timing.

Remi Locherer

unread,
Jan 5, 2014, 10:42:54 AM1/5/14
to te...@openbsd.org
On Sun, Jan 05, 2014 at 09:15:21PM +0900, Ryan McBride wrote:
> My wish is for something with this user functionality, but use the
> password to encrypt/decrypt the user.key file, via pbkdf2-ish function
> (like bioctl/softraid_crypto), to avoid having the key in plaintext on
> the disk. It's a bit trickier, as you'd need to handle password
> changes, but with the right metadata in the user.key file you could
> avoid having a separate binary for this (all handled cleanly by
> login_yubikey).


Yes, that would be nice. But I don't understand how it could work without an
extra tool to handle password changes.

Even without the encrypt/decrypt functionality a tool like ssh-keygen for
yubikey in base would be nice. It could be used to generate the key and id
file and write it to the yubikey.


> On Sat, Jan 04, 2014 at 10:55:39AM +0100, Remi Locherer wrote:

Remi Locherer

unread,
Jan 5, 2014, 1:24:16 PM1/5/14
to te...@openbsd.org
Good point! I changed it to this:

ret = pwd_login(username, password_pwd, wheel, lastchance, class);
ret_yubi = yubikey_login(username, password_yubikey);
if (ret_yubi != AUTH_OK)
ret = AUTH_FAILED;

This does not work because pwd_login writes directly to the back channel. To
make it work correct I would need to change login_passwd.c (maybe with
#ifdev YUBIKEY).

But I try to implement Ryan's idea instead with a passphrase that encrypts the
user.key file.

Kent R. Spillner

unread,
Jan 5, 2014, 8:22:11 PM1/5/14
to Remi Locherer, te...@openbsd.org
Still haven't tested, but I also saw:

> + password_pwd = malloc(password_pwd_len + 1); /* +1 for \0 */
> +
> + /* extract the password */
> + for ( cnt = 0 ; cnt < password_pwd_len ; cnt++ )
> + password_pwd[cnt] = password[cnt];
> + password_pwd[password_pwd_len] = '\0';


Use strlcpy, don't roll your own.


> + /* copy last 44 bytes (yubikey one-time password) */
> + for ( cnt = 0 ; cnt + password_pwd_len < strlen(password) ; cnt++ )
> + password_yubikey[cnt] = password[cnt+password_pwd_len];

If you made password_yubikey char[45] instead of char[44] then you could do:

char *temp = password + password_pwd_len;
strlcpy(password_yubikey, temp, 45);

Kent R. Spillner

unread,
Jan 5, 2014, 8:27:01 PM1/5/14
to Remi Locherer, te...@openbsd.org

> + /* the string generated by yubikey is 44 bytes long */
> + password_pwd_len = strlen(password) - 44, cnt;


Haven't tested your latest diff, but I think you have a copy-pasto here (", cnt").

Remi Locherer

unread,
Jan 6, 2014, 1:43:10 AM1/6/14
to Kent R. Spillner, te...@openbsd.org
On Sun, Jan 05, 2014 at 06:44:22PM -0600, Kent R. Spillner wrote:
> Still haven't tested, but I also saw:
>
> > + password_pwd = malloc(password_pwd_len + 1); /* +1 for \0 */
> > +
> > + /* extract the password */
> > + for ( cnt = 0 ; cnt < password_pwd_len ; cnt++ )
> > + password_pwd[cnt] = password[cnt];
> > + password_pwd[password_pwd_len] = '\0';
>
>
> Use strlcpy, don't roll your own.

Yes, that's better.

> > + /* copy last 44 bytes (yubikey one-time password) */
> > + for ( cnt = 0 ; cnt + password_pwd_len < strlen(password) ; cnt++ )
> > + password_yubikey[cnt] = password[cnt+password_pwd_len];
>
> If you made password_yubikey char[45] instead of char[44] then you could do:
>
> char *temp = password + password_pwd_len;
> strlcpy(password_yubikey, temp, 45);

This way I don't even have to copy the string. Having password_yubikey
pointing to the right position is sufficient.

New diff, but don't use it. It will log you in with a wrong one-time password
as long as the password is correct.


Index: Makefile
===================================================================
RCS file: /cvs/src/libexec/Makefile,v
retrieving revision 1.54
diff -u -p -r1.54 Makefile
--- Makefile 4 Dec 2013 20:49:28 -0000 1.54
+++ Makefile 3 Jan 2014 23:54:18 -0000
@@ -5,8 +5,8 @@

SUBDIR= comsat fingerd ftpd getty ld.so lockspool login_chpass \
login_lchpass login_passwd login_radius login_reject \
- login_skey login_tis login_token login_yubikey mail.local \
- makewhatis rpc.rquotad rpc.rstatd rpc.rusersd rpc.rwalld \
+ login_skey login_tis login_token login_yubikey login_yubikey-and-pwd \
+ mail.local makewhatis rpc.rquotad rpc.rstatd rpc.rusersd rpc.rwalld \
rpc.sprayd rshd security spamd spamd-setup spamlogd talkd \
tcpd uucpd

Index: login_yubikey/login_yubikey.c
===================================================================
RCS file: /cvs/src/libexec/login_yubikey/login_yubikey.c,v
retrieving revision 1.8
diff -u -p -r1.8 login_yubikey.c
--- login_yubikey/login_yubikey.c 27 Nov 2013 21:25:25 -0000 1.8
+++ login_yubikey/login_yubikey.c 6 Jan 2014 06:30:38 -0000
@@ -54,6 +54,12 @@
#define AUTH_OK 0
#define AUTH_FAILED -1

+#ifdef PASSWD
+#include <util.h>
+#include <common.h>
+FILE *back = NULL;
+#endif
+
static const char *path = "/var/db/yubikey";

static int clean_string(const char *);
@@ -67,6 +73,13 @@ main(int argc, char *argv[])
char *username, *password = NULL;
char response[1024];

+#ifdef PASSWD
+ int pwd_len, ret_yubi;
+ char *password_pwd = NULL, *password_yubikey = NULL;
+ char *wheel = NULL, *class = NULL;
+ int lastchance = 0;
+#endif
+
setpriority(PRIO_PROCESS, 0, 0);
openlog(NULL, LOG_ODELAY, LOG_AUTH);

@@ -151,7 +164,36 @@ main(int argc, char *argv[])
}
}

+#ifndef PASSWD
ret = yubikey_login(username, password);
+#endif
+#ifdef PASSWD
+ /*
+ * XXX this is bad because pwd_login writes to back and makes
+ * the login successful if pwd_login succeeds even if yubikey
+ * auth fails!
+ */
+ back = f;
+
+ /* the string generated by yubikey is 44 bytes + \0 */
+ pwd_len = strlen(password) - 44 + 1;
+ password_pwd = malloc(pwd_len);
+
+ /* extract the password */
+ strlcpy(password_pwd, password, pwd_len);
+
+ /* the yubikey one-time password is located right after the password */
+ password_yubikey = password + pwd_len;
+
+ ret = pwd_login(username, password_pwd, wheel, lastchance, class);
+ ret_yubi = yubikey_login(username, password_yubikey);
+ if (ret_yubi != AUTH_OK)
+ ret = AUTH_FAILED;
+
0 new messages