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 0 on success, non-zero 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_user_info_t *user_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: null state not supported for CRYPTOCard",
118 * Return a synchronous challenge.
119 * Returns 0 on success, non-zero otherwise.
122 cryptocard_challenge(const otp_user_info_t *user_info,
124 __attribute__ ((unused))
126 const char csd[OTP_MAX_CSD_LEN + 1],
127 char challenge[OTP_MAX_CHALLENGE_LEN + 1],
129 __attribute__ ((unused))
133 __attribute__ ((unused))
137 __attribute__ ((unused))
140 const char *log_prefix)
142 unsigned char output[8];
145 /* CRYPTOCard sync challenges are always 8 bytes. */
146 if (strlen(challenge) != 8)
149 /* run x99 once on the challenge */
150 if (otp_x99_mac(challenge, 8, output, user_info->keyblock, log_prefix))
153 /* convert the mac into the next challenge */
154 for (i = 0; i < 8; ++i) {
160 (void) memcpy(challenge, output, 8);
168 * Return the expected card response for a given challenge.
169 * Returns 0 on success, non-zero otherwise.
171 * The X9.9 MAC is used by CRYPTOcard in the following manner:
173 * 1. Convert the challenge to ASCII (eg "12345" -> 0x3132333435).
174 * We don't actually do a conversion, the challenge is already ASCII.
175 * Note that Secure Computing SafeWord Gold/Platinum tokens can use
176 * "raw" challenge bytes.
177 * 2. Use the challenge as the plaintext input to the X9.9 MAC algorithm.
179 * 3. Convert the 32 bit MAC to ASCII (eg 0x1234567f -> "1234567f").
180 * Note that SafeWord Gold/Platinum tokens can display a 64 bit MAC.
181 * 4. Possibly apply transformations on chars "a" thru "f".
182 * 5. Truncate the response for 7 digit display modes.
185 cryptocard_response(otp_user_info_t *user_info,
187 __attribute__ ((unused))
189 const char csd[OTP_MAX_CSD_LEN + 1],
190 const char challenge[OTP_MAX_CHALLENGE_LEN + 1],
191 char response[OTP_MAX_RESPONSE_LEN + 1],
192 const char *log_prefix)
194 unsigned char output[8];
196 const char *conversion;
199 if (otp_x99_mac(challenge, strlen(challenge), output,
200 user_info->keyblock, log_prefix) !=0)
203 /* Setup for step 4. */
204 if (user_info->featuremask & OTP_CF_DD)
205 conversion = otp_cc_dec_conversion;
207 conversion = otp_hex_conversion;
210 otp_keyblock2keystring(l_response, output, conversion);
211 (void) memcpy(response, l_response, 8);
215 if (user_info->featuremask & OTP_CF_R7)
216 (void) memmove(&response[3], &response[4], 5);
223 * Update rd (there is no csd for cryptocard).
224 * Returns 0 if succesful, -1 otherwise.
227 cryptocard_updatecsd(
229 __attribute__ ((unused))
231 const otp_user_info_t *user_info,
232 otp_user_state_t *user_state,
234 __attribute__ ((unused))
236 const char challenge[OTP_MAX_CHALLENGE_LEN + 1],
238 __attribute__ ((unused))
243 __attribute__ ((unused))
248 __attribute__ ((unused))
250 const char *log_prefix)
252 if (auth_rc == OTP_RC_OK)
253 user_state->rd[0] = '\0'; /* reset */
255 (void) sprintf(user_state->rd, "%" PRIx32,
256 (int32_t) ewin); /* rwindow candidate */
262 /* events can only go forward, so an auth can never be too early */
266 __attribute__ ((unused))
268 const otp_user_state_t *user_state,
270 __attribute__ ((unused))
272 const char challenge[OTP_MAX_CHALLENGE_LEN + 1],
274 __attribute__ ((unused))
276 const char *log_prefix)
283 * Determine if a window position if consecutive relative to a saved
284 * (rwindow candidate) window position, for rwindow override.
285 * user_state contains the previous auth position, twin and ewin the current.
286 * Returns 1 on success (consecutive), 0 otherwise.
289 cryptocard_isconsecutive(
290 const otp_user_info_t *user_info,
291 const otp_user_state_t *user_state,
293 __attribute__ ((unused))
297 const char *log_prefix)
299 int rcanewin; /* saved rwindow candidate window position */
301 /* extract the saved rwindow candidate position */
302 if (sscanf(user_state->rd, "%" SCNx32, &rcanewin) != 1) {
303 otp_log(OTP_LOG_ERR, "%s: %s: invalid rwindow data for [%s]", log_prefix,
304 __func__, user_info->username);
308 /* Is this the next passcode? */
309 if (ewin == rcanewin + 1)
316 /* no twin so just return 0 */
320 __attribute__ ((unused))
322 const otp_user_info_t *user_info,
324 __attribute__ ((unused))
326 const char csd[OTP_MAX_CSD_LEN + 1])
332 /* cardops instance */
333 static cardops_t cryptocard_cardops = {
334 .prefix = "cryptocard",
335 .prefix_len = 10, /* strlen("cryptocard") */
337 .name2fm = cryptocard_name2fm,
338 .keystring2keyblock = cryptocard_keystring2keyblock,
339 .nullstate = cryptocard_nullstate,
340 .challenge = cryptocard_challenge,
341 .response = cryptocard_response,
342 .updatecsd = cryptocard_updatecsd,
343 .isearly = cryptocard_isearly,
344 .isconsecutive = cryptocard_isconsecutive,
345 .maxtwin = cryptocard_maxtwin,
351 cryptocard_init(void)
353 if (otp_num_cardops == OTP_MAX_VENDORS) {
354 otp_log(OTP_LOG_ERR, "cryptocard_init: module limit exceeded");
358 otp_cardops[otp_num_cardops++] = cryptocard_cardops;
359 otp_log(OTP_LOG_DEBUG, "cryptocard_init: loaded");