View | Details | Raw Unified | Return to bug 2319 | Differences between
and this patch

Collapse All | Expand All

(-)a/Makefile.in (+1 lines)
Lines 107-112 SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ Link Here
107
	auth2-none.o auth2-passwd.o auth2-pubkey.o \
107
	auth2-none.o auth2-passwd.o auth2-pubkey.o \
108
	monitor_mm.o monitor.o monitor_wrap.o auth-krb5.o \
108
	monitor_mm.o monitor.o monitor_wrap.o auth-krb5.o \
109
	auth2-gss.o gss-serv.o gss-serv-krb5.o \
109
	auth2-gss.o gss-serv.o gss-serv-krb5.o \
110
	auth-u2f.o \
110
	loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
111
	loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
111
	sftp-server.o sftp-common.o \
112
	sftp-server.o sftp-common.o \
112
	roaming_common.o roaming_serv.o \
113
	roaming_common.o roaming_serv.o \
(-)a/audit-linux.c (+1 lines)
Lines 113-118 audit_event(ssh_audit_event_t event) Link Here
113
	case SSH_AUTH_FAIL_PUBKEY:
113
	case SSH_AUTH_FAIL_PUBKEY:
114
	case SSH_AUTH_FAIL_HOSTBASED:
114
	case SSH_AUTH_FAIL_HOSTBASED:
115
	case SSH_AUTH_FAIL_GSSAPI:
115
	case SSH_AUTH_FAIL_GSSAPI:
116
	case SSH_AUTH_FAIL_U2F:
116
	case SSH_INVALID_USER:
117
	case SSH_INVALID_USER:
117
		linux_audit_record_event(-1, audit_username(), NULL,
118
		linux_audit_record_event(-1, audit_username(), NULL,
118
			get_remote_ipaddr(), "sshd", 0);
119
			get_remote_ipaddr(), "sshd", 0);
(-)a/audit.c (+3 lines)
Lines 63-68 audit_classify_auth(const char *method) Link Here
63
		return SSH_AUTH_FAIL_HOSTBASED;
63
		return SSH_AUTH_FAIL_HOSTBASED;
64
	else if (strcmp(method, "gssapi-with-mic") == 0)
64
	else if (strcmp(method, "gssapi-with-mic") == 0)
65
		return SSH_AUTH_FAIL_GSSAPI;
65
		return SSH_AUTH_FAIL_GSSAPI;
66
	else if (strcmp(method, "u2f") == 0)
67
		return SSH_AUTH_FAIL_U2F;
66
	else
68
	else
67
		return SSH_AUDIT_UNKNOWN;
69
		return SSH_AUDIT_UNKNOWN;
68
}
70
}
Lines 98-103 audit_event_lookup(ssh_audit_event_t ev) Link Here
98
		{SSH_AUTH_FAIL_PUBKEY,		"AUTH_FAIL_PUBKEY"},
100
		{SSH_AUTH_FAIL_PUBKEY,		"AUTH_FAIL_PUBKEY"},
99
		{SSH_AUTH_FAIL_HOSTBASED,	"AUTH_FAIL_HOSTBASED"},
101
		{SSH_AUTH_FAIL_HOSTBASED,	"AUTH_FAIL_HOSTBASED"},
100
		{SSH_AUTH_FAIL_GSSAPI,		"AUTH_FAIL_GSSAPI"},
102
		{SSH_AUTH_FAIL_GSSAPI,		"AUTH_FAIL_GSSAPI"},
103
		{SSH_AUTH_FAIL_U2F,		"AUTH_FAIL_U2F"},
101
		{SSH_INVALID_USER,		"INVALID_USER"},
104
		{SSH_INVALID_USER,		"INVALID_USER"},
102
		{SSH_NOLOGIN,			"NOLOGIN"},
105
		{SSH_NOLOGIN,			"NOLOGIN"},
103
		{SSH_CONNECTION_CLOSE,		"CONNECTION_CLOSE"},
106
		{SSH_CONNECTION_CLOSE,		"CONNECTION_CLOSE"},
(-)a/audit.h (+1 lines)
Lines 39-44 enum ssh_audit_event_type { Link Here
39
	SSH_AUTH_FAIL_PUBKEY,	/* ssh2 pubkey or ssh1 rsa */
39
	SSH_AUTH_FAIL_PUBKEY,	/* ssh2 pubkey or ssh1 rsa */
40
	SSH_AUTH_FAIL_HOSTBASED,	/* ssh2 hostbased or ssh1 rhostsrsa */
40
	SSH_AUTH_FAIL_HOSTBASED,	/* ssh2 hostbased or ssh1 rhostsrsa */
41
	SSH_AUTH_FAIL_GSSAPI,
41
	SSH_AUTH_FAIL_GSSAPI,
42
	SSH_AUTH_FAIL_U2F,
42
	SSH_INVALID_USER,
43
	SSH_INVALID_USER,
43
	SSH_NOLOGIN,		/* denied by /etc/nologin, not implemented */
44
	SSH_NOLOGIN,		/* denied by /etc/nologin, not implemented */
44
	SSH_CONNECTION_CLOSE,	/* closed after attempting auth or session */
45
	SSH_CONNECTION_CLOSE,	/* closed after attempting auth or session */
(-)a/auth-u2f.c (+639 lines)
Line 0 Link Here
1
/*
2
 * Copyright (c) 2014 Google Inc.  All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
 */
24
25
#include "includes.h"
26
27
#ifdef U2F
28
29
#include <ctype.h>
30
#include <openssl/x509.h>
31
#include <openssl/err.h>
32
#include <u2f-host.h>
33
#include <fcntl.h>
34
35
#include "key.h"
36
#include "hostfile.h"
37
#include "auth.h"
38
#include "auth-options.h"
39
#include "ssh.h"
40
#include "ssh2.h"
41
#include "log.h"
42
#include "dispatch.h"
43
#include "misc.h"
44
#include "servconf.h"
45
#include "packet.h"
46
#include "digest.h"
47
#include "xmalloc.h"
48
#include "monitor_wrap.h"
49
#include "u2f.h"
50
51
// Evaluates to the maximum size that base64-encoding 'size' bytes can have,
52
// including one byte for a trailing NULL byte.
53
#define BASE64_ENCODED_SIZE(size) (((size)+2)/3)*4 + 1
54
55
// Evaluates to the maximum size that base64-decoding 'size' bytes can have.
56
#define BASE64_DECODED_SIZE(size) ((size) * 3/4)
57
58
extern ServerOptions options;
59
60
static void input_userauth_u2f_auth_response(int, u_int32_t, void *);
61
static void input_userauth_u2f_register_response(int type, u_int32_t seq, void *ctxt);
62
63
static const int u2f_challenge_len = 32;
64
// We set the application id to the fixed identifier “openssh”. Theoretically,
65
// it should be an HTTPS URL, listing further origins that are acceptable.
66
// However, since the SSH client cannot fetch such a URL anyway, we don’t
67
// bother setting the appid to anything meaningful.
68
//
69
// In case we need to do that in the future, we can easily make the appid a
70
// configuration option.
71
static const char *appid = "openssh";
72
73
void u2f_sha256(u_char *dest, const u_char *src, size_t srclen) {
74
	struct ssh_digest_ctx *ctx = ssh_digest_start(SSH_DIGEST_SHA256);
75
	ssh_digest_update(ctx, src, srclen);
76
	ssh_digest_final(ctx, dest, ssh_digest_bytes(SSH_DIGEST_SHA256));
77
}
78
79
/* We can get away without a JSON parser because all values in the JSON
80
 * messages used in U2F are (websafe) base64 encoded, therefore we don’t need
81
 * to care about escaping at all. We can just look for the starting double
82
 * quote and take everything until the next double quote.
83
 */
84
static char *
85
extract_json_string(const char *json, const char *key)
86
{
87
	char *quotedkey;
88
	char *keypos;
89
	char *value;
90
	char *end;
91
	int quotedkeylen;
92
93
	quotedkeylen = xasprintf(&quotedkey, "\"%s\"", key);
94
	keypos = strstr(json, quotedkey);
95
	free(quotedkey);
96
	if (keypos == NULL)
97
		return NULL;
98
99
	keypos += quotedkeylen;
100
	if (*keypos == ':')
101
		keypos++;
102
	while (*keypos != '\0' && isspace(*keypos))
103
		keypos++;
104
	if (*keypos != '"')
105
		return NULL;
106
	keypos++;
107
	value = xstrdup(keypos);
108
	if ((end = strchr(value, '"')) == NULL) {
109
		free(value);
110
		return NULL;
111
	}
112
	*end = '\0';
113
	return value;
114
}
115
116
static int
117
urlsafe_base64_decode(const char *base64, u_char *buffer, size_t bufferlen)
118
{
119
	// U2F uses urlsafe base64, which replaces + with - and / with _, so we
120
	// need to revert that before base64 decoding.
121
	char *replaced;
122
	char *pos;
123
	int ret;
124
125
	replaced = xstrdup(base64);
126
	while ((pos = strchr(replaced, '-')) != NULL)
127
		*pos = '+';
128
	while ((pos = strchr(replaced, '_')) != NULL)
129
		*pos = '/';
130
131
	ret = b64_pton(replaced, buffer, bufferlen);
132
	free(replaced);
133
	return ret;
134
}
135
136
static int
137
urlsafe_base64_encode(u_char const *src, size_t srclength, char *target, size_t targsize)
138
{
139
	char *pos;
140
	int len;
141
142
	if ((len = b64_ntop(src, srclength, target, targsize)) == -1)
143
		return -1;
144
145
	while ((pos = strchr(target, '+')) != NULL)
146
		*pos = '-';
147
148
	while ((pos = strchr(target, '/')) != NULL)
149
		*pos = '_';
150
151
	return len;
152
}
153
154
static Key*
155
read_keyfile(FILE *fp, char *filename, struct passwd *pw, u_long *linenum)
156
{
157
	char line[SSH_MAX_PUBKEY_BYTES];
158
	Key *found = NULL;
159
160
	while (read_keyfile_line(fp, filename, line, sizeof(line), linenum) != -1) {
161
		char *cp;
162
		if (found != NULL)
163
			key_free(found);
164
		found = key_new(KEY_U2F);
165
		auth_clear_options();
166
167
		/* Skip leading whitespace, empty and comment lines. */
168
		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
169
			;
170
		if (!*cp || *cp == '\n' || *cp == '#')
171
			continue;
172
173
		if (key_read(found, &cp) != 1) {
174
			continue;
175
		}
176
		if (found->type == KEY_U2F) {
177
			// TODO: calculate and display a fingerprint of the key handle and pubkey?
178
			debug("ssh-u2f key found: file %s, line %lu", filename, *linenum);
179
			return found;
180
		}
181
	}
182
	return NULL;
183
}
184
185
/*
186
 * Read a key from the key files.
187
 */
188
Key*
189
read_user_u2f_key(struct passwd *pw, u_int key_idx)
190
{
191
	size_t i;
192
	// TODO: It might not be safe to pass the key back to the unprivileged
193
	// process. It probably is, but we should review this.
194
195
	// In the first step, we need to go through all u2f keys that we have and
196
	// collect their key handles.
197
	for (i = 0; i < options.num_authkeys_files; i++) {
198
		FILE *fp;
199
		char *file;
200
		Key *key = NULL;
201
		u_long linenum = 0;
202
		if (strcasecmp(options.authorized_keys_files[i], "none") == 0)
203
			continue;
204
		file = expand_authorized_keys(options.authorized_keys_files[i], pw);
205
		debug("looking for ssh-u2f keys in %s", file);
206
		if ((fp = fopen(file, "r")) == NULL) {
207
			free(file);
208
			continue;
209
		}
210
		do
211
		{
212
			// TODO: Hackish way to allow getting more than one key
213
			key_free(key);
214
			key = read_keyfile(fp, file, pw, &linenum);
215
		}
216
		while(key_idx-- > 0);
217
		fclose(fp);
218
		free(file);
219
		if (key != NULL)
220
			return key;
221
	}
222
	return NULL;
223
}
224
225
static int
226
userauth_u2f_register(Authctxt *authctxt)
227
{
228
	u_char random[u2f_challenge_len];
229
	char challenge[BASE64_ENCODED_SIZE(sizeof(random))];
230
	char *json;
231
232
	arc4random_buf(random, sizeof(random));
233
	if (urlsafe_base64_encode(random, sizeof(random), challenge, sizeof(challenge)) == -1)
234
		fatal("urlsafe_base64_encode(arc4random_buf()) failed");
235
236
	xasprintf(&json, "{\"challenge\": \"%s\", \"version\": \"U2F_V2\", \"appId\": \"%s\"}",
237
		challenge, appid);
238
239
	packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
240
	packet_put_cstring(json);
241
	packet_send();
242
	free(json);
243
	dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
244
		&input_userauth_u2f_register_response);
245
	authctxt->postponed = 1;
246
	return 0;
247
}
248
249
static int
250
userauth_u2f_authenticate(Authctxt *authctxt)
251
{
252
	char pubkey[BASE64_ENCODED_SIZE(U2F_PUBKEY_LEN)];
253
	char *keyhandle;
254
	char *json;
255
	Key *key;
256
	u_char *challenge;
257
258
	if ((key = PRIVSEP(read_user_u2f_key(authctxt->pw, authctxt->u2f_attempt))) == NULL) {
259
		if (authctxt->u2f_attempt == 0) {
260
			char *reason = "Skipping U2F authentication: no ssh-u2f keys found in the authorized keys file(s).";
261
			debug("%s", reason);
262
			auth_debug_add("%s", reason);
263
			authctxt->postponed = 0;
264
			return (1);
265
		} else {
266
			debug("terminating u2f authentication unsuccessfully, no more keys to try.");
267
			userauth_finish(authctxt, 0, "u2f", NULL);
268
			return (0);
269
		}
270
	}
271
272
	packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
273
	challenge = xmalloc(u2f_challenge_len);
274
	arc4random_buf(challenge, u2f_challenge_len);
275
	free(authctxt->u2f_challenge);
276
	key_free(authctxt->u2f_key);
277
	authctxt->u2f_challenge = xmalloc(BASE64_ENCODED_SIZE(u2f_challenge_len));
278
	authctxt->u2f_key = key;
279
280
	if (urlsafe_base64_encode(challenge, u2f_challenge_len,
281
			authctxt->u2f_challenge, BASE64_ENCODED_SIZE(u2f_challenge_len)) == -1)
282
		fatal("urlsafe_base64_encode(arc4random_buf()) failed");
283
284
	if (urlsafe_base64_encode(key->u2f_pubkey, U2F_PUBKEY_LEN, pubkey, sizeof(pubkey)) == -1)
285
		fatal("urlsafe_base64_encode(key->u2f_pubkey) failed");
286
287
	keyhandle = xmalloc(BASE64_ENCODED_SIZE(key->u2f_key_handle_len));
288
	if (urlsafe_base64_encode(key->u2f_key_handle, key->u2f_key_handle_len,
289
				keyhandle, BASE64_ENCODED_SIZE(key->u2f_key_handle_len)) == -1)
290
		fatal("urlsafe_base64_encode(key->u2f_key_handle) failed");
291
292
	xasprintf(&json, "{\"challenge\": \"%s\", \"keyHandle\": \"%s\", \"appId\": \"%s\"}",
293
		authctxt->u2f_challenge, keyhandle, appid);
294
	packet_put_cstring(json);
295
	free(json);
296
	free(keyhandle);
297
	free(challenge);
298
	packet_send();
299
300
	dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
301
		&input_userauth_u2f_auth_response);
302
	authctxt->postponed = 1;
303
	return (0);
304
}
305
306
static int
307
userauth_u2f(Authctxt *authctxt)
308
{
309
	int mode = packet_get_int();
310
	packet_check_eom();
311
	if (mode == U2F_MODE_REGISTRATION) {
312
		debug("Starting U2F registration");
313
		return userauth_u2f_register(authctxt);
314
	} else if (mode == U2F_MODE_AUTHENTICATION) {
315
		debug("Starting U2F authentication");
316
		authctxt->u2f_attempt = 0;
317
		authctxt->u2f_challenge = NULL;
318
		authctxt->u2f_key = NULL;
319
		return userauth_u2f_authenticate(authctxt);
320
	} else {
321
		error("Unknown U2F mode %d requested by the client.", mode);
322
		return 0;
323
	}
324
}
325
326
static void
327
input_userauth_u2f_register_response(int type, u_int32_t seq, void *ctxt)
328
{
329
#define u2f_bounds_check(necessary_bytes) do { \
330
	if (restlen < necessary_bytes) { \
331
		error("U2F response too short: need %d bytes, but only %d remaining", \
332
			necessary_bytes, restlen); \
333
		goto out; \
334
	} \
335
} while (0)
336
337
#define u2f_advance(parsed_bytes) do { \
338
	int advance = parsed_bytes; \
339
	walk += advance; \
340
	restlen -= advance; \
341
} while (0)
342
343
	Authctxt *authctxt = ctxt;
344
	char *response, *regdata = NULL, *clientdata = NULL;
345
	u_char *decoded = NULL;
346
	u_char *walk = NULL;
347
	u_char *keyhandle = NULL;
348
	u_char *pubkey = NULL;
349
	u_char *signature = NULL;
350
	u_char *dummy = NULL;
351
	u_char *cdecoded = NULL;
352
	X509 *x509 = NULL;
353
	EVP_PKEY *pkey = NULL;
354
	EVP_MD_CTX mdctx;
355
	int restlen;
356
	int khlen;
357
	int cdecodedlen;
358
	int err;
359
	char errorbuf[4096];
360
	u_char digest[ssh_digest_bytes(SSH_DIGEST_SHA256)];
361
362
	authctxt->postponed = 0;
363
364
	response = packet_get_string(NULL);
365
	packet_check_eom();
366
	if ((regdata = extract_json_string(response, "registrationData")) == NULL) {
367
		error("U2F Response not JSON, or does not contain \"registrationData\"");
368
		goto out;
369
	}
370
371
	decoded = xmalloc(BASE64_DECODED_SIZE(strlen(regdata)));
372
	restlen = urlsafe_base64_decode(regdata, decoded, BASE64_DECODED_SIZE(strlen(regdata)));
373
	walk = decoded;
374
375
	// Header (magic byte)
376
	u2f_bounds_check(1);
377
	if (walk[0] != 0x05) {
378
		error("U2F response does not start with magic byte 0x05");
379
		goto out;
380
	}
381
	u2f_advance(1);
382
383
	// Length of the public key
384
	u2f_bounds_check(U2F_PUBKEY_LEN);
385
	pubkey = walk;
386
	u2f_advance(U2F_PUBKEY_LEN);
387
388
	// Length of the key handle
389
	u2f_bounds_check(1);
390
	khlen = walk[0];
391
	if (khlen <= 0) {
392
		error("Invalid key handle length: %d", khlen);
393
		goto out;
394
	}
395
	u2f_advance(1);
396
397
	// Key handle
398
	u2f_bounds_check(khlen);
399
	keyhandle = walk;
400
	u2f_advance(khlen);
401
402
	// Attestation certificate
403
	u2f_bounds_check(1);
404
	signature = walk;
405
	if ((x509 = d2i_X509(NULL, (const unsigned char **)&signature, restlen)) == NULL) {
406
		error("U2F response contains an invalid attestation certificate.");
407
		goto out;
408
	}
409
410
	// U2F dictates that the length of the certificate should be determined by
411
	// encoding the certificate using DER.
412
	u2f_advance(i2d_X509(x509, &dummy));
413
	free(dummy);
414
415
	// Ensure we have at least one byte of signature.
416
	u2f_bounds_check(1);
417
418
	if ((clientdata = extract_json_string(response, "clientData")) == NULL) {
419
		error("U2F response JSON lacks the \"clientData\" key.");
420
		goto out;
421
	}
422
423
	cdecoded = xmalloc(BASE64_DECODED_SIZE(strlen(clientdata)));
424
	cdecodedlen = urlsafe_base64_decode(clientdata, cdecoded, BASE64_DECODED_SIZE(strlen(clientdata)));
425
	pkey = X509_get_pubkey(x509);
426
427
	if ((err = EVP_VerifyInit(&mdctx, EVP_sha256())) != 1) {
428
		ERR_error_string(ERR_get_error(), errorbuf);
429
		fatal("EVP_VerifyInit() failed: %s (reason: %s)",
430
				errorbuf, ERR_reason_error_string(err));
431
	}
432
	EVP_VerifyUpdate(&mdctx, "\0", 1);
433
	u2f_sha256(digest, appid, strlen(appid));
434
	EVP_VerifyUpdate(&mdctx, digest, sizeof(digest));
435
	u2f_sha256(digest, cdecoded, cdecodedlen);
436
	EVP_VerifyUpdate(&mdctx, digest, sizeof(digest));
437
	EVP_VerifyUpdate(&mdctx, keyhandle, khlen);
438
	EVP_VerifyUpdate(&mdctx, pubkey, U2F_PUBKEY_LEN);
439
440
	err = EVP_VerifyFinal(&mdctx, walk, restlen, pkey);
441
	if (err == 0) {
442
		error("Verifying the U2F registration signature failed: invalid signature");
443
		goto out;
444
	} else if (err == -1) {
445
		long e = ERR_get_error();
446
		ERR_error_string(e, errorbuf);
447
		error("Verifying the U2F registration signature failed: %s (raw %lu) (reason: %s)",
448
				errorbuf, e, ERR_reason_error_string(err));
449
		goto out;
450
	}
451
452
	{
453
		/* Send the client a ssh-u2f line to append to the authorized_keys file
454
		 * (in order to register the security key that was just used). */
455
		char *authorizedkey;
456
		char key[U2F_PUBKEY_LEN + khlen];
457
		char key64[BASE64_ENCODED_SIZE(sizeof(key))];
458
459
		memcpy(key, pubkey, U2F_PUBKEY_LEN);
460
		memcpy(key+U2F_PUBKEY_LEN, keyhandle, khlen);
461
462
		if (b64_ntop(key, sizeof(key), key64, sizeof(key64)) == -1)
463
			fatal("b64_ntop(key)");
464
465
		xasprintf(&authorizedkey, "ssh-u2f %s my security key", key64);
466
		packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
467
		packet_put_cstring(authorizedkey);
468
		packet_send();
469
		free(authorizedkey);
470
		dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
471
	}
472
473
out:
474
	free(regdata);
475
	free(clientdata);
476
	free(decoded);
477
	free(cdecoded);
478
	if (x509 != NULL)
479
		X509_free(x509);
480
	if (pkey != NULL)
481
		EVP_PKEY_free(pkey);
482
	userauth_finish(authctxt, 0, "u2f", NULL);
483
#undef u2f_bounds_check
484
#undef u2f_advance
485
}
486
487
int
488
verify_u2f_user(Key *key, u_char *dgst, size_t dgstlen, u_char *sig, size_t siglen)
489
{
490
	char errorbuf[4096];
491
	int ret = 0;
492
	EC_KEY *ec;
493
	u_char *p;
494
	/* To save bytes, the (common) public key prefix is not included in U2F
495
	 * messages itself. */
496
#define PREFIX_LEN 26
497
#define TOTAL_LEN U2F_PUBKEY_LEN + PREFIX_LEN
498
	u_char user_pubkey[TOTAL_LEN] =
499
		"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a"
500
		"\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00";
501
502
	memcpy(user_pubkey+PREFIX_LEN, key->u2f_pubkey, U2F_PUBKEY_LEN);
503
504
	p = user_pubkey;
505
	if ((ec = d2i_EC_PUBKEY(NULL, (const unsigned char **)&p, TOTAL_LEN)) == NULL) {
506
		ERR_error_string(ERR_get_error(), errorbuf);
507
		error("Verifying U2F authentication signature failed: "
508
				"d2i_EC_PUBKEY() failed: %s (reason: %s)",
509
				errorbuf, ERR_reason_error_string(ERR_get_error()));
510
		return 0;
511
	}
512
513
	if ((ret = ECDSA_verify(0, dgst, dgstlen, sig, siglen, ec)) == -1) {
514
		ERR_error_string(ERR_get_error(), errorbuf);
515
		error("Verifying U2F authentication signature failed: "
516
				"ECDSA_verify() failed: %s (reason: %s)",
517
				errorbuf, ERR_reason_error_string(ERR_get_error()));
518
		goto out;
519
	}
520
521
	debug("U2F authentication signature verified: %s.", (ret == 1 ? "valid" : "invalid"));
522
523
out:
524
	EC_KEY_free(ec);
525
	return (ret == 1);
526
#undef TOTAL_LEN
527
#undef PREFIX_LEN
528
}
529
530
static void
531
input_userauth_u2f_auth_response(int type, u_int32_t seq, void *ctxt)
532
{
533
	int authenticated = 0;
534
	Authctxt *authctxt = ctxt;
535
	u_char digest[ssh_digest_bytes(SSH_DIGEST_SHA256)];
536
	char *sig = NULL;
537
	char *clientdata = NULL;
538
	u_char *decoded = NULL;
539
	int decodedlen;
540
	u_char *cdecoded = NULL;
541
	int cdecodedlen;
542
	char *received_challenge = NULL;
543
	char *resp = packet_get_string(NULL);
544
	packet_check_eom();
545
546
	if ((sig = extract_json_string(resp, "signatureData")) == NULL) {
547
		error("U2F Response not JSON, or does not contain \"signatureData\"");
548
		goto out;
549
	}
550
551
	if (*sig == '\0') {
552
		error("U2F authentication failed: empty signature. "
553
				"Probably the key is not registered (i.e. the configured "
554
				"key handle/pubkey do not exist on the security key you are using)");
555
		goto out;
556
	}
557
558
	decoded = xmalloc(BASE64_DECODED_SIZE(strlen(sig)));
559
	decodedlen = urlsafe_base64_decode(sig, decoded, BASE64_DECODED_SIZE(strlen(sig)));
560
	// Ensure that the user presence byte, the counter and at least one byte of
561
	// signature are present.
562
	if (decodedlen <= (int)(sizeof(u_char) + sizeof(u_int32_t))) {
563
		error("Decoded U2F signature too short (%d bytes, expected more than %d bytes)",
564
				decodedlen, (int)(sizeof(u_char) + sizeof(u_int32_t)));
565
		goto out;
566
	}
567
	if ((decoded[0] & 0x01) != 0x01) {
568
		error("No user presence detected. Please touch your security key upon "
569
				"being prompted when retrying.");
570
		goto out;
571
	}
572
	u_int32_t counter = ntohl(*((u_int32_t*)(decoded + sizeof(u_char))));
573
	// XXX: Ideally, we would verify that this counter never decreases to
574
	// detect cloned security keys. However, since OpenSSH never writes any
575
	// data to disk, we cannot keep track of the counter.
576
	debug("usage counter = %d\n", counter);
577
578
	struct ssh_digest_ctx *sha256ctx = ssh_digest_start(SSH_DIGEST_SHA256);
579
	u2f_sha256(digest, appid, strlen(appid));
580
	ssh_digest_update(sha256ctx, digest, sizeof(digest));
581
	ssh_digest_update(sha256ctx, decoded, sizeof(u_char));
582
	ssh_digest_update(sha256ctx, decoded+1, 4 * sizeof(u_char));
583
584
	if ((clientdata = extract_json_string(resp, "clientData")) == NULL) {
585
		error("U2F response JSON lacks the \"clientData\" key.");
586
		goto out;
587
	}
588
589
	cdecoded = xcalloc(1, BASE64_DECODED_SIZE(strlen(clientdata))+1);
590
	cdecodedlen = urlsafe_base64_decode(clientdata, cdecoded, BASE64_DECODED_SIZE(strlen(clientdata)));
591
592
	// XXX: We intentionally do not verify the "origin" field because that
593
	// would always require end-to-end connectivity, i.e. both server and
594
	// client need to share the understanding of the server’s hostname. As an
595
	// example, if the client connects to the server as ssh-gateway.example.net
596
	// (which could be a CNAME pointing to fra01.example.net), but the server
597
	// has the hostname fra01.example.net, this would break.
598
599
	if ((received_challenge = extract_json_string(cdecoded, "challenge")) == NULL) {
600
		error("U2F response clientData lacks the \"challenge\" key.");
601
		goto out;
602
	}
603
	if (strcmp(received_challenge, authctxt->u2f_challenge) != 0) {
604
		error("U2F response challenge bytes differ from what was sent. Man in the middle?");
605
		free(received_challenge);
606
		goto out;
607
	}
608
	free(received_challenge);
609
610
	u2f_sha256(digest, cdecoded, cdecodedlen);
611
	ssh_digest_update(sha256ctx, digest, sizeof(digest));
612
	ssh_digest_final(sha256ctx, digest, sizeof(digest));
613
614
	authenticated = PRIVSEP(verify_u2f_user(
615
		authctxt->u2f_key, digest, sizeof(digest), decoded+5, decodedlen-5));
616
617
	authctxt->postponed = 0;
618
	dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
619
out:
620
	free(sig);
621
	free(clientdata);
622
	free(decoded);
623
	free(cdecoded);
624
	authctxt->u2f_attempt++;
625
	if (authenticated) {
626
		userauth_finish(authctxt, 1, "u2f", NULL);
627
	} else {
628
		// Try again, perhaps there are more keys to use.
629
		userauth_u2f_authenticate(authctxt);
630
	}
631
}
632
633
Authmethod method_u2f = {
634
	"u2f",
635
	userauth_u2f,
636
	&options.u2f_authentication
637
};
638
639
#endif /* U2F */
(-)a/auth.h (+10 lines)
Lines 76-81 struct Authctxt { Link Here
76
	char		*krb5_ticket_file;
76
	char		*krb5_ticket_file;
77
	char		*krb5_ccname;
77
	char		*krb5_ccname;
78
#endif
78
#endif
79
#ifdef U2F
80
	Key         *u2f_key;
81
	char        *u2f_challenge;
82
	int          u2f_attempt;
83
#endif
79
	Buffer		*loginmsg;
84
	Buffer		*loginmsg;
80
	void		*methoddata;
85
	void		*methoddata;
81
86
Lines 132-137 void pubkey_auth_info(Authctxt *, const Key *, const char *, ...) Link Here
132
void	 auth2_record_userkey(Authctxt *, struct sshkey *);
137
void	 auth2_record_userkey(Authctxt *, struct sshkey *);
133
int	 auth2_userkey_already_used(Authctxt *, struct sshkey *);
138
int	 auth2_userkey_already_used(Authctxt *, struct sshkey *);
134
139
140
#ifdef U2F
141
Key	 *read_user_u2f_key(struct passwd *, u_int);
142
int	 verify_u2f_user(Key *, u_char *, size_t, u_char *, size_t);
143
#endif
144
135
struct stat;
145
struct stat;
136
int	 auth_secure_path(const char *, struct stat *, const char *, uid_t,
146
int	 auth_secure_path(const char *, struct stat *, const char *, uid_t,
137
    char *, size_t);
147
    char *, size_t);
(-)a/auth2.c (+6 lines)
Lines 72-77 extern Authmethod method_hostbased; Link Here
72
#ifdef GSSAPI
72
#ifdef GSSAPI
73
extern Authmethod method_gssapi;
73
extern Authmethod method_gssapi;
74
#endif
74
#endif
75
#ifdef U2F
76
extern Authmethod method_u2f;
77
#endif
75
78
76
Authmethod *authmethods[] = {
79
Authmethod *authmethods[] = {
77
	&method_none,
80
	&method_none,
Lines 79-84 Authmethod *authmethods[] = { Link Here
79
#ifdef GSSAPI
82
#ifdef GSSAPI
80
	&method_gssapi,
83
	&method_gssapi,
81
#endif
84
#endif
85
#ifdef U2F
86
	&method_u2f,
87
#endif
82
	&method_passwd,
88
	&method_passwd,
83
	&method_kbdint,
89
	&method_kbdint,
84
	&method_hostbased,
90
	&method_hostbased,
(-)a/configure.ac (-3 / +57 lines)
Lines 1452-1457 AC_ARG_WITH([skey], Link Here
1452
	]
1452
	]
1453
)
1453
)
1454
1454
1455
# Check whether user wants u2f support (using libu2f-host)
1456
U2F_MSG="no"
1457
AC_ARG_WITH([u2f],
1458
	[  --with-u2f[[=PATH]]   Enable U2F support (using libu2f-host)],
1459
	[ if test "x$withval" != "xno" ; then
1460
		if test "x$withval" = "xyes" ; then
1461
			AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no])
1462
			if test "x$PKGCONFIG" != "xno"; then
1463
				AC_MSG_CHECKING([if $PKGCONFIG knows about u2f-host])
1464
			 	if "$PKGCONFIG" u2f-host; then
1465
					AC_MSG_RESULT([yes])
1466
					use_pkgconfig_for_libu2fhost=yes
1467
				else
1468
					AC_MSG_RESULT([no])
1469
				fi
1470
			fi
1471
		else
1472
			CPPFLAGS="$CPPFLAGS -I${withval}/include"
1473
			if test -n "${need_dash_r}"; then
1474
				LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}"
1475
			else
1476
				LDFLAGS="-L${withval}/lib ${LDFLAGS}"
1477
			fi
1478
		fi
1479
		if test "x$use_pkgconfig_for_libu2fhost" = "xyes"; then
1480
			LIBU2FHOST=`$PKGCONFIG --libs u2f-host`
1481
			CPPFLAGS="$CPPFLAGS `$PKGCONFIG --cflags u2f-host`"
1482
		else
1483
			LIBU2FHOST="-lu2f-host"
1484
		fi
1485
		LIBS="$LIBS $LIBU2FHOST"
1486
		AC_CHECK_LIB([u2f-host], [u2fh_global_init],
1487
			[ AC_DEFINE([U2F], [1], [Enable U2F support (using libu2f-host)])
1488
			  U2F_MSG="yes"
1489
			  AC_SUBST([LIBU2FHOST])
1490
			],
1491
			[ AC_MSG_ERROR([libu2f-host not found]) ],
1492
			[ $LIBS ]
1493
		)
1494
		AC_MSG_CHECKING([if libu2f-host version is compatible])
1495
		AC_COMPILE_IFELSE(
1496
		    [AC_LANG_PROGRAM([[ #include <u2f-host.h> ]],
1497
		    [[
1498
	u2fh_global_init(0);
1499
	exit(0);
1500
		    ]])],
1501
		    [ AC_MSG_RESULT([yes]) ],
1502
		    [ AC_MSG_RESULT([no])
1503
		      AC_MSG_ERROR([u2f-host version is not compatible]) ]
1504
		)
1505
	fi ]
1506
)
1507
1455
# Check whether user wants to use ldns
1508
# Check whether user wants to use ldns
1456
LDNS_MSG="no"
1509
LDNS_MSG="no"
1457
AC_ARG_WITH(ldns,
1510
AC_ARG_WITH(ldns,
Lines 2348-2354 AC_ARG_WITH([ssl-engine], Link Here
2348
)
2401
)
2349
2402
2350
if test "x$openssl" = "xyes" ; then
2403
if test "x$openssl" = "xyes" ; then
2351
	LIBS="-lcrypto $LIBS"
2404
	LIBS="-lcrypto -lssl $LIBS"
2352
	AC_TRY_LINK_FUNC([RAND_add], [AC_DEFINE([HAVE_OPENSSL], [1],
2405
	AC_TRY_LINK_FUNC([RAND_add], [AC_DEFINE([HAVE_OPENSSL], [1],
2353
		[Define if your ssl headers are included
2406
		[Define if your ssl headers are included
2354
		with #include <openssl/header.h>])],
2407
		with #include <openssl/header.h>])],
Lines 2433-2440 if test "x$openssl" = "xyes" ; then Link Here
2433
			ssl_library_ver=`cat conftest.ssllibver`
2486
			ssl_library_ver=`cat conftest.ssllibver`
2434
			# Check version is supported.
2487
			# Check version is supported.
2435
			case "$ssl_library_ver" in
2488
			case "$ssl_library_ver" in
2436
				0090[[0-7]]*|009080[[0-5]]*)
2489
				0090*)
2437
					AC_MSG_ERROR([OpenSSL >= 0.9.8f required (have "$ssl_library_ver")])
2490
					AC_MSG_ERROR([OpenSSL >= 1.0.0 required (have "$ssl_library_ver")])
2438
			                ;;
2491
			                ;;
2439
			        *) ;;
2492
			        *) ;;
2440
			esac
2493
			esac
Lines 4974-4979 echo " KerberosV support: $KRB5_MSG" Link Here
4974
echo "                   SELinux support: $SELINUX_MSG"
5027
echo "                   SELinux support: $SELINUX_MSG"
4975
echo "                 Smartcard support: $SCARD_MSG"
5028
echo "                 Smartcard support: $SCARD_MSG"
4976
echo "                     S/KEY support: $SKEY_MSG"
5029
echo "                     S/KEY support: $SKEY_MSG"
5030
echo "                       U2F support: $U2F_MSG"
4977
echo "              MD5 password support: $MD5_MSG"
5031
echo "              MD5 password support: $MD5_MSG"
4978
echo "                   libedit support: $LIBEDIT_MSG"
5032
echo "                   libedit support: $LIBEDIT_MSG"
4979
echo "  Solaris process contract support: $SPC_MSG"
5033
echo "  Solaris process contract support: $SPC_MSG"
(-)a/monitor.c (+69 lines)
Lines 2-7 Link Here
2
/*
2
/*
3
 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
3
 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
4
 * Copyright 2002 Markus Friedl <markus@openbsd.org>
4
 * Copyright 2002 Markus Friedl <markus@openbsd.org>
5
 * Copyright 2014 Google Inc.
5
 * All rights reserved.
6
 * All rights reserved.
6
 *
7
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * Redistribution and use in source and binary forms, with or without
Lines 164-169 int mm_answer_audit_event(int, Buffer *); Link Here
164
int mm_answer_audit_command(int, Buffer *);
165
int mm_answer_audit_command(int, Buffer *);
165
#endif
166
#endif
166
167
168
#ifdef U2F
169
int mm_answer_read_user_u2f_key(int, Buffer *);
170
int mm_answer_verify_u2f_user(int, Buffer *);
171
#endif
172
167
static int monitor_read_log(struct monitor *);
173
static int monitor_read_log(struct monitor *);
168
174
169
static Authctxt *authctxt;
175
static Authctxt *authctxt;
Lines 235-240 struct mon_table mon_dispatch_proto20[] = { Link Here
235
    {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
241
    {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
236
    {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
242
    {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
237
#endif
243
#endif
244
#ifdef U2F
245
    {MONITOR_REQ_READUSERU2FKEY, MON_AUTH, mm_answer_read_user_u2f_key},
246
    {MONITOR_REQ_VERIFYU2FUSER, MON_AUTH, mm_answer_verify_u2f_user},
247
#endif
238
    {0, 0, NULL}
248
    {0, 0, NULL}
239
};
249
};
240
250
Lines 1809-1814 mm_answer_audit_event(int socket, Buffer *m) Link Here
1809
	case SSH_AUTH_FAIL_PUBKEY:
1819
	case SSH_AUTH_FAIL_PUBKEY:
1810
	case SSH_AUTH_FAIL_HOSTBASED:
1820
	case SSH_AUTH_FAIL_HOSTBASED:
1811
	case SSH_AUTH_FAIL_GSSAPI:
1821
	case SSH_AUTH_FAIL_GSSAPI:
1822
	case SSH_AUTH_FAIL_U2F:
1812
	case SSH_LOGIN_EXCEED_MAXTRIES:
1823
	case SSH_LOGIN_EXCEED_MAXTRIES:
1813
	case SSH_LOGIN_ROOT_DENIED:
1824
	case SSH_LOGIN_ROOT_DENIED:
1814
	case SSH_CONNECTION_CLOSE:
1825
	case SSH_CONNECTION_CLOSE:
Lines 2057-2059 mm_answer_gss_userok(int sock, Buffer *m) Link Here
2057
}
2068
}
2058
#endif /* GSSAPI */
2069
#endif /* GSSAPI */
2059
2070
2071
#ifdef U2F
2072
int
2073
mm_answer_read_user_u2f_key(int sock, Buffer *m)
2074
{
2075
	int authenticated = 0;
2076
	Key *key;
2077
	u_int key_idx;
2078
	u_char *blob = NULL;
2079
	u_int blen = 0;
2080
2081
	key_idx = buffer_get_int(m);
2082
	buffer_clear(m);
2083
2084
	key = read_user_u2f_key(authctxt->pw, key_idx);
2085
	buffer_put_int(m, key == NULL ? 1 : 0);
2086
	if (key != NULL)
2087
	{
2088
		if (key_to_blob(key, &blob, &blen) == 0)
2089
			fatal("%s: key_to_blob failed", __func__);
2090
		buffer_put_string(m, blob, blen);
2091
		debug3("%s: sending key", __func__);
2092
	} else {
2093
		debug3("%s: no key to send", __func__);
2094
		if (key_idx == 0) {
2095
			auth_method = "u2f";
2096
			authenticated = 1;
2097
		}
2098
	}
2099
2100
	mm_request_send(sock, MONITOR_ANS_READUSERU2FKEY, m);
2101
	return authenticated;
2102
}
2103
2104
int
2105
mm_answer_verify_u2f_user(int sock, Buffer *m)
2106
{
2107
	int authenticated = 0;
2108
	Key *key;
2109
	u_char *blob, *dgst, *sig;
2110
	u_int bloblen, dgstlen, siglen;
2111
2112
	blob = buffer_get_string(m, &bloblen);
2113
	key = key_from_blob(blob, bloblen);
2114
	dgst = buffer_get_string(m, &dgstlen);
2115
	sig = buffer_get_string(m, &siglen);
2116
2117
	buffer_clear(m);
2118
2119
	authenticated = verify_u2f_user(key, dgst, dgstlen, sig, siglen);
2120
	buffer_put_int(m, authenticated);
2121
2122
	auth_method = "u2f";
2123
	mm_request_send(sock, MONITOR_ANS_VERIFYU2FUSER, m);
2124
2125
	key_free(key);
2126
	return authenticated;
2127
}
2128
#endif /* U2F */
(-)a/monitor.h (+2 lines)
Lines 56-61 enum monitor_reqtype { Link Here
56
	MONITOR_REQ_GSSUSEROK = 46, MONITOR_ANS_GSSUSEROK = 47,
56
	MONITOR_REQ_GSSUSEROK = 46, MONITOR_ANS_GSSUSEROK = 47,
57
	MONITOR_REQ_GSSCHECKMIC = 48, MONITOR_ANS_GSSCHECKMIC = 49,
57
	MONITOR_REQ_GSSCHECKMIC = 48, MONITOR_ANS_GSSCHECKMIC = 49,
58
	MONITOR_REQ_TERM = 50,
58
	MONITOR_REQ_TERM = 50,
59
	MONITOR_REQ_READUSERU2FKEY = 52, MONITOR_ANS_READUSERU2FKEY = 53,
60
	MONITOR_REQ_VERIFYU2FUSER = 54, MONITOR_ANS_VERIFYU2FUSER = 55,
59
61
60
	MONITOR_REQ_PAM_START = 100,
62
	MONITOR_REQ_PAM_START = 100,
61
	MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103,
63
	MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103,
(-)a/monitor_wrap.c (+60 lines)
Lines 2-7 Link Here
2
/*
2
/*
3
 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
3
 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
4
 * Copyright 2002 Markus Friedl <markus@openbsd.org>
4
 * Copyright 2002 Markus Friedl <markus@openbsd.org>
5
 * Copyright 2014 Google Inc.
5
 * All rights reserved.
6
 * All rights reserved.
6
 *
7
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * Redistribution and use in source and binary forms, with or without
Lines 1088-1090 mm_ssh_gssapi_userok(char *user) Link Here
1088
}
1089
}
1089
#endif /* GSSAPI */
1090
#endif /* GSSAPI */
1090
1091
1092
#ifdef U2F
1093
Key *
1094
mm_read_user_u2f_key(struct passwd *pw, u_int key_idx)
1095
{
1096
	Buffer m;
1097
	Key *key = NULL;
1098
	u_char *blob;
1099
	u_int blen;
1100
	u_int is_null;
1101
1102
	debug3("%s entering", __func__);
1103
1104
	buffer_init(&m);
1105
	buffer_put_int(&m, key_idx);
1106
1107
	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_READUSERU2FKEY, &m);
1108
	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_READUSERU2FKEY, &m);
1109
1110
	is_null = buffer_get_int(&m);
1111
	if (is_null == 0) {
1112
		blob = buffer_get_string(&m, &blen);
1113
		if ((key = key_from_blob(blob, blen)) == NULL)
1114
			fatal("%s: key_from_blob failed", __func__);
1115
1116
		free(blob);
1117
	}
1118
1119
	buffer_free(&m);
1120
	return key;
1121
}
1122
1123
int
1124
mm_verify_u2f_user(Key *key, u_char * dgst, size_t dgstlen, u_char * sig, size_t siglen)
1125
{
1126
	int authenticated = 0;
1127
	Buffer m;
1128
	u_char *blob;
1129
	u_int blen;
1130
1131
	debug3("%s entering", __func__);
1132
1133
	if (key_to_blob(key, &blob, &blen) == 0)
1134
		fatal("%s: key_to_blob failed", __func__);
1135
	buffer_init(&m);
1136
	buffer_put_string(&m, blob, blen);
1137
	free(blob);
1138
1139
	buffer_put_string(&m, dgst, dgstlen);
1140
	buffer_put_string(&m, sig, siglen);
1141
1142
	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_VERIFYU2FUSER, &m);
1143
	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_VERIFYU2FUSER, &m);
1144
1145
	authenticated = buffer_get_int(&m);
1146
	buffer_free(&m);
1147
1148
	return authenticated;
1149
}
1150
#endif /* U2F */
(-)a/monitor_wrap.h (+4 lines)
Lines 53-58 int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int); Link Here
53
int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **);
53
int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **);
54
int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *);
54
int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *);
55
BIGNUM *mm_auth_rsa_generate_challenge(Key *);
55
BIGNUM *mm_auth_rsa_generate_challenge(Key *);
56
#ifdef U2F
57
Key *mm_read_user_u2f_key(struct passwd *, u_int);
58
int mm_verify_u2f_user(Key *, u_char *, size_t, u_char *, size_t);
59
#endif
56
60
57
#ifdef GSSAPI
61
#ifdef GSSAPI
58
OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
62
OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
(-)a/readconf.c (+26 lines)
Lines 150-155 typedef enum { Link Here
150
	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
150
	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
151
	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
151
	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
152
	oSendEnv, oControlPath, oControlMaster, oControlPersist,
152
	oSendEnv, oControlPath, oControlMaster, oControlPersist,
153
	oU2FAuthentication, oU2FMode,
153
	oHashKnownHosts,
154
	oHashKnownHosts,
154
	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
155
	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
155
	oVisualHostKey, oUseRoaming,
156
	oVisualHostKey, oUseRoaming,
Lines 198-203 static struct { Link Here
198
	{ "gssapiauthentication", oUnsupported },
199
	{ "gssapiauthentication", oUnsupported },
199
	{ "gssapidelegatecredentials", oUnsupported },
200
	{ "gssapidelegatecredentials", oUnsupported },
200
#endif
201
#endif
202
#ifdef U2F
203
	{ "u2fauthentication", oU2FAuthentication },
204
	{ "u2fmode", oU2FMode },
205
#else
206
	{ "u2fmode", oUnsupported },
207
	{ "u2fauthentication", oUnsupported },
208
#endif
201
	{ "fallbacktorsh", oDeprecated },
209
	{ "fallbacktorsh", oDeprecated },
202
	{ "usersh", oDeprecated },
210
	{ "usersh", oDeprecated },
203
	{ "identityfile", oIdentityFile },
211
	{ "identityfile", oIdentityFile },
Lines 919-924 parse_time: Link Here
919
		intptr = &options->challenge_response_authentication;
927
		intptr = &options->challenge_response_authentication;
920
		goto parse_flag;
928
		goto parse_flag;
921
929
930
	case oU2FAuthentication:
931
		intptr = &options->u2f_authentication;
932
		goto parse_flag;
933
934
	case oU2FMode:
935
		charptr = &options->u2f_mode;
936
		goto parse_string;
937
922
	case oGssAuthentication:
938
	case oGssAuthentication:
923
		intptr = &options->gss_authentication;
939
		intptr = &options->gss_authentication;
924
		goto parse_flag;
940
		goto parse_flag;
Lines 1657-1662 initialize_options(Options * options) Link Here
1657
	options->password_authentication = -1;
1673
	options->password_authentication = -1;
1658
	options->kbd_interactive_authentication = -1;
1674
	options->kbd_interactive_authentication = -1;
1659
	options->kbd_interactive_devices = NULL;
1675
	options->kbd_interactive_devices = NULL;
1676
	options->u2f_authentication = -1;
1677
	options->u2f_mode = NULL;
1660
	options->rhosts_rsa_authentication = -1;
1678
	options->rhosts_rsa_authentication = -1;
1661
	options->hostbased_authentication = -1;
1679
	options->hostbased_authentication = -1;
1662
	options->batch_mode = -1;
1680
	options->batch_mode = -1;
Lines 1889-1894 fill_default_options(Options * options) Link Here
1889
		options->tun_remote = SSH_TUNID_ANY;
1907
		options->tun_remote = SSH_TUNID_ANY;
1890
	if (options->permit_local_command == -1)
1908
	if (options->permit_local_command == -1)
1891
		options->permit_local_command = 0;
1909
		options->permit_local_command = 0;
1910
	if (options->u2f_authentication == -1)
1911
		options->u2f_authentication = 1;
1912
	if (options->u2f_mode == NULL)
1913
		options->u2f_mode = strdup("authentication");
1892
	options->use_roaming = 0;
1914
	options->use_roaming = 0;
1893
	if (options->visual_host_key == -1)
1915
	if (options->visual_host_key == -1)
1894
		options->visual_host_key = 0;
1916
		options->visual_host_key = 0;
Lines 2327-2332 dump_client_config(Options *o, const char *host) Link Here
2327
	dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
2349
	dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
2328
	dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
2350
	dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
2329
#endif /* GSSAPI */
2351
#endif /* GSSAPI */
2352
#ifdef U2F
2353
	dump_cfg_fmtint(oU2FAuthentication, o->u2f_authentication);
2354
	dump_cfg_string(oU2FMode, o->u2f_mode);
2355
#endif /* GSSAPI */
2330
	dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
2356
	dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
2331
	dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
2357
	dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
2332
	dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
2358
	dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
(-)a/readconf.h (+2 lines)
Lines 46-55 typedef struct { Link Here
46
					/* Try S/Key or TIS, authentication. */
46
					/* Try S/Key or TIS, authentication. */
47
	int     gss_authentication;	/* Try GSS authentication */
47
	int     gss_authentication;	/* Try GSS authentication */
48
	int     gss_deleg_creds;	/* Delegate GSS credentials */
48
	int     gss_deleg_creds;	/* Delegate GSS credentials */
49
	int     u2f_authentication;
49
	int     password_authentication;	/* Try password
50
	int     password_authentication;	/* Try password
50
						 * authentication. */
51
						 * authentication. */
51
	int     kbd_interactive_authentication; /* Try keyboard-interactive auth. */
52
	int     kbd_interactive_authentication; /* Try keyboard-interactive auth. */
52
	char	*kbd_interactive_devices; /* Keyboard-interactive auth devices. */
53
	char	*kbd_interactive_devices; /* Keyboard-interactive auth devices. */
54
	char    *u2f_mode; /* mode (registration or authentication) for U2F auth. */
53
	int     batch_mode;	/* Batch mode: do not ask for passwords. */
55
	int     batch_mode;	/* Batch mode: do not ask for passwords. */
54
	int     check_host_ip;	/* Also keep track of keys for IP address */
56
	int     check_host_ip;	/* Also keep track of keys for IP address */
55
	int     strict_host_key_checking;	/* Strict host key checking. */
57
	int     strict_host_key_checking;	/* Strict host key checking. */
(-)a/servconf.c (+20 lines)
Lines 117-122 initialize_server_options(ServerOptions *options) Link Here
117
	options->kerberos_ticket_cleanup = -1;
117
	options->kerberos_ticket_cleanup = -1;
118
	options->kerberos_get_afs_token = -1;
118
	options->kerberos_get_afs_token = -1;
119
	options->gss_authentication=-1;
119
	options->gss_authentication=-1;
120
	options->u2f_authentication = -1;
120
	options->gss_cleanup_creds = -1;
121
	options->gss_cleanup_creds = -1;
121
	options->gss_strict_acceptor = -1;
122
	options->gss_strict_acceptor = -1;
122
	options->password_authentication = -1;
123
	options->password_authentication = -1;
Lines 287-292 fill_default_server_options(ServerOptions *options) Link Here
287
		options->kerberos_get_afs_token = 0;
288
		options->kerberos_get_afs_token = 0;
288
	if (options->gss_authentication == -1)
289
	if (options->gss_authentication == -1)
289
		options->gss_authentication = 0;
290
		options->gss_authentication = 0;
291
	// U2F authentication is disabled by default. On its own, it does not
292
	// provide adequate security, and it should be used as a second factor in
293
	// combination with publickey, for example.
294
	if (options->u2f_authentication == -1)
295
		options->u2f_authentication = 0;
290
	if (options->gss_cleanup_creds == -1)
296
	if (options->gss_cleanup_creds == -1)
291
		options->gss_cleanup_creds = 1;
297
		options->gss_cleanup_creds = 1;
292
	if (options->gss_strict_acceptor == -1)
298
	if (options->gss_strict_acceptor == -1)
Lines 419-424 typedef enum { Link Here
419
	sHostKeyAlgorithms,
425
	sHostKeyAlgorithms,
420
	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
426
	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
421
	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
427
	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
428
	sU2FAuthentication,
422
	sAcceptEnv, sPermitTunnel,
429
	sAcceptEnv, sPermitTunnel,
423
	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
430
	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
424
	sUsePrivilegeSeparation, sAllowAgentForwarding,
431
	sUsePrivilegeSeparation, sAllowAgentForwarding,
Lines 498-503 static struct { Link Here
498
	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
505
	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
499
	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
506
	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
500
#endif
507
#endif
508
#ifdef U2F
509
	{ "u2fauthentication", sU2FAuthentication, SSHCFG_ALL },
510
#else
511
	{ "u2fauthentication", sUnsupported, SSHCFG_ALL },
512
#endif
501
	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
513
	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
502
	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
514
	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
503
	{ "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
515
	{ "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
Lines 1250-1255 process_server_config_line(ServerOptions *options, char *line, Link Here
1250
		intptr = &options->gss_strict_acceptor;
1262
		intptr = &options->gss_strict_acceptor;
1251
		goto parse_flag;
1263
		goto parse_flag;
1252
1264
1265
	case sU2FAuthentication:
1266
		intptr = &options->u2f_authentication;
1267
		goto parse_flag;
1268
1253
	case sPasswordAuthentication:
1269
	case sPasswordAuthentication:
1254
		intptr = &options->password_authentication;
1270
		intptr = &options->password_authentication;
1255
		goto parse_flag;
1271
		goto parse_flag;
Lines 1983-1988 copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) Link Here
1983
1999
1984
	M_CP_INTOPT(password_authentication);
2000
	M_CP_INTOPT(password_authentication);
1985
	M_CP_INTOPT(gss_authentication);
2001
	M_CP_INTOPT(gss_authentication);
2002
	M_CP_INTOPT(u2f_authentication);
1986
	M_CP_INTOPT(rsa_authentication);
2003
	M_CP_INTOPT(rsa_authentication);
1987
	M_CP_INTOPT(pubkey_authentication);
2004
	M_CP_INTOPT(pubkey_authentication);
1988
	M_CP_INTOPT(kerberos_authentication);
2005
	M_CP_INTOPT(kerberos_authentication);
Lines 2271-2276 dump_config(ServerOptions *o) Link Here
2271
	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
2288
	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
2272
	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
2289
	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
2273
#endif
2290
#endif
2291
#ifdef U2F
2292
	dump_cfg_fmtint(sU2FAuthentication, o->u2f_authentication);
2293
#endif
2274
	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
2294
	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
2275
	dump_cfg_fmtint(sKbdInteractiveAuthentication,
2295
	dump_cfg_fmtint(sKbdInteractiveAuthentication,
2276
	    o->kbd_interactive_authentication);
2296
	    o->kbd_interactive_authentication);
(-)a/servconf.h (+1 lines)
Lines 124-129 typedef struct { Link Here
124
						 * authentication. */
124
						 * authentication. */
125
	int     kbd_interactive_authentication;	/* If true, permit */
125
	int     kbd_interactive_authentication;	/* If true, permit */
126
	int     challenge_response_authentication;
126
	int     challenge_response_authentication;
127
	int     u2f_authentication;
127
	int     permit_empty_passwd;	/* If false, do not permit empty
128
	int     permit_empty_passwd;	/* If false, do not permit empty
128
					 * passwords. */
129
					 * passwords. */
129
	int     permit_user_env;	/* If true, read ~/.ssh/environment */
130
	int     permit_user_env;	/* If true, read ~/.ssh/environment */
(-)a/ssh.1 (+2 lines)
Lines 540-545 For full details of the options listed below, and their possible values, see Link Here
540
.It TCPKeepAlive
540
.It TCPKeepAlive
541
.It Tunnel
541
.It Tunnel
542
.It TunnelDevice
542
.It TunnelDevice
543
.It U2FAuthentication
544
.It U2FMode
543
.It UpdateHostKeys
545
.It UpdateHostKeys
544
.It UsePrivilegedPort
546
.It UsePrivilegedPort
545
.It User
547
.It User
(-)a/ssh.c (+11 lines)
Lines 74-83 Link Here
74
#ifdef WITH_OPENSSL
74
#ifdef WITH_OPENSSL
75
#include <openssl/evp.h>
75
#include <openssl/evp.h>
76
#include <openssl/err.h>
76
#include <openssl/err.h>
77
#include <openssl/ssl.h>
77
#endif
78
#endif
78
#include "openbsd-compat/openssl-compat.h"
79
#include "openbsd-compat/openssl-compat.h"
79
#include "openbsd-compat/sys-queue.h"
80
#include "openbsd-compat/sys-queue.h"
80
81
82
#ifdef U2F
83
#include <u2f-host.h>
84
#endif
85
81
#include "xmalloc.h"
86
#include "xmalloc.h"
82
#include "ssh.h"
87
#include "ssh.h"
83
#include "ssh1.h"
88
#include "ssh1.h"
Lines 955-960 main(int ac, char **av) Link Here
955
#ifdef WITH_OPENSSL
960
#ifdef WITH_OPENSSL
956
	OpenSSL_add_all_algorithms();
961
	OpenSSL_add_all_algorithms();
957
	ERR_load_crypto_strings();
962
	ERR_load_crypto_strings();
963
	SSL_load_error_strings();
964
#endif
965
966
#ifdef U2F
967
	if (u2fh_global_init(0) != U2FH_OK)
968
		fatal("u2fh_global_init() failed");
958
#endif
969
#endif
959
970
960
	/* Initialize the command to execute on remote host. */
971
	/* Initialize the command to execute on remote host. */
(-)a/ssh_config.5 (+10 lines)
Lines 1679-1684 Presently, only Link Here
1679
from OpenSSH 6.8 and greater support the
1679
from OpenSSH 6.8 and greater support the
1680
.Dq hostkeys@openssh.com
1680
.Dq hostkeys@openssh.com
1681
protocol extension used to inform the client of all the server's hostkeys.
1681
protocol extension used to inform the client of all the server's hostkeys.
1682
.It Cm U2FAuthentication
1683
Specifies whether user authentication based on U2F (Universal Second Factor) is allowed. The default is
1684
.Dq yes .
1685
.It Cm U2FMode
1686
Specifies which mode the U2F authentication method should use. Can be either
1687
.Dq authentication
1688
or
1689
.Dq registration .
1690
The default is
1691
.Dq authentication .
1682
.It Cm UsePrivilegedPort
1692
.It Cm UsePrivilegedPort
1683
Specifies whether to use a privileged port for outgoing connections.
1693
Specifies whether to use a privileged port for outgoing connections.
1684
The argument must be
1694
The argument must be
(-)a/sshconnect.c (-1 / +1 lines)
Lines 1381-1387 ssh_login(Sensitive *sensitive, const char *orighost, Link Here
1381
	debug("Authenticating to %s:%d as '%s'", host, port, server_user);
1381
	debug("Authenticating to %s:%d as '%s'", host, port, server_user);
1382
	if (compat20) {
1382
	if (compat20) {
1383
		ssh_kex2(host, hostaddr, port);
1383
		ssh_kex2(host, hostaddr, port);
1384
		ssh_userauth2(local_user, server_user, host, sensitive);
1384
		ssh_userauth2(local_user, server_user, host, port, sensitive);
1385
	} else {
1385
	} else {
1386
#ifdef WITH_SSH1
1386
#ifdef WITH_SSH1
1387
		ssh_kex(host, hostaddr);
1387
		ssh_kex(host, hostaddr);
(-)a/sshconnect.h (-1 / +1 lines)
Lines 50-56 void ssh_kex(char *, struct sockaddr *); Link Here
50
void	 ssh_kex2(char *, struct sockaddr *, u_short);
50
void	 ssh_kex2(char *, struct sockaddr *, u_short);
51
51
52
void	 ssh_userauth1(const char *, const char *, char *, Sensitive *);
52
void	 ssh_userauth1(const char *, const char *, char *, Sensitive *);
53
void	 ssh_userauth2(const char *, const char *, char *, Sensitive *);
53
void	 ssh_userauth2(const char *, const char *, char *, u_short, Sensitive *);
54
54
55
void	 ssh_put_password(char *);
55
void	 ssh_put_password(char *);
56
int	 ssh_local_cmd(const char *);
56
int	 ssh_local_cmd(const char *);
(-)a/sshconnect2.c (-1 / +177 lines)
Lines 2-7 Link Here
2
/*
2
/*
3
 * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3
 * Copyright (c) 2000 Markus Friedl.  All rights reserved.
4
 * Copyright (c) 2008 Damien Miller.  All rights reserved.
4
 * Copyright (c) 2008 Damien Miller.  All rights reserved.
5
 * Copyright (c) 2014 Google Inc.  All rights reserved.
5
 *
6
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * modification, are permitted provided that the following conditions
Lines 30-35 Link Here
30
#include <sys/socket.h>
31
#include <sys/socket.h>
31
#include <sys/wait.h>
32
#include <sys/wait.h>
32
#include <sys/stat.h>
33
#include <sys/stat.h>
34
#include <time.h>
33
35
34
#include <errno.h>
36
#include <errno.h>
35
#include <fcntl.h>
37
#include <fcntl.h>
Lines 44-49 Link Here
44
#include <vis.h>
46
#include <vis.h>
45
#endif
47
#endif
46
48
49
#ifdef U2F
50
#include <u2f-host.h>
51
#endif
52
47
#include "openbsd-compat/sys-queue.h"
53
#include "openbsd-compat/sys-queue.h"
48
54
49
#include "xmalloc.h"
55
#include "xmalloc.h"
Lines 71-76 Link Here
71
#include "uidswap.h"
77
#include "uidswap.h"
72
#include "hostfile.h"
78
#include "hostfile.h"
73
#include "ssherr.h"
79
#include "ssherr.h"
80
#include "u2f.h"
74
81
75
#ifdef GSSAPI
82
#ifdef GSSAPI
76
#include "ssh-gss.h"
83
#include "ssh-gss.h"
Lines 265-270 struct cauthctxt { Link Here
265
	const char *server_user;
272
	const char *server_user;
266
	const char *local_user;
273
	const char *local_user;
267
	const char *host;
274
	const char *host;
275
	char *host_port;
268
	const char *service;
276
	const char *service;
269
	struct cauthmethod *method;
277
	struct cauthmethod *method;
270
	sig_atomic_t success;
278
	sig_atomic_t success;
Lines 317-322 int input_gssapi_error(int, u_int32_t, void *); Link Here
317
int	input_gssapi_errtok(int, u_int32_t, void *);
325
int	input_gssapi_errtok(int, u_int32_t, void *);
318
#endif
326
#endif
319
327
328
#ifdef U2F
329
int userauth_u2f(Authctxt *authctxt);
330
int input_userauth_u2f_authenticate(int type, u_int32_t seq, void *ctxt);
331
int input_userauth_u2f_register(int type, u_int32_t seq, void *ctxt);
332
int input_userauth_u2f_register_response(int type, u_int32_t seq, void *ctxt);
333
#endif
334
320
void	userauth(Authctxt *, char *);
335
void	userauth(Authctxt *, char *);
321
336
322
static int sign_and_send_pubkey(Authctxt *, Identity *);
337
static int sign_and_send_pubkey(Authctxt *, Identity *);
Lines 329-334 static Authmethod *authmethod_lookup(const char *name); Link Here
329
static char *authmethods_get(void);
344
static char *authmethods_get(void);
330
345
331
Authmethod authmethods[] = {
346
Authmethod authmethods[] = {
347
	// U2F needs to be the first authentication method, so that we use it once
348
	// the server allows it. This enables server configurations containing e.g.:
349
	// AuthenticationMethods password,u2f pubkey,u2f
350
#ifdef U2F
351
    {"u2f",
352
        userauth_u2f,
353
        NULL,
354
        &options.u2f_authentication,
355
        NULL},
356
#endif
332
#ifdef GSSAPI
357
#ifdef GSSAPI
333
	{"gssapi-with-mic",
358
	{"gssapi-with-mic",
334
		userauth_gssapi,
359
		userauth_gssapi,
Lines 366-372 Authmethod authmethods[] = { Link Here
366
391
367
void
392
void
368
ssh_userauth2(const char *local_user, const char *server_user, char *host,
393
ssh_userauth2(const char *local_user, const char *server_user, char *host,
369
    Sensitive *sensitive)
394
    u_short port, Sensitive *sensitive)
370
{
395
{
371
	struct ssh *ssh = active_state;
396
	struct ssh *ssh = active_state;
372
	Authctxt authctxt;
397
	Authctxt authctxt;
Lines 383-388 ssh_userauth2(const char *local_user, const char *server_user, char *host, Link Here
383
	authctxt.server_user = server_user;
408
	authctxt.server_user = server_user;
384
	authctxt.local_user = local_user;
409
	authctxt.local_user = local_user;
385
	authctxt.host = host;
410
	authctxt.host = host;
411
	get_hostfile_hostname_ipaddr(host, NULL, port, &authctxt.host_port, NULL);
386
	authctxt.service = "ssh-connection";		/* service name */
412
	authctxt.service = "ssh-connection";		/* service name */
387
	authctxt.success = 0;
413
	authctxt.success = 0;
388
	authctxt.method = authmethod_lookup("none");
414
	authctxt.method = authmethod_lookup("none");
Lines 885-890 input_gssapi_error(int type, u_int32_t plen, void *ctxt) Link Here
885
}
911
}
886
#endif /* GSSAPI */
912
#endif /* GSSAPI */
887
913
914
#ifdef U2F
915
int
916
userauth_u2f(Authctxt *authctxt)
917
{
918
	// first step: we dont send anything, but install a custom dispatcher.
919
	debug("sshconnect2:userauth_u2f");
920
921
	// For U2F_MODE_REGISTRATION, this code path will return 0, meaning the
922
	// authentication method will not be retried. If we did not do that, we
923
	// would loop endlessly.
924
	if (authctxt->info_req_seen) {
925
		dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL);
926
		return 0;
927
	}
928
929
	packet_start(SSH2_MSG_USERAUTH_REQUEST);
930
	packet_put_cstring(authctxt->server_user);
931
	packet_put_cstring(authctxt->service);
932
	packet_put_cstring(authctxt->method->name);
933
	if (options.u2f_mode == NULL || strcasecmp(options.u2f_mode, "authentication") == 0) {
934
		packet_put_int(U2F_MODE_AUTHENTICATION);
935
		dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_u2f_authenticate);
936
	} else if (options.u2f_mode != NULL && strcasecmp(options.u2f_mode, "registration") == 0) {
937
		packet_put_int(U2F_MODE_REGISTRATION);
938
		dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_u2f_register);
939
	} else {
940
		fatal("Invalid U2F mode (\"%s\"), expected \"authentication\" or \"registration\".",
941
				options.u2f_mode);
942
	}
943
	packet_send();
944
945
	return 1;
946
}
947
948
static void
949
wait_for_u2f_devices(u2fh_devs *devs)
950
{
951
	time_t looking;
952
	int attempts = 0;
953
	u2fh_rc rc;
954
955
	// The U2F implementation considerations recommend 3 seconds as the time a
956
	// client implementation should grant for security keys to respond. We wait
957
	// 3 times that for the user to insert a security key (and it being
958
	// detected).
959
	looking = monotime();
960
	do {
961
		if ((rc = u2fh_devs_discover(devs, NULL)) != U2FH_OK && attempts++ == 0)
962
			error("Please insert and touch your U2F security key.");
963
		if (rc != U2FH_OK)
964
			usleep(50);
965
	} while (rc != U2FH_OK && (monotime() - looking) <= 9);
966
	if (rc != U2FH_OK)
967
		fatal("No U2F devices found (%s). Did you plug in your U2F security key?",
968
				u2fh_strerror(rc));
969
970
	if (attempts == 0)
971
		error("Please touch your U2F security key now.");
972
}
973
974
int
975
input_userauth_u2f_register(int type, u_int32_t seq, void *ctxt)
976
{
977
	Authctxt *authctxt = ctxt;
978
	char *challenge, *response;
979
	u2fh_devs *devs = NULL;
980
	u2fh_rc rc;
981
	const char *origin = authctxt->host_port;
982
983
	if (authctxt == NULL)
984
		fatal("input_userauth_u2f_register: no authentication context");
985
986
	authctxt->info_req_seen = 1;
987
988
	challenge = packet_get_string(NULL);
989
	packet_check_eom();
990
991
	if ((rc = u2fh_devs_init(&devs)) != U2FH_OK)
992
		fatal("u2fh_devs_init() failed: %s", u2fh_strerror(rc));
993
994
	wait_for_u2f_devices(devs);
995
996
	if ((rc = u2fh_register(devs, challenge, origin, &response, U2FH_REQUEST_USER_PRESENCE)) != U2FH_OK)
997
		fatal("u2fh_register() failed: %s", u2fh_strerror(rc));
998
999
	u2fh_devs_done(devs);
1000
1001
	packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
1002
	packet_put_cstring(response);
1003
	packet_send();
1004
1005
	free(response);
1006
	dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL);
1007
	dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_u2f_register_response);
1008
	return 0;
1009
}
1010
1011
int
1012
input_userauth_u2f_register_response(int type, u_int32_t seq, void *ctxt)
1013
{
1014
	char *response = packet_get_string(NULL);
1015
	printf("%s\n", response);
1016
	fflush(stdout);
1017
	return 0;
1018
}
1019
1020
int
1021
input_userauth_u2f_authenticate(int type, u_int32_t seq, void *ctxt)
1022
{
1023
	Authctxt *authctxt = ctxt;
1024
	char *challenge, *response;
1025
	u2fh_devs *devs = NULL;
1026
	u2fh_rc rc;
1027
	const char *origin = authctxt->host_port;
1028
1029
	if (authctxt == NULL)
1030
		fatal("input_userauth_u2f_authenticate: no authentication context");
1031
1032
	authctxt->info_req_seen = 1;
1033
1034
	challenge = packet_get_string(NULL);
1035
	packet_check_eom();
1036
1037
	debug("Starting U2F authentication for origin \"%s\".", origin);
1038
1039
	if ((rc = u2fh_devs_init(&devs)) != U2FH_OK)
1040
		fatal("u2fh_devs_init() failed: %s", u2fh_strerror(rc));
1041
1042
	wait_for_u2f_devices(devs);
1043
1044
	// TODO: refactor with input_userauth_u2f_register(), the following line is the only one that is different :)
1045
	if ((rc = u2fh_authenticate(devs, challenge, origin, &response, U2FH_REQUEST_USER_PRESENCE)) != U2FH_OK)
1046
		fatal("u2fh_authenticate() failed: %s", u2fh_strerror(rc));
1047
1048
	u2fh_devs_done(devs);
1049
1050
	packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
1051
	packet_put_cstring(response);
1052
	packet_send();
1053
1054
	free(response);
1055
	return 0;
1056
1057
	// We intentionally do not set SSH2_MSG_USERAUTH_INFO_REQUEST to NULL,
1058
	// because the server might send us more challenges (in case more than one
1059
	// U2F security key is in the authorized_keys).
1060
}
1061
1062
#endif /* U2F */
1063
888
int
1064
int
889
userauth_none(Authctxt *authctxt)
1065
userauth_none(Authctxt *authctxt)
890
{
1066
{
(-)a/sshd.c (+2 lines)
Lines 77-82 Link Here
77
#include <openssl/dh.h>
77
#include <openssl/dh.h>
78
#include <openssl/bn.h>
78
#include <openssl/bn.h>
79
#include <openssl/rand.h>
79
#include <openssl/rand.h>
80
#include <openssl/ssl.h>
80
#include "openbsd-compat/openssl-compat.h"
81
#include "openbsd-compat/openssl-compat.h"
81
#endif
82
#endif
82
83
Lines 1636-1641 main(int ac, char **av) Link Here
1636
1637
1637
#ifdef WITH_OPENSSL
1638
#ifdef WITH_OPENSSL
1638
	OpenSSL_add_all_algorithms();
1639
	OpenSSL_add_all_algorithms();
1640
	SSL_load_error_strings();
1639
#endif
1641
#endif
1640
1642
1641
	/* If requested, redirect the logs to the specified logfile. */
1643
	/* If requested, redirect the logs to the specified logfile. */
(-)a/sshd_config.5 (+19 lines)
Lines 1524-1529 for authentication using Link Here
1524
.Cm TrustedUserCAKeys .
1524
.Cm TrustedUserCAKeys .
1525
For more details on certificates, see the CERTIFICATES section in
1525
For more details on certificates, see the CERTIFICATES section in
1526
.Xr ssh-keygen 1 .
1526
.Xr ssh-keygen 1 .
1527
.It Cm U2FAuthentication
1528
Specifies whether user authentication based on U2F (Universal Second Factor) is allowed. The default is
1529
.Dq no .
1530
Note that U2F authentication should never be used alone, so specify for example:
1531
.Bd -literal -offset indent
1532
U2FAuthentication yes
1533
AuthenticationMethods pubkey,u2f
1534
.Ed
1535
.Pp
1536
That way, pubkey authentication will be performed and U2F will be required
1537
after pubkey authentication was successful. In case the user in question does
1538
not have any ssh-u2f lines in their authorized_keys file, the u2f
1539
authentication method will just return success.
1540
.Pp
1541
In order to register a U2F security key, enable this option as outlined above.
1542
Then, run
1543
.Dq ssh -o U2FMode=registration server.example.net
1544
in order to obtain a ssh-u2f line which you can then append to your
1545
authorized_keys.
1527
.It Cm UseDNS
1546
.It Cm UseDNS
1528
Specifies whether
1547
Specifies whether
1529
.Xr sshd 8
1548
.Xr sshd 8
(-)a/sshkey.c (+83 lines)
Lines 3-8 Link Here
3
 * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
3
 * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
4
 * Copyright (c) 2008 Alexander von Gernler.  All rights reserved.
4
 * Copyright (c) 2008 Alexander von Gernler.  All rights reserved.
5
 * Copyright (c) 2010,2011 Damien Miller.  All rights reserved.
5
 * Copyright (c) 2010,2011 Damien Miller.  All rights reserved.
6
 * Copyright (c) 2014 Google Inc.  All rights reserved.
6
 *
7
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * modification, are permitted provided that the following conditions
Lines 58-63 Link Here
58
#define SSHKEY_INTERNAL
59
#define SSHKEY_INTERNAL
59
#include "sshkey.h"
60
#include "sshkey.h"
60
#include "match.h"
61
#include "match.h"
62
#include "key.h"
63
#include "hostfile.h"
64
#include "auth.h"
65
#include "u2f.h"
61
66
62
/* openssh private key file format */
67
/* openssh private key file format */
63
#define MARK_BEGIN		"-----BEGIN OPENSSH PRIVATE KEY-----\n"
68
#define MARK_BEGIN		"-----BEGIN OPENSSH PRIVATE KEY-----\n"
Lines 115-120 static const struct keytype keytypes[] = { Link Here
115
#  endif /* OPENSSL_HAS_NISTP521 */
120
#  endif /* OPENSSL_HAS_NISTP521 */
116
# endif /* OPENSSL_HAS_ECC */
121
# endif /* OPENSSL_HAS_ECC */
117
#endif /* WITH_OPENSSL */
122
#endif /* WITH_OPENSSL */
123
	{ "ssh-u2f", "U2F", KEY_U2F, 0, 0 },
118
	{ NULL, NULL, -1, -1, 0, 0 }
124
	{ NULL, NULL, -1, -1, 0, 0 }
119
};
125
};
120
126
Lines 510-515 sshkey_new(int type) Link Here
510
		break;
516
		break;
511
	case KEY_UNSPEC:
517
	case KEY_UNSPEC:
512
		break;
518
		break;
519
	case KEY_U2F:
520
		break;
513
	default:
521
	default:
514
		free(k);
522
		free(k);
515
		return NULL;
523
		return NULL;
Lines 790-795 to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain) Link Here
790
		    key->ed25519_pk, ED25519_PK_SZ)) != 0)
798
		    key->ed25519_pk, ED25519_PK_SZ)) != 0)
791
			return ret;
799
			return ret;
792
		break;
800
		break;
801
#ifdef U2F
802
	case KEY_U2F:
803
		if (key->u2f_pubkey == NULL)
804
			return SSH_ERR_INVALID_ARGUMENT;
805
		if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
806
		    (ret = sshbuf_put_string(b, key->u2f_pubkey, U2F_PUBKEY_LEN)) != 0 ||
807
		    (ret = sshbuf_put_string(b,
808
				key->u2f_key_handle, key->u2f_key_handle_len)) != 0)
809
			return ret;
810
		break;
811
#endif
793
	default:
812
	default:
794
		return SSH_ERR_KEY_TYPE_UNKNOWN;
813
		return SSH_ERR_KEY_TYPE_UNKNOWN;
795
	}
814
	}
Lines 1258-1263 sshkey_read(struct sshkey *ret, char **cpp) Link Here
1258
		retval = 0;
1277
		retval = 0;
1259
#endif /* WITH_SSH1 */
1278
#endif /* WITH_SSH1 */
1260
		break;
1279
		break;
1280
	case KEY_U2F:
1281
#ifdef U2F
1282
		space = strchr(cp, ' ');
1283
		if (space == NULL)
1284
			return SSH_ERR_INVALID_FORMAT;
1285
		*space = '\0';
1286
		type = sshkey_type_from_name(cp);
1287
		if (type == KEY_UNSPEC)
1288
			return SSH_ERR_INVALID_FORMAT;
1289
		cp = space+1;
1290
		if (*cp == '\0')
1291
			return SSH_ERR_INVALID_FORMAT;
1292
		if (ret->type == KEY_UNSPEC) {
1293
			ret->type = type;
1294
		} else if (ret->type != type)
1295
			return SSH_ERR_KEY_TYPE_MISMATCH;
1296
		cp = space+1;
1297
		/* trim comment */
1298
		space = strchr(cp, ' ');
1299
		if (space)
1300
			*space = '\0';
1301
		blob = sshbuf_new();
1302
		if ((r = sshbuf_b64tod(blob, cp)) != 0) {
1303
			sshbuf_free(blob);
1304
			return r;
1305
		}
1306
		// TODO: why do we _need_ to use malloc here? xmalloc gives memory that crashes!
1307
		ret->u2f_pubkey = malloc(U2F_PUBKEY_LEN);
1308
		memcpy(ret->u2f_pubkey, sshbuf_ptr(blob), U2F_PUBKEY_LEN);
1309
		ret->u2f_key_handle_len = sshbuf_len(blob) - U2F_PUBKEY_LEN;
1310
		ret->u2f_key_handle = malloc(ret->u2f_key_handle_len);
1311
		memcpy(ret->u2f_key_handle, sshbuf_ptr(blob) + U2F_PUBKEY_LEN, ret->u2f_key_handle_len);
1312
		sshbuf_free(blob);
1313
		retval = (r >= 0) ? 0 : 1;
1314
#endif /* U2F */
1315
		break;
1261
	case KEY_UNSPEC:
1316
	case KEY_UNSPEC:
1262
	case KEY_RSA:
1317
	case KEY_RSA:
1263
	case KEY_DSA:
1318
	case KEY_DSA:
Lines 1962-1967 sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp, Link Here
1962
#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
2017
#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
1963
	EC_POINT *q = NULL;
2018
	EC_POINT *q = NULL;
1964
#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
2019
#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
2020
#ifdef U2F
2021
	u_char *khandle = NULL;
2022
#endif
1965
2023
1966
#ifdef DEBUG_PK /* XXX */
2024
#ifdef DEBUG_PK /* XXX */
1967
	sshbuf_dump(b, stderr);
2025
	sshbuf_dump(b, stderr);
Lines 2101-2106 sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp, Link Here
2101
		key->ed25519_pk = pk;
2159
		key->ed25519_pk = pk;
2102
		pk = NULL;
2160
		pk = NULL;
2103
		break;
2161
		break;
2162
#ifdef U2F
2163
	case KEY_U2F:
2164
		if ((ret = sshbuf_get_string(b, &pk, &len)) != 0)
2165
			goto out;
2166
		if (len != U2F_PUBKEY_LEN) {
2167
			ret = SSH_ERR_INVALID_FORMAT;
2168
			goto out;
2169
		}
2170
		if ((ret = sshbuf_get_string(b, &khandle, &len)) != 0)
2171
			goto out;
2172
		if ((key = sshkey_new(type)) == NULL) {
2173
			ret = SSH_ERR_ALLOC_FAIL;
2174
			goto out;
2175
		}
2176
		key->u2f_pubkey = pk;
2177
		key->u2f_key_handle_len = len;
2178
		key->u2f_key_handle = khandle;
2179
		pk = NULL;
2180
		khandle = NULL;
2181
		ret = SSH_ERR_ALLOC_FAIL;
2182
		break;
2183
#endif
2104
	case KEY_UNSPEC:
2184
	case KEY_UNSPEC:
2105
		if ((key = sshkey_new(type)) == NULL) {
2185
		if ((key = sshkey_new(type)) == NULL) {
2106
			ret = SSH_ERR_ALLOC_FAIL;
2186
			ret = SSH_ERR_ALLOC_FAIL;
Lines 2133-2138 sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp, Link Here
2133
	if (q != NULL)
2213
	if (q != NULL)
2134
		EC_POINT_free(q);
2214
		EC_POINT_free(q);
2135
#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
2215
#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
2216
#ifdef U2F
2217
	free(khandle);
2218
#endif
2136
	return ret;
2219
	return ret;
2137
}
2220
}
2138
2221
(-)a/sshkey.h (+6 lines)
Lines 62-67 enum sshkey_types { Link Here
62
	KEY_DSA_CERT,
62
	KEY_DSA_CERT,
63
	KEY_ECDSA_CERT,
63
	KEY_ECDSA_CERT,
64
	KEY_ED25519_CERT,
64
	KEY_ED25519_CERT,
65
	KEY_U2F,
65
	KEY_UNSPEC
66
	KEY_UNSPEC
66
};
67
};
67
68
Lines 106-111 struct sshkey { Link Here
106
	u_char	*ed25519_sk;
107
	u_char	*ed25519_sk;
107
	u_char	*ed25519_pk;
108
	u_char	*ed25519_pk;
108
	struct sshkey_cert *cert;
109
	struct sshkey_cert *cert;
110
#ifdef U2F
111
	u_char *u2f_pubkey;
112
	u_int   u2f_key_handle_len;
113
	u_char *u2f_key_handle;
114
#endif
109
};
115
};
110
116
111
#define	ED25519_SK_SZ	crypto_sign_ed25519_SECRETKEYBYTES
117
#define	ED25519_SK_SZ	crypto_sign_ed25519_SECRETKEYBYTES
(-)a/u2f.h (-1 / +8 lines)
Line 0 Link Here
0
- 
1
#ifndef OPENSSH_U2F_H
2
#define OPENSSH_U2F_H
3
4
#define U2F_PUBKEY_LEN 65
5
#define U2F_MODE_REGISTRATION 0
6
#define U2F_MODE_AUTHENTICATION 1
7
8
#endif

Return to bug 2319