GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: libexec/login_yubikey/yubikey.c Lines: 0 128 0.0 %
Date: 2017-11-07 Branches: 0 60 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: yubikey.c,v 1.6 2017/09/16 08:07:15 anton Exp $ */
2
3
/*
4
 * Written by Simon Josefsson <simon@josefsson.org>.
5
 * Copyright (c) 2006, 2007, 2008, 2009 Yubico AB
6
 * Copyright (c) 2010 Daniel Hartmeier <daniel@benzedrine.cx>
7
 * All rights reserved.
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions are
11
 * met:
12
 *
13
 * * Redistributions of source code must retain the above copyright
14
 *   notice, this list of conditions and the following disclaimer.
15
 *
16
 * * Redistributions in binary form must reproduce the above
17
 *   copyright notice, this list of conditions and the following
18
 *   disclaimer in the documentation and/or other materials provided
19
 *   with the distribution.
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
 *
33
 */
34
35
#include <ctype.h>
36
#include <stdlib.h>
37
#include <wchar.h>
38
#include <locale.h>
39
#include <errno.h>
40
41
#include "yubikey.h"
42
#include "keymaps.h"
43
44
static const uint8_t RC[] = {
45
	0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
46
};
47
48
static const uint8_t rijndael_sbox[] = {
49
	0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5,
50
	0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
51
	0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
52
	0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
53
	0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
54
	0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
55
	0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A,
56
	0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
57
	0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
58
	0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
59
	0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B,
60
	0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
61
	0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85,
62
	0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
63
	0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
64
	0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
65
	0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17,
66
	0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
67
	0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88,
68
	0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
69
	0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
70
	0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
71
	0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9,
72
	0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
73
	0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
74
	0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
75
	0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
76
	0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
77
	0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94,
78
	0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
79
	0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68,
80
	0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
81
};
82
83
static const uint8_t rijndael_inv_sbox[] = {
84
	0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38,
85
	0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
86
	0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
87
	0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
88
	0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D,
89
	0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
90
	0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2,
91
	0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
92
	0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
93
	0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
94
	0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA,
95
	0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
96
	0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A,
97
	0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
98
	0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
99
	0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
100
	0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA,
101
	0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
102
	0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85,
103
	0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
104
	0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
105
	0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
106
	0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20,
107
	0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
108
	0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31,
109
	0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
110
	0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
111
	0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
112
	0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0,
113
	0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
114
	0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26,
115
	0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
116
};
117
118
static inline uint8_t
119
xtime(uint8_t b)
120
{
121
	return (b & 0x80) ? ((b << 1) ^ 0x1b) : (b << 1);
122
}
123
124
#define NUMBER_OF_ROUNDS 10
125
126
void
127
yubikey_aes_decrypt(uint8_t *state, const uint8_t *key)
128
{
129
	uint8_t i, j, round_key[0x10];
130
	uint8_t a02x, a13x;
131
	uint8_t a02xx, a13xx;
132
	uint8_t k1, k2;
133
134
	memcpy(round_key, key, sizeof(round_key));
135
	for (i = 0; i < NUMBER_OF_ROUNDS; i++) {
136
		round_key[0] ^= RC[i];
137
138
		round_key[0] ^= rijndael_sbox[round_key[13]];
139
		round_key[1] ^= rijndael_sbox[round_key[14]];
140
		round_key[2] ^= rijndael_sbox[round_key[15]];
141
		round_key[3] ^= rijndael_sbox[round_key[12]];
142
143
		for (j = 4; j < 16; j++)
144
			round_key[j] ^= round_key[j - 4];
145
	}
146
	for (i = 0; i < 0x10; i++)
147
		state[i] ^= round_key[i];
148
149
	for (i = 1; i <= NUMBER_OF_ROUNDS; i++) {
150
		/* inv_byte_sub_shift_row(); */
151
152
		/* First row: 0 shift, 0 4 8 12 */
153
		state[0] = rijndael_inv_sbox[state[0]];
154
		state[4] = rijndael_inv_sbox[state[4]];
155
		state[8] = rijndael_inv_sbox[state[8]];
156
		state[12] = rijndael_inv_sbox[state[12]];
157
158
		/* Second row: -1 shift, 1 5 9 13 */
159
		j = state[13];
160
		state[13] = rijndael_inv_sbox[state[9]];
161
		state[9] = rijndael_inv_sbox[state[5]];
162
		state[5] = rijndael_inv_sbox[state[1]];
163
		state[1] = rijndael_inv_sbox[j];
164
165
		/* Third row: -2 shift, 2 6 10 14 */
166
		j = state[2];
167
		state[2] = rijndael_inv_sbox[state[10]];
168
		state[10] = rijndael_inv_sbox[j];
169
		j = state[6];
170
		state[6] = rijndael_inv_sbox[state[14]];
171
		state[14] = rijndael_inv_sbox[j];
172
173
		/* Fourth row: -3 shift, 3 7 11 15 */
174
		j = state[3];
175
		state[3] = rijndael_inv_sbox[state[7]];
176
		state[7] = rijndael_inv_sbox[state[11]];
177
		state[11] = rijndael_inv_sbox[state[15]];
178
		state[15] = rijndael_inv_sbox[j];
179
180
		/* get_inv_round_key(i); */
181
182
		for (j = 15; j > 3; j--)
183
			round_key[j] ^= round_key[j - 4];
184
185
		round_key[0] ^= (RC[NUMBER_OF_ROUNDS - i] ^
186
		    rijndael_sbox[round_key[13]]);
187
188
		round_key[1] ^= rijndael_sbox[round_key[14]];
189
		round_key[2] ^= rijndael_sbox[round_key[15]];
190
		round_key[3] ^= rijndael_sbox[round_key[12]];
191
192
		for (j = 0; j < 16; j++)
193
			state[j] ^= round_key[j];
194
		if (i != NUMBER_OF_ROUNDS) {
195
			/* inv_mix_column(); */
196
197
			for (j = 0; j < 16; j += 4) {
198
				k1 = state[j] ^ state[j + 2];
199
				a02x = xtime(k1);
200
				k2 = state[j + 1] ^ state[j + 3];
201
				a13x = xtime(k2);
202
203
				k1 ^= (k2 ^ xtime(state[j + 1] ^ state[j + 2]));
204
				k2 = k1;
205
206
				a02xx = xtime(a02x);
207
				a13xx = xtime(a13x);
208
209
210
				k1 ^= (xtime(a02xx ^ a13xx) ^ a02xx);
211
				k2 ^= (xtime(a02xx ^ a13xx) ^ a13xx);
212
213
				state[j] ^= (k1 ^ a02x);
214
				state[j + 1] ^= k2;
215
				state[j + 2] ^= (k1 ^ a13x);
216
				state[j + 3] ^= (k2 ^ a02x ^ a13x);
217
			}
218
		}
219
220
	}
221
}
222
223
uint16_t
224
yubikey_crc16(const uint8_t *buf, size_t buf_size)
225
{
226
	uint16_t m_crc = 0xffff;
227
228
	while (buf_size--) {
229
		int i, j;
230
231
		m_crc ^= (uint8_t)*buf++ & 0xFF;
232
		for (i = 0; i < 8; i++) {
233
			j = m_crc & 1;
234
			m_crc >>= 1;
235
			if (j)
236
				m_crc ^= 0x8408;
237
		}
238
	}
239
	return m_crc;
240
}
241
242
static const char hex_trans[] = "0123456789abcdef";
243
244
void
245
yubikey_hex_encode(char *dst, const char *src, size_t srcSize)
246
{
247
	while (srcSize--) {
248
		*dst++ = hex_trans[(*src >> 4) & 0xf];
249
		*dst++ = hex_trans[*src++ & 0xf];
250
	}
251
	*dst = '\0';
252
}
253
254
void
255
yubikey_hex_decode(char *dst, const char *src, size_t dstSize)
256
{
257
	char b;
258
	int flag = 0;
259
	char *p1;
260
261
	for (; *src && dstSize > 0; src++) {
262
		p1 = strchr(hex_trans, tolower((unsigned char)*src));
263
		if (p1 == NULL)
264
			b = 0;
265
		else
266
			b = (char)(p1 - hex_trans);
267
		if ((flag = !flag))
268
			*dst = b;
269
		else {
270
			*dst = (*dst << 4) | b;
271
			dst++;
272
			dstSize--;
273
		}
274
	}
275
	while (dstSize--)
276
		*dst++ = 0;
277
}
278
279
static const char modhex_trans[] = "cbdefghijklnrtuv";
280
281
void
282
yubikey_modhex_decode(char *dst, const char *src, size_t dstSize)
283
{
284
	char b;
285
	int flag = 0;
286
	char *p1;
287
288
	for (; *src && dstSize > 0; src++) {
289
		p1 = strchr(modhex_trans, tolower((unsigned char)*src));
290
		if (p1 == NULL)
291
			b = 0;
292
		else
293
			b = (char)(p1 - modhex_trans);
294
295
		if ((flag = !flag))
296
			*dst = b;
297
		else {
298
			*dst = (*dst << 4) | b;
299
			dst++;
300
			dstSize--;
301
		}
302
	}
303
	while (dstSize--)
304
		*dst++ = 0;
305
}
306
307
uint8_t
308
yubikey_keymap_decode(wchar_t *wpassword, char *token, int index)
309
{
310
	int c, j, found;
311
	for (j=0; j<YUBIKEY_TOKEN_SIZE; j++) {
312
		found = 0;
313
		for (c=0; c<16; c++) {
314
			if (wpassword[j] == keymaps[index][c]) {
315
				token[j] = modhex_trans[c];
316
				found++;
317
				break;
318
			}
319
		}
320
		if (found == 0)
321
			return 1;
322
	}
323
	return 0;
324
}
325
326
int
327
yubikey_parse(const uint8_t *password, const uint8_t key[YUBIKEY_KEY_SIZE],
328
    yubikey_token_t out, int index)
329
{
330
	wchar_t *wpassword, *pp;
331
	char token[YUBIKEY_TOKEN_SIZE + 1], *lc_ctype;
332
	size_t len;
333
	int rc = 0;
334
335
	if (index < 0 || index >= YUBIKEY_KEYMAP_COUNT)
336
		return -1;
337
338
	len = strlen(password);
339
	pp = wpassword = reallocarray(NULL, len + 1, sizeof(wchar_t));
340
	if (pp == NULL)
341
		return ENOMEM;
342
343
	memset(out, 0, sizeof(*out));
344
	memset(token, 0, YUBIKEY_TOKEN_SIZE + 1);
345
346
	lc_ctype = getenv("LC_CTYPE");
347
	setlocale(LC_CTYPE, lc_ctype ? lc_ctype : "C.UTF-8");
348
	len = mbstowcs(wpassword, password, len);
349
	if (len == (size_t)-1) {
350
		rc = errno;
351
		goto ret;
352
	}
353
	setlocale(LC_CTYPE, "C");
354
355
	if (len > YUBIKEY_TOKEN_SIZE)
356
		pp = pp + len - YUBIKEY_TOKEN_SIZE;
357
	if (len < YUBIKEY_TOKEN_SIZE) {
358
		rc = EMSGSIZE;
359
		goto ret;
360
	}
361
362
	if (yubikey_keymap_decode(pp, token, index)) {
363
		rc = EINVAL;
364
		goto ret;
365
	}
366
	yubikey_modhex_decode((void *)out, token, sizeof(*out));
367
	yubikey_aes_decrypt((void *)out, key);
368
369
ret:
370
	freezero(wpassword, (len + 1) * sizeof(wchar_t));
371
	return rc;
372
}