GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/tokeninit/../../libexec/login_token/token.c Lines: 0 126 0.0 %
Date: 2017-11-07 Branches: 0 60 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: token.c,v 1.19 2015/10/05 17:31:17 millert Exp $	*/
2
3
/*-
4
 * Copyright (c) 1995 Migration Associates Corp. All Rights Reserved
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. All advertising materials mentioning features or use of this software
15
 *    must display the following acknowledgement:
16
 *      This product includes software developed by Berkeley Software Design,
17
 *      Inc.
18
 * 4. The name of Berkeley Software Design, Inc.  may not be used to endorse
19
 *    or promote products derived from this software without specific prior
20
 *    written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
23
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
 * ARE DISCLAIMED.  IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
26
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
 * SUCH DAMAGE.
33
 *
34
 *	BSDI $From: token.c,v 1.2 1996/08/28 22:07:55 prb Exp $
35
 */
36
37
/*
38
 * DES functions for one-way encrypting Authentication Tokens.
39
 * All knowledge of DES is confined to this file.
40
 */
41
42
#include <sys/types.h>
43
#include <sys/time.h>
44
#include <sys/resource.h>
45
46
#include <ctype.h>
47
#include <stdio.h>
48
#include <syslog.h>
49
#include <limits.h>
50
#include <stdlib.h>
51
#include <string.h>
52
#include <unistd.h>
53
#include <openssl/des.h>
54
55
#include "token.h"
56
#include "tokendb.h"
57
58
/*
59
 * Define a union of various types of arguments to DES functions.
60
 * All native DES types are modulo 8 bytes in length. Cipher text
61
 * needs a trailing null byte.
62
 */
63
64
typedef	union {
65
	DES_cblock	cb;
66
	char		ct[9];
67
	uint32_t	ul[2];
68
} TOKEN_CBlock;
69
70
/*
71
 * Static definition of random number challenge for token.
72
 * Challenge length is 8 bytes, left-justified with trailing null byte.
73
 */
74
75
static	TOKEN_CBlock tokennumber;
76
77
/*
78
 * Static function prototypes
79
 */
80
81
static	void	tokenseed(TOKEN_CBlock *);
82
static	void	lcase(char *);
83
static	void	h2d(char *);
84
static	void	h2cb(char *, TOKEN_CBlock *);
85
static	void	cb2h(TOKEN_CBlock, char *);
86
87
/*
88
 * Generate random DES cipherblock seed. Feedback key into
89
 * new_random_key to strengthen.
90
 */
91
92
static void
93
tokenseed(TOKEN_CBlock *cb)
94
{
95
	cb->ul[0] = arc4random();
96
	cb->ul[1] = arc4random();
97
}
98
99
/*
100
 * Send a random challenge string to the token. The challenge
101
 * is always base 10 as there are no alpha keys on the keyboard.
102
 */
103
104
void
105
tokenchallenge(char *user, char *challenge, int size, char *card_type)
106
{
107
	TOKENDB_Rec tr;
108
	TOKEN_CBlock cb;
109
	DES_key_schedule ks;
110
	int r, c;
111
112
	r = 1;	/* no reduced input mode by default! */
113
114
	if ((tt->modes & TOKEN_RIM) &&
115
	    tokendb_getrec(user, &tr) == 0 &&
116
	    (tr.mode & TOKEN_RIM)) {
117
		c = 0;
118
		while ((r = tokendb_lockrec(user, &tr, TOKEN_LOCKED)) == 1) {
119
			if (c++ >= 60)
120
				break;
121
			sleep(1);
122
		}
123
		tr.flags &= ~TOKEN_LOCKED;
124
		if (r == 0 && tr.rim[0]) {
125
			h2cb(tr.secret, &cb);
126
			DES_fixup_key_parity(&cb.cb);
127
			DES_key_sched(&cb.cb, &ks);
128
			DES_ecb_encrypt(&tr.rim, &cb.cb, &ks, DES_ENCRYPT);
129
			memcpy(tr.rim, cb.cb, 8);
130
			for (r = 0; r < 8; ++r) {
131
				if ((tr.rim[r] &= 0xf) > 9)
132
					tr.rim[r] -= 10;
133
				tr.rim[r] |= 0x30;
134
			}
135
			r = 0;		/* reset it back */
136
			memcpy(tokennumber.ct, tr.rim, 8);
137
			tokennumber.ct[8] = 0;
138
			tokendb_putrec(user, &tr);
139
		}
140
	}
141
	if (r != 0 || tr.rim[0] == '\0') {
142
		memset(tokennumber.ct, 0, sizeof(tokennumber.ct));
143
		snprintf(tokennumber.ct, sizeof(tokennumber.ct), "%8.8u",
144
		    arc4random());
145
		if (r == 0) {
146
			memcpy(tr.rim, tokennumber.ct, 8);
147
			tokendb_putrec(user, &tr);
148
		}
149
	}
150
151
	snprintf(challenge, size, "%s Challenge \"%s\"\r\n%s Response: ",
152
	    card_type, tokennumber.ct, card_type);
153
}
154
155
/*
156
 * Verify response from user against token's predicted cipher
157
 * of the random number challenge.
158
 */
159
160
int
161
tokenverify(char *username, char *challenge, char *response)
162
{
163
	char	*state;
164
	TOKENDB_Rec tokenrec;
165
	TOKEN_CBlock tmp;
166
	TOKEN_CBlock cmp_text;
167
	TOKEN_CBlock user_seed;
168
	TOKEN_CBlock cipher_text;
169
	DES_key_schedule key_schedule;
170
171
172
	memset(cmp_text.ct, 0, sizeof(cmp_text.ct));
173
	memset(user_seed.ct, 0, sizeof(user_seed.ct));
174
	memset(cipher_text.ct, 0, sizeof(cipher_text.ct));
175
	memset(tokennumber.ct, 0, sizeof(tokennumber.ct));
176
177
	(void)strtok(challenge, "\"");
178
	state = strtok(NULL, "\"");
179
	tmp.ul[0] = strtoul(state, NULL, 10);
180
	snprintf(tokennumber.ct, sizeof(tokennumber.ct), "%8.8u",tmp.ul[0]);
181
182
	/*
183
	 * Retrieve the db record for the user. Nuke it as soon as
184
	 * we have translated out the user's shared secret just in
185
	 * case we (somehow) get core dumped...
186
	 */
187
188
	if (tokendb_getrec(username, &tokenrec))
189
		return (-1);
190
191
	h2cb(tokenrec.secret, &user_seed);
192
	explicit_bzero(&tokenrec.secret, sizeof(tokenrec.secret));
193
194
	if (!(tokenrec.flags & TOKEN_ENABLED))
195
		return (-1);
196
197
	/*
198
	 * Compute the anticipated response in hex. Nuke the user's
199
	 * shared secret asap.
200
	 */
201
202
	DES_fixup_key_parity(&user_seed.cb);
203
	DES_key_sched(&user_seed.cb, &key_schedule);
204
	explicit_bzero(user_seed.ct, sizeof(user_seed.ct));
205
	DES_ecb_encrypt(&tokennumber.cb, &cipher_text.cb, &key_schedule,
206
	    DES_ENCRYPT);
207
	explicit_bzero(&key_schedule, sizeof(key_schedule));
208
209
	/*
210
	 * The token thinks it's descended from VAXen.  Deal with i386
211
	 * endian-ness of binary cipher prior to generating ascii from first
212
	 * 32 bits.
213
	 */
214
215
	HTONL(cipher_text.ul[0]);
216
	snprintf(cmp_text.ct, sizeof(cmp_text.ct), "%8.8x", cipher_text.ul[0]);
217
218
	if (tokenrec.mode & TOKEN_PHONEMODE) {
219
		/*
220
		 * If we are a CRYPTOCard, we need to see if we are in
221
		 * "telephone number mode".  If so, transmogrify the fourth
222
		 * digit of the cipher.  Lower case response just in case
223
		 * it's * hex.  Compare hex cipher with anticipated response
224
		 * from token.
225
		 */
226
227
		lcase(response);
228
229
		if (response[3] == '-')
230
			cmp_text.ct[3] = '-';
231
	}
232
233
	if ((tokenrec.mode & TOKEN_HEXMODE) && !strcmp(response, cmp_text.ct))
234
		return (0);
235
236
	/*
237
	 * No match against the computed hex cipher.  The token could be
238
	 * in decimal mode.  Pervert the string to magic decimal equivalent.
239
	 */
240
241
	h2d(cmp_text.ct);
242
243
	if ((tokenrec.mode & TOKEN_DECMODE) && !strcmp(response, cmp_text.ct))
244
		return (0);
245
246
	return (-1);
247
}
248
249
/*
250
 * Initialize a new user record in the token database.
251
 */
252
253
int
254
tokenuserinit(int flags, char *username, unsigned char *usecret, unsigned mode)
255
{
256
	TOKENDB_Rec tokenrec;
257
	TOKEN_CBlock secret;
258
	TOKEN_CBlock nulls;
259
	TOKEN_CBlock checksum;
260
	TOKEN_CBlock checktxt;
261
	DES_key_schedule key_schedule;
262
263
	memset(&secret, 0, sizeof(secret));
264
265
	/*
266
	 * If no user secret passed in, create one
267
	 */
268
269
	if ( (flags & TOKEN_GENSECRET) )
270
		tokenseed(&secret);
271
	else
272
		memcpy(&secret, usecret, sizeof(DES_cblock));
273
274
	DES_fixup_key_parity(&secret.cb);
275
276
	/*
277
	 * Check if the db record already exists.  If there's no
278
	 * force-init flag and it exists, go away. Else,
279
	 * create the user's db record and put to the db.
280
	 */
281
282
283
	if (!(flags & TOKEN_FORCEINIT) &&
284
	    tokendb_getrec(username, &tokenrec) == 0)
285
		return (1);
286
287
	memset(&tokenrec, 0, sizeof(tokenrec));
288
	strlcpy(tokenrec.uname, username, sizeof(tokenrec.uname));
289
	cb2h(secret, tokenrec.secret);
290
	tokenrec.mode = 0;
291
	tokenrec.flags = TOKEN_ENABLED | TOKEN_USEMODES;
292
	tokenrec.mode = mode;
293
	memset(tokenrec.reserved_char1, 0, sizeof(tokenrec.reserved_char1));
294
	memset(tokenrec.reserved_char2, 0, sizeof(tokenrec.reserved_char2));
295
296
	if (tokendb_putrec(username, &tokenrec))
297
		return (-1);
298
299
	/*
300
	 * Check if the shared secret was generated here. If so, we
301
	 * need to inform the user about it in order that it can be
302
	 * programmed into the token. See tokenverify() (above) for
303
	 * discussion of cipher generation.
304
	 */
305
306
	if (!(flags & TOKEN_GENSECRET)) {
307
		explicit_bzero(&secret, sizeof(secret));
308
		return (0);
309
	}
310
311
	printf("Shared secret for %s\'s token: "
312
	    "%03o %03o %03o %03o %03o %03o %03o %03o\n",
313
	    username, secret.cb[0], secret.cb[1], secret.cb[2], secret.cb[3],
314
	    secret.cb[4], secret.cb[5], secret.cb[6], secret.cb[7]);
315
316
	DES_key_sched(&secret.cb, &key_schedule);
317
	explicit_bzero(&secret, sizeof(secret));
318
	memset(&nulls, 0, sizeof(nulls));
319
	DES_ecb_encrypt(&nulls.cb, &checksum.cb, &key_schedule, DES_ENCRYPT);
320
	explicit_bzero(&key_schedule, sizeof(key_schedule));
321
	HTONL(checksum.ul[0]);
322
	snprintf(checktxt.ct, sizeof(checktxt.ct), "%8.8x", checksum.ul[0]);
323
	printf("Hex Checksum: \"%s\"", checktxt.ct);
324
325
	h2d(checktxt.ct);
326
	printf("\tDecimal Checksum: \"%s\"\n", checktxt.ct);
327
328
	return (0);
329
}
330
331
/*
332
 * Magically transform a hex character string into a decimal character
333
 * string as defined by the token card vendor. The string should have
334
 * been lowercased by now.
335
 */
336
337
static	void
338
h2d(char *cp)
339
{
340
	int	i;
341
342
	for (i=0; i<sizeof(DES_cblock); i++, cp++) {
343
		if (*cp >= 'a' && *cp <= 'f')
344
			*cp = tt->map[*cp - 'a'];
345
	}
346
}
347
348
/*
349
 * Translate an hex 16 byte ascii representation of an unsigned
350
 * integer to a DES_cblock.
351
 */
352
353
static	void
354
h2cb(char *hp, TOKEN_CBlock *cb)
355
{
356
	char	scratch[9];
357
358
	strlcpy(scratch, hp, sizeof(scratch));
359
	cb->ul[0] = strtoul(scratch, NULL, 16);
360
361
	strlcpy(scratch, hp + 8, sizeof(scratch));
362
	cb->ul[1] = strtoul(scratch, NULL, 16);
363
}
364
365
/*
366
 * Translate a DES_cblock to an 16 byte ascii hex representation.
367
 */
368
369
static	void
370
cb2h(TOKEN_CBlock cb, char* hp)
371
{
372
	char	scratch[17];
373
374
	snprintf(scratch,   9, "%8.8x", cb.ul[0]);
375
	snprintf(scratch+8, 9, "%8.8x", cb.ul[1]);
376
	memcpy(hp, scratch, 16);
377
}
378
379
/*
380
 * Lowercase possible hex response
381
 */
382
383
static	void
384
lcase(char *cp)
385
{
386
	while (*cp) {
387
		if (isupper((unsigned char)*cp))
388
			*cp = tolower((unsigned char)*cp);
389
		cp++;
390
	}
391
}