Skip to content

Commit

Permalink
Add for TOTP and Feitian c200 support
Browse files Browse the repository at this point in the history
git-svn-id: http://otpd.googlecode.com/svn/trunk@74 1a59f654-b740-11de-97ce-e783fd196cab
  • Loading branch information
gpaterno committed Nov 26, 2010
1 parent dbcc580 commit 44c7b78
Show file tree
Hide file tree
Showing 7 changed files with 621 additions and 3 deletions.
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
otpd-3.2.7: 2010/11/26
- Addedd TOTP algorithm
- Addedd support for the Feitian c200, which seems to have a small TOTP difference

otpd-3.1.0: 2008/02/11
- gsmd: add support for gsmd backup server and failover
- gsmd: fix request type field in gsmd message
Expand Down
4 changes: 3 additions & 1 deletion README
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
This README file is from the original project coming off TRI-D Systems.
This OTPD is now forked from the original code, you can find all the details
in http://otpd.googlecode.com.
on the website http://otpd.googlecode.com.

Copyright 2009-2010 Giuseppe Paterno' (gpaterno@gpaterno.com)

-------------------------------------------------------------------------
0. INTRODUCTION
Expand Down
227 changes: 227 additions & 0 deletions cardops/c200.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
/*
* c200.c
*
* A TOTP implementation for the Feitian c200, that is not fully
* compliant with the standard.
* Generation time is 60 seconds and time is rounded to the next minute.
*
* This file has been generated from the cardops/hotp.c, originally created
* by TRI-D Systems
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
*
* Copyright 2010 Giuseppe Paterno' (gpaterno@gpaterno.com)
* Copyright 2006,2007 TRI-D Systems, Inc.
*/

#include "../ident.h"

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>

#include "../extern.h"
#include "../otp.h"
#include "../cardops.h"
#include "c200.h"

/* Card name to feature mask mappings */
static struct {
const char *name;
uint32_t fm;
} card[] = {
{ "c200-d6", HOTP6 }, /* 6 digit response */
{ "c200-d7", HOTP7 }, /* 7 digit response */
{ "c200-d8", HOTP8 }, /* 8 digit response */

{ NULL, 0 } /* end of list */
};

static void
c2c(uint64_t counter, unsigned char challenge[8])
{
challenge[0] = counter >> 56;
challenge[1] = counter >> 48;
challenge[2] = counter >> 40;
challenge[3] = counter >> 32;
challenge[4] = counter >> 24;
challenge[5] = counter >> 16;
challenge[6] = counter >> 8;
challenge[7] = counter;
}


/*
* Convert card name to feature mask.
* Returns 0 on success, non-zero otherwise.
*/
static int
c200_name2fm(user_t *user, __unused__ state_t *state)
{
int i;

for (i = 0; card[i].name; ++i) {
if (!strcasecmp(user->card, card[i].name)) {
user->featuremask = card[i].fm;
return 0;
}
}
return 1;
}

/*
* Convert an ASCII keystring to a key.
* Returns keylen on success, -1 otherwise.
*/
static int
c200_keystring2key(user_t *user, state_t *state)
{
size_t l = strlen(user->keystring);

/* min 128-bit key */
if (l < 32)
return -1;

state->scratch1 = l/2; /* save keylen for hotp_response() */
return a2nx(user->keystring, user->key, state->scratch1);
}

/*
* Who cares about nullstate? We use time :)
*/
static int
c200_nullstate(__unused__ const config_t *config,__unused__ const user_t *user,
__unused__ state_t *state, __unused__ time_t when)
{
return 0;
}

/*
* Return a synchronous challenge.
* Returns 0 on success, -1 otherwise.
* (we return -1)
*/
static int
c200_challenge(const user_t *user, state_t *state,
unsigned char challenge[OTP_MAX_CHALLENGE_LEN],
__unused__ time_t when, __unused__ int twin,__unused__ int ewin)
{
return 0;
}

/*
* Return the expected card response for a given challenge.
* Returns 0 on success, non-zero otherwise.
*/
static int
c200_response(const user_t *user, state_t *state,
__unused__ const unsigned char challenge[OTP_MAX_CHALLENGE_LEN],
__unused__ size_t len, char response[OTP_MAX_RESPONSE_LEN + 1])
{
time_t t;
long t_rounding;
uint64_t iv;
unsigned char mychallenge[8];

/* This is actually a bug of the Feitian c200 implementation
* Get the time in seconds from unix birth,
* then get the difference in seconds to the next available minute (60 seconds)
* using a modulus and add it to the standard seconds (t + t_rounding)
* At the end, divide by the time step (c200 is 60 seconds).
*/

t = time(NULL);
t_rounding = 60 - (t % 60);
iv = ((int) (t + t_rounding)) / TIME_STEP;

mlog(LOG_DEBUG1, "c200: iv is set to %lu", iv);

c2c(iv, mychallenge);

return hotp_mac(mychallenge, response, user->key, state->scratch1,
(user->featuremask & OTP_CF_LEN) >> OTP_CF_LEN_SHIFT);
}

/*
* No sync mode, it's time based ;-)
* Returns 0, let it seems it's ok (fake response)
*/
static int
c200_updatecsd(state_t *state, __unused__ time_t when,
__unused__ int twin, int ewin, int auth_rc)
{
return 0;
}

/*
* Determine if a window position if consecutive relative to a saved
* (rwindow candidate) window position, for rwindow override.
* Since we don't have a sync mode, this is never called.
* Just return 0 (not consecutive).
*/
static int
c200_isconsecutive(const user_t *user, state_t *state, int thisewin)
{
return 1;
}

/* no twin so just return 0 */
static int
c200_maxtwin(__unused__ const user_t *user, __unused__ state_t *state,
__unused__ time_t when)
{
return 0;
}

/* return human-readable challenge */
static char *
c200_printchallenge(char s[OTP_MAX_CHALLENGE_LEN * 2 + 1],
const unsigned char challenge[OTP_MAX_CHALLENGE_LEN],
size_t len)
{
return x2a(challenge, len, s, x2a_hex_conversion);
}

/* cardops instance */
static cardops_t c200_cardops = {
.prefix = "c200",
.plen = 4, /* strlen("hotp") */

.name2fm = c200_name2fm,
.keystring2key = c200_keystring2key,
.nullstate = c200_nullstate,
.challenge = c200_challenge,
.response = c200_response,
.updatecsd = c200_updatecsd,
.isconsecutive = c200_isconsecutive,
.maxtwin = c200_maxtwin,
.printchallenge = c200_printchallenge,
};

/* constructor */
void
c200_init(void)
{
if (ncardops == OTP_MAX_VENDORS) {
mlog(LOG_CRIT, "c200_init: module limit exceeded");
exit(1);
}

cardops[ncardops++] = c200_cardops;
}
81 changes: 81 additions & 0 deletions cardops/c200.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* c200.h
*
* A TOTP implementation for the Feitian c200, that is not fully
* compliant with the standard.
* Generation time is 60 seconds and time is rounded to the next minute.
*
* This file has been generated from the cardops/hotp.c, originally created
* by TRI-D Systems
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
*
* Copyright 2010 Giuseppe Paterno' (gpaterno@gpaterno.com)
* Copyright 2006,2007 TRI-D Systems, Inc.
*/

#ifndef CARDOPS_HOTP_H
#define CARDOPS_HOTP_H

#include "../ident.h"

#include <inttypes.h>
#include <sys/types.h>

#include "../extern.h"
#include "../otp.h"
#include "../cardops.h"

/* Time step */
#define TIME_STEP 60

/* card modes */
#define HOTP_CF_LEN5 (OTP_CF_LEN2|OTP_CF_LEN0)
#define HOTP_CF_LEN6 (OTP_CF_LEN2|OTP_CF_LEN1)
#define HOTP_CF_LEN7 (OTP_CF_LEN2|OTP_CF_LEN1|OTP_CF_LEN0)
#define HOTP_CF_LEN8 OTP_CF_LEN3
#define HOTP_CF_LEN9 (OTP_CF_LEN3|OTP_CF_LEN0)

#define HOTP5 (OTP_CF_ES|HOTP_CF_LEN5)
#define HOTP6 (OTP_CF_ES|HOTP_CF_LEN6)
#define HOTP7 (OTP_CF_ES|HOTP_CF_LEN7)
#define HOTP8 (OTP_CF_ES|HOTP_CF_LEN8)
#define HOTP9 (OTP_CF_ES|HOTP_CF_LEN9)

static int c200_name2fm(user_t *, state_t *);
static int c200_keystring2key(user_t *, state_t *);
static int c200_nullstate(const config_t *, const user_t *, state_t *, time_t);
static int c200_challenge(const user_t *, state_t *,
unsigned char [OTP_MAX_CHALLENGE_LEN], time_t,
int, int);
static int c200_response(const user_t *, state_t *,
const unsigned char [OTP_MAX_CHALLENGE_LEN],
size_t, char [OTP_MAX_RESPONSE_LEN + 1]);
static int c200_updatecsd(state_t *, time_t, int, int, int);
static int c200_isconsecutive(const user_t *, state_t *, int);
static int c200_maxtwin(const user_t *, state_t *, time_t);
static char *c200_printchallenge(char [OTP_MAX_CHALLENGE_LEN * 2 + 1],
const unsigned char [OTP_MAX_CHALLENGE_LEN],
size_t);

#if defined(__GNUC__)
__attribute__ ((constructor))
#elif defined(__SUNPRO_C)
#pragma init(c200_init)
#endif
void c200_init(void);

#endif /* CARDOPS_HOTP_H */
Loading

0 comments on commit 44c7b78

Please sign in to comment.