3
* $Id: cryptocard.c,v 1.39.2.1 2005/12/08 01:30:54 fcusack Exp $
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
* Copyright 2005 TRI-D Systems, Inc.
27
#include "../otp_cardops.h"
28
#include "cryptocard.h"
30
/* Card name to feature mask mappings */
35
{ "cryptocard-h8-rc", CRYPTOCARD_H8_RC },
36
{ "cryptocard-d8-rc", CRYPTOCARD_D8_RC },
37
{ "cryptocard-h7-rc", CRYPTOCARD_H7_RC },
38
{ "cryptocard-d7-rc", CRYPTOCARD_D7_RC },
39
{ "cryptocard-h8-es", CRYPTOCARD_H8_ES },
40
{ "cryptocard-d8-es", CRYPTOCARD_D8_ES },
41
{ "cryptocard-h7-es", CRYPTOCARD_H7_ES },
42
{ "cryptocard-d7-es", CRYPTOCARD_D7_ES },
43
{ "cryptocard-h8-rs", CRYPTOCARD_H8_RS },
44
{ "cryptocard-d8-rs", CRYPTOCARD_D8_RS },
45
{ "cryptocard-h7-rs", CRYPTOCARD_H7_RS },
46
{ "cryptocard-d7-rs", CRYPTOCARD_D7_RS },
48
{ NULL, 0 } /* end of list */
53
* Convert card name to feature mask.
54
* Returns 0 on success, non-zero otherwise.
57
cryptocard_name2fm(const char *name, uint32_t *featuremask)
61
for (i = 0; card[i].name; ++i) {
62
if (!strcasecmp(name, card[i].name)) {
63
*featuremask = card[i].fm;
72
* Convert an ASCII keystring to a keyblock.
73
* Returns keylen on success, -1 otherwise.
76
cryptocard_keystring2keyblock(const char *keystring,
77
unsigned char keyblock[OTP_MAX_KEY_LEN])
79
/* 64-bit DES key with optional line ending */
80
if ((strlen(keystring) & ~1) != 16)
83
return otp_keystring2keyblock(keystring, keyblock);
89
* We don't currently support nullstate for CRYPTOCard, so return -1.
94
__attribute__ ((unused))
96
const otp_option_t *opt,
98
__attribute__ ((unused))
100
const otp_card_info_t *card_info,
102
__attribute__ ((unused))
104
otp_user_state_t *user_state,
106
__attribute__ ((unused))
109
const char *log_prefix)
111
otp_log(OTP_LOG_ERR, "%s: %s: null state not supported for CRYPTOCard",
112
log_prefix, __func__);
118
* Return a synchronous challenge.
119
* Returns 0 on success, -1 otherwise.
120
* (-2 rc is for early challenge, N/A for cryptocard.)
123
cryptocard_challenge(const otp_card_info_t *card_info,
124
otp_user_state_t *user_state,
125
unsigned char challenge[OTP_MAX_CHALLENGE_LEN],
127
__attribute__ ((unused))
131
__attribute__ ((unused))
135
__attribute__ ((unused))
138
const char *log_prefix)
140
unsigned char output[8];
143
/* run x99 once on the previous challenge */
144
if (otp_x99_mac(challenge, user_state->clen, output, card_info->keyblock,
148
/* convert the mac into the next challenge */
149
for (i = 0; i < 8; ++i) {
155
(void) memcpy(challenge, output, 8);
156
user_state->clen = 8;
163
* Return the expected card response for a given challenge.
164
* Returns 0 on success, non-zero otherwise.
166
* The X9.9 MAC is used by CRYPTOcard in the following manner:
168
* 1. Convert the challenge to ASCII (eg "12345" -> 0x3132333435).
169
* We don't actually do a conversion, the challenge is already ASCII.
170
* Note that Secure Computing SafeWord Gold/Platinum tokens can use
171
* "raw" challenge bytes.
172
* 2. Use the challenge as the plaintext input to the X9.9 MAC algorithm.
174
* 3. Convert the 32 bit MAC to ASCII (eg 0x1234567f -> "1234567f").
175
* Note that SafeWord Gold/Platinum tokens can display a 64 bit MAC.
176
* 4. Possibly apply transformations on chars "a" thru "f".
177
* 5. Truncate the response for 7 digit display modes.
180
cryptocard_response(otp_card_info_t *card_info,
181
const unsigned char challenge[OTP_MAX_CHALLENGE_LEN],
182
size_t len, char response[OTP_MAX_RESPONSE_LEN + 1],
183
const char *log_prefix)
185
unsigned char output[8];
186
const char *conversion;
189
if (otp_x99_mac(challenge, len, output,
190
card_info->keyblock, log_prefix) !=0)
193
/* Setup for step 4. */
194
if (card_info->featuremask & OTP_CF_DD)
195
conversion = otp_cc_dec_conversion;
197
conversion = otp_hex_conversion;
200
(void) otp_keyblock2keystring(response, output, 4, conversion);
203
if (card_info->featuremask & OTP_CF_R7)
204
(void) memmove(&response[3], &response[4], 5);
211
* Update rd (there is no csd for cryptocard).
212
* Returns 0 if succesful, -1 otherwise.
215
cryptocard_updatecsd(otp_user_state_t *user_state,
217
__attribute__ ((unused))
221
__attribute__ ((unused))
227
if (auth_rc == OTP_RC_OK)
228
user_state->rd[0] = '\0'; /* reset */
230
(void) sprintf(user_state->rd, "%" PRIx32,
231
(int32_t) ewin); /* rwindow candidate */
238
* Determine if a window position if consecutive relative to a saved
239
* (rwindow candidate) window position, for rwindow override.
240
* user_state contains the previous auth position, twin and ewin the current.
241
* Returns 1 on success (consecutive), 0 otherwise.
244
cryptocard_isconsecutive(
246
__attribute__ ((unused))
248
const otp_card_info_t *card_info,
249
const otp_user_state_t *user_state,
250
int thisewin, const char *log_prefix)
254
/* extract the saved rwindow candidate position */
255
if (sscanf(user_state->rd, "%" SCNx32, &nextewin) != 1) {
256
otp_log(OTP_LOG_ERR, "%s: %s: invalid rwindow data for [%s]",
257
log_prefix, __func__, card_info->username);
262
/* Is this the next passcode? */
263
if (thisewin == nextewin)
270
/* no twin so just return 0 */
274
__attribute__ ((unused))
276
const otp_card_info_t *card_info,
278
__attribute__ ((unused))
280
const char csd[OTP_MAX_CSD_LEN + 1])
286
/* return human-readable challenge */
288
cryptocard_printchallenge(char s[OTP_MAX_CHALLENGE_LEN * 2 + 1],
289
const unsigned char challenge[OTP_MAX_CHALLENGE_LEN],
292
/* cryptocard challenge is implicitly ASCII */
293
(void) memcpy(s, challenge, len);
299
/* cardops instance */
300
static cardops_t cryptocard_cardops = {
301
.prefix = "cryptocard",
302
.prefix_len = 10, /* strlen("cryptocard") */
304
.name2fm = cryptocard_name2fm,
305
.keystring2keyblock = cryptocard_keystring2keyblock,
306
.nullstate = cryptocard_nullstate,
307
.challenge = cryptocard_challenge,
308
.response = cryptocard_response,
309
.updatecsd = cryptocard_updatecsd,
310
.isconsecutive = cryptocard_isconsecutive,
311
.maxtwin = cryptocard_maxtwin,
312
.printchallenge = cryptocard_printchallenge,
318
cryptocard_init(void)
320
if (otp_num_cardops == OTP_MAX_VENDORS) {
321
otp_log(OTP_LOG_ERR, "cryptocard_init: module limit exceeded");
325
otp_cardops[otp_num_cardops++] = cryptocard_cardops;
326
otp_log(OTP_LOG_DEBUG, "cryptocard_init: loaded");