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

Collapse All | Expand All

(-)a/Makefile.in (+1 lines)
Lines 101-106 SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ Link Here
101
	auth2-none.o auth2-passwd.o auth2-pubkey.o \
101
	auth2-none.o auth2-passwd.o auth2-pubkey.o \
102
	monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \
102
	monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \
103
	kexc25519s.o auth-krb5.o \
103
	kexc25519s.o auth-krb5.o \
104
	auth-u2f.o \
104
	auth2-gss.o gss-serv.o gss-serv-krb5.o \
105
	auth2-gss.o gss-serv.o gss-serv-krb5.o \
105
	loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
106
	loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
106
	sftp-server.o sftp-common.o \
107
	sftp-server.o sftp-common.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 73-78 struct Authctxt { Link Here
73
	char		*krb5_ticket_file;
73
	char		*krb5_ticket_file;
74
	char		*krb5_ccname;
74
	char		*krb5_ccname;
75
#endif
75
#endif
76
#ifdef U2F
77
	Key         *u2f_key;
78
	char        *u2f_challenge;
79
	int          u2f_attempt;
80
#endif
76
	Buffer		*loginmsg;
81
	Buffer		*loginmsg;
77
	void		*methoddata;
82
	void		*methoddata;
78
};
83
};
Lines 124-129 int user_key_allowed(struct passwd *, Key *); Link Here
124
void	 pubkey_auth_info(Authctxt *, const Key *, const char *, ...)
129
void	 pubkey_auth_info(Authctxt *, const Key *, const char *, ...)
125
	    __attribute__((__format__ (printf, 3, 4)));
130
	    __attribute__((__format__ (printf, 3, 4)));
126
131
132
#ifdef U2F
133
Key	 *read_user_u2f_key(struct passwd *, u_int);
134
int	 verify_u2f_user(Key *, u_char *, size_t, u_char *, size_t);
135
#endif
136
127
struct stat;
137
struct stat;
128
int	 auth_secure_path(const char *, struct stat *, const char *, uid_t,
138
int	 auth_secure_path(const char *, struct stat *, const char *, uid_t,
129
    char *, size_t);
139
    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/config.h.in (+8 lines)
Lines 1607-1612 Link Here
1607
/* syslog_r function is safe to use in in a signal handler */
1607
/* syslog_r function is safe to use in in a signal handler */
1608
#undef SYSLOG_R_SAFE_IN_SIGHAND
1608
#undef SYSLOG_R_SAFE_IN_SIGHAND
1609
1609
1610
/* Enable U2F support (using libu2f-host) */
1611
#undef U2F
1612
1610
/* Support passwords > 8 chars */
1613
/* Support passwords > 8 chars */
1611
#undef UNIXWARE_LONG_PASSWORDS
1614
#undef UNIXWARE_LONG_PASSWORDS
1612
1615
Lines 1686-1691 Link Here
1686
/* Define if xauth is found in your path */
1689
/* Define if xauth is found in your path */
1687
#undef XAUTH_PATH
1690
#undef XAUTH_PATH
1688
1691
1692
/* Enable large inode numbers on Mac OS X 10.5.  */
1693
#ifndef _DARWIN_USE_64_BIT_INODE
1694
# define _DARWIN_USE_64_BIT_INODE 1
1695
#endif
1696
1689
/* Number of bits in a file offset, on hosts where this is settable. */
1697
/* Number of bits in a file offset, on hosts where this is settable. */
1690
#undef _FILE_OFFSET_BITS
1698
#undef _FILE_OFFSET_BITS
1691
1699
(-)a/configure.ac (-3 / +57 lines)
Lines 1380-1385 AC_ARG_WITH([skey], Link Here
1380
	]
1380
	]
1381
)
1381
)
1382
1382
1383
# Check whether user wants u2f support (using libu2f-host)
1384
U2F_MSG="no"
1385
AC_ARG_WITH([u2f],
1386
	[  --with-u2f[[=PATH]]   Enable U2F support (using libu2f-host)],
1387
	[ if test "x$withval" != "xno" ; then
1388
		if test "x$withval" = "xyes" ; then
1389
			AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no])
1390
			if test "x$PKGCONFIG" != "xno"; then
1391
				AC_MSG_CHECKING([if $PKGCONFIG knows about u2f-host])
1392
			 	if "$PKGCONFIG" u2f-host; then
1393
					AC_MSG_RESULT([yes])
1394
					use_pkgconfig_for_libu2fhost=yes
1395
				else
1396
					AC_MSG_RESULT([no])
1397
				fi
1398
			fi
1399
		else
1400
			CPPFLAGS="$CPPFLAGS -I${withval}/include"
1401
			if test -n "${need_dash_r}"; then
1402
				LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}"
1403
			else
1404
				LDFLAGS="-L${withval}/lib ${LDFLAGS}"
1405
			fi
1406
		fi
1407
		if test "x$use_pkgconfig_for_libu2fhost" = "xyes"; then
1408
			LIBU2FHOST=`$PKGCONFIG --libs u2f-host`
1409
			CPPFLAGS="$CPPFLAGS `$PKGCONFIG --cflags u2f-host`"
1410
		else
1411
			LIBU2FHOST="-lu2f-host"
1412
		fi
1413
		LIBS="$LIBS $LIBU2FHOST"
1414
		AC_CHECK_LIB([u2f-host], [u2fh_global_init],
1415
			[ AC_DEFINE([U2F], [1], [Enable U2F support (using libu2f-host)])
1416
			  U2F_MSG="yes"
1417
			  AC_SUBST([LIBU2FHOST])
1418
			],
1419
			[ AC_MSG_ERROR([libu2f-host not found]) ],
1420
			[ $LIBS ]
1421
		)
1422
		AC_MSG_CHECKING([if libu2f-host version is compatible])
1423
		AC_COMPILE_IFELSE(
1424
		    [AC_LANG_PROGRAM([[ #include <u2f-host.h> ]],
1425
		    [[
1426
	u2fh_global_init(0);
1427
	exit(0);
1428
		    ]])],
1429
		    [ AC_MSG_RESULT([yes]) ],
1430
		    [ AC_MSG_RESULT([no])
1431
		      AC_MSG_ERROR([u2f-host version is not compatible]) ]
1432
		)
1433
	fi ]
1434
)
1435
1383
# Check whether user wants to use ldns
1436
# Check whether user wants to use ldns
1384
LDNS_MSG="no"
1437
LDNS_MSG="no"
1385
AC_ARG_WITH(ldns,
1438
AC_ARG_WITH(ldns,
Lines 2212-2218 AC_ARG_WITH([ssl-dir], Link Here
2212
		fi
2265
		fi
2213
	]
2266
	]
2214
)
2267
)
2215
LIBS="-lcrypto $LIBS"
2268
LIBS="-lcrypto -lssl $LIBS"
2216
AC_TRY_LINK_FUNC([RAND_add], [AC_DEFINE([HAVE_OPENSSL], [1],
2269
AC_TRY_LINK_FUNC([RAND_add], [AC_DEFINE([HAVE_OPENSSL], [1],
2217
	[Define if your ssl headers are included
2270
	[Define if your ssl headers are included
2218
	with #include <openssl/header.h>])],
2271
	with #include <openssl/header.h>])],
Lines 2295-2302 AC_RUN_IFELSE( Link Here
2295
		ssl_library_ver=`cat conftest.ssllibver`
2348
		ssl_library_ver=`cat conftest.ssllibver`
2296
		# Check version is supported.
2349
		# Check version is supported.
2297
		case "$ssl_library_ver" in
2350
		case "$ssl_library_ver" in
2298
			0090[[0-7]]*|009080[[0-5]]*)
2351
			0090*)
2299
				AC_MSG_ERROR([OpenSSL >= 0.9.8f required])
2352
				AC_MSG_ERROR([OpenSSL >= 1.0.0 required])
2300
		                ;;
2353
		                ;;
2301
		        *) ;;
2354
		        *) ;;
2302
		esac
2355
		esac
Lines 4829-4834 echo " KerberosV support: $KRB5_MSG" Link Here
4829
echo "                   SELinux support: $SELINUX_MSG"
4882
echo "                   SELinux support: $SELINUX_MSG"
4830
echo "                 Smartcard support: $SCARD_MSG"
4883
echo "                 Smartcard support: $SCARD_MSG"
4831
echo "                     S/KEY support: $SKEY_MSG"
4884
echo "                     S/KEY support: $SKEY_MSG"
4885
echo "                       U2F support: $U2F_MSG"
4832
echo "              MD5 password support: $MD5_MSG"
4886
echo "              MD5 password support: $MD5_MSG"
4833
echo "                   libedit support: $LIBEDIT_MSG"
4887
echo "                   libedit support: $LIBEDIT_MSG"
4834
echo "  Solaris process contract support: $SPC_MSG"
4888
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 185-190 int mm_answer_audit_event(int, Buffer *); Link Here
185
int mm_answer_audit_command(int, Buffer *);
186
int mm_answer_audit_command(int, Buffer *);
186
#endif
187
#endif
187
188
189
#ifdef U2F
190
int mm_answer_read_user_u2f_key(int, Buffer *);
191
int mm_answer_verify_u2f_user(int, Buffer *);
192
#endif
193
188
static int monitor_read_log(struct monitor *);
194
static int monitor_read_log(struct monitor *);
189
195
190
static Authctxt *authctxt;
196
static Authctxt *authctxt;
Lines 256-261 struct mon_table mon_dispatch_proto20[] = { Link Here
256
    {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
262
    {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
257
    {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
263
    {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
258
#endif
264
#endif
265
#ifdef U2F
266
    {MONITOR_REQ_READUSERU2FKEY, MON_AUTH, mm_answer_read_user_u2f_key},
267
    {MONITOR_REQ_VERIFYU2FUSER, MON_AUTH, mm_answer_verify_u2f_user},
268
#endif
259
    {0, 0, NULL}
269
    {0, 0, NULL}
260
};
270
};
261
271
Lines 1752-1757 mm_answer_audit_event(int socket, Buffer *m) Link Here
1752
	case SSH_AUTH_FAIL_PUBKEY:
1762
	case SSH_AUTH_FAIL_PUBKEY:
1753
	case SSH_AUTH_FAIL_HOSTBASED:
1763
	case SSH_AUTH_FAIL_HOSTBASED:
1754
	case SSH_AUTH_FAIL_GSSAPI:
1764
	case SSH_AUTH_FAIL_GSSAPI:
1765
	case SSH_AUTH_FAIL_U2F:
1755
	case SSH_LOGIN_EXCEED_MAXTRIES:
1766
	case SSH_LOGIN_EXCEED_MAXTRIES:
1756
	case SSH_LOGIN_ROOT_DENIED:
1767
	case SSH_LOGIN_ROOT_DENIED:
1757
	case SSH_CONNECTION_CLOSE:
1768
	case SSH_CONNECTION_CLOSE:
Lines 2164-2166 mm_answer_gss_userok(int sock, Buffer *m) Link Here
2164
}
2175
}
2165
#endif /* GSSAPI */
2176
#endif /* GSSAPI */
2166
2177
2178
#ifdef U2F
2179
int
2180
mm_answer_read_user_u2f_key(int sock, Buffer *m)
2181
{
2182
	int authenticated = 0;
2183
	Key *key;
2184
	u_int key_idx;
2185
	u_char *blob = NULL;
2186
	u_int blen = 0;
2187
2188
	key_idx = buffer_get_int(m);
2189
	buffer_clear(m);
2190
2191
	key = read_user_u2f_key(authctxt->pw, key_idx);
2192
	buffer_put_int(m, key == NULL ? 1 : 0);
2193
	if (key != NULL)
2194
	{
2195
		if (key_to_blob(key, &blob, &blen) == 0)
2196
			fatal("%s: key_to_blob failed", __func__);
2197
		buffer_put_string(m, blob, blen);
2198
		debug3("%s: sending key", __func__);
2199
	} else {
2200
		debug3("%s: no key to send", __func__);
2201
		if (key_idx == 0) {
2202
			auth_method = "u2f";
2203
			authenticated = 1;
2204
		}
2205
	}
2206
2207
	mm_request_send(sock, MONITOR_ANS_READUSERU2FKEY, m);
2208
	return authenticated;
2209
}
2210
2211
int
2212
mm_answer_verify_u2f_user(int sock, Buffer *m)
2213
{
2214
	int authenticated = 0;
2215
	Key *key;
2216
	u_char *blob, *dgst, *sig;
2217
	u_int bloblen, dgstlen, siglen;
2218
2219
	blob = buffer_get_string(m, &bloblen);
2220
	key = key_from_blob(blob, bloblen);
2221
	dgst = buffer_get_string(m, &dgstlen);
2222
	sig = buffer_get_string(m, &siglen);
2223
2224
	buffer_clear(m);
2225
2226
	authenticated = verify_u2f_user(key, dgst, dgstlen, sig, siglen);
2227
	buffer_put_int(m, authenticated);
2228
2229
	auth_method = "u2f";
2230
	mm_request_send(sock, MONITOR_ANS_VERIFYU2FUSER, m);
2231
2232
	key_free(key);
2233
	return authenticated;
2234
}
2235
#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 1300-1302 mm_ssh_gssapi_userok(char *user) Link Here
1300
}
1301
}
1301
#endif /* GSSAPI */
1302
#endif /* GSSAPI */
1302
1303
1304
#ifdef U2F
1305
Key *
1306
mm_read_user_u2f_key(struct passwd *pw, u_int key_idx)
1307
{
1308
	Buffer m;
1309
	Key *key = NULL;
1310
	u_char *blob;
1311
	u_int blen;
1312
	u_int is_null;
1313
1314
	debug3("%s entering", __func__);
1315
1316
	buffer_init(&m);
1317
	buffer_put_int(&m, key_idx);
1318
1319
	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_READUSERU2FKEY, &m);
1320
	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_READUSERU2FKEY, &m);
1321
1322
	is_null = buffer_get_int(&m);
1323
	if (is_null == 0) {
1324
		blob = buffer_get_string(&m, &blen);
1325
		if ((key = key_from_blob(blob, blen)) == NULL)
1326
			fatal("%s: key_from_blob failed", __func__);
1327
1328
		free(blob);
1329
	}
1330
1331
	buffer_free(&m);
1332
	return key;
1333
}
1334
1335
int
1336
mm_verify_u2f_user(Key *key, u_char * dgst, size_t dgstlen, u_char * sig, size_t siglen)
1337
{
1338
	int authenticated = 0;
1339
	Buffer m;
1340
	u_char *blob;
1341
	u_int blen;
1342
1343
	debug3("%s entering", __func__);
1344
1345
	if (key_to_blob(key, &blob, &blen) == 0)
1346
		fatal("%s: key_to_blob failed", __func__);
1347
	buffer_init(&m);
1348
	buffer_put_string(&m, blob, blen);
1349
	free(blob);
1350
1351
	buffer_put_string(&m, dgst, dgstlen);
1352
	buffer_put_string(&m, sig, siglen);
1353
1354
	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_VERIFYU2FUSER, &m);
1355
	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_VERIFYU2FUSER, &m);
1356
1357
	authenticated = buffer_get_int(&m);
1358
	buffer_free(&m);
1359
1360
	return authenticated;
1361
}
1362
#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 (+11 lines)
Lines 144-149 typedef enum { Link Here
144
	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
144
	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
145
	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
145
	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
146
	oSendEnv, oControlPath, oControlMaster, oControlPersist,
146
	oSendEnv, oControlPath, oControlMaster, oControlPersist,
147
	oU2fMode,
147
	oHashKnownHosts,
148
	oHashKnownHosts,
148
	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
149
	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
149
	oVisualHostKey, oUseRoaming,
150
	oVisualHostKey, oUseRoaming,
Lines 190-195 static struct { Link Here
190
	{ "gssapiauthentication", oUnsupported },
191
	{ "gssapiauthentication", oUnsupported },
191
	{ "gssapidelegatecredentials", oUnsupported },
192
	{ "gssapidelegatecredentials", oUnsupported },
192
#endif
193
#endif
194
#ifdef U2F
195
	{ "u2fmode", oU2fMode },
196
#else
197
	{ "u2fmode", oUnsupported },
198
#endif
193
	{ "fallbacktorsh", oDeprecated },
199
	{ "fallbacktorsh", oDeprecated },
194
	{ "usersh", oDeprecated },
200
	{ "usersh", oDeprecated },
195
	{ "identityfile", oIdentityFile },
201
	{ "identityfile", oIdentityFile },
Lines 861-866 parse_time: Link Here
861
		intptr = &options->challenge_response_authentication;
867
		intptr = &options->challenge_response_authentication;
862
		goto parse_flag;
868
		goto parse_flag;
863
869
870
	case oU2fMode:
871
		charptr = &options->u2f_mode;
872
		goto parse_string;
873
864
	case oGssAuthentication:
874
	case oGssAuthentication:
865
		intptr = &options->gss_authentication;
875
		intptr = &options->gss_authentication;
866
		goto parse_flag;
876
		goto parse_flag;
Lines 1542-1547 initialize_options(Options * options) Link Here
1542
	options->password_authentication = -1;
1552
	options->password_authentication = -1;
1543
	options->kbd_interactive_authentication = -1;
1553
	options->kbd_interactive_authentication = -1;
1544
	options->kbd_interactive_devices = NULL;
1554
	options->kbd_interactive_devices = NULL;
1555
	options->u2f_mode = NULL;
1545
	options->rhosts_rsa_authentication = -1;
1556
	options->rhosts_rsa_authentication = -1;
1546
	options->hostbased_authentication = -1;
1557
	options->hostbased_authentication = -1;
1547
	options->batch_mode = -1;
1558
	options->batch_mode = -1;
(-)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 109-114 initialize_server_options(ServerOptions *options) Link Here
109
	options->kerberos_ticket_cleanup = -1;
109
	options->kerberos_ticket_cleanup = -1;
110
	options->kerberos_get_afs_token = -1;
110
	options->kerberos_get_afs_token = -1;
111
	options->gss_authentication=-1;
111
	options->gss_authentication=-1;
112
	options->u2f_authentication = -1;
112
	options->gss_cleanup_creds = -1;
113
	options->gss_cleanup_creds = -1;
113
	options->password_authentication = -1;
114
	options->password_authentication = -1;
114
	options->kbd_interactive_authentication = -1;
115
	options->kbd_interactive_authentication = -1;
Lines 250-255 fill_default_server_options(ServerOptions *options) Link Here
250
		options->kerberos_get_afs_token = 0;
251
		options->kerberos_get_afs_token = 0;
251
	if (options->gss_authentication == -1)
252
	if (options->gss_authentication == -1)
252
		options->gss_authentication = 0;
253
		options->gss_authentication = 0;
254
	// U2F authentication is disabled by default. On its own, it does not
255
	// provide adequate security, and it should be used as a second factor in
256
	// combination with publickey, for example.
257
	if (options->u2f_authentication == -1)
258
		options->u2f_authentication = 0;
253
	if (options->gss_cleanup_creds == -1)
259
	if (options->gss_cleanup_creds == -1)
254
		options->gss_cleanup_creds = 1;
260
		options->gss_cleanup_creds = 1;
255
	if (options->password_authentication == -1)
261
	if (options->password_authentication == -1)
Lines 353-358 typedef enum { Link Here
353
	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
359
	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
354
	sClientAliveCountMax, sAuthorizedKeysFile,
360
	sClientAliveCountMax, sAuthorizedKeysFile,
355
	sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
361
	sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
362
	sU2FAuthentication,
356
	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
363
	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
357
	sUsePrivilegeSeparation, sAllowAgentForwarding,
364
	sUsePrivilegeSeparation, sAllowAgentForwarding,
358
	sHostCertificate,
365
	sHostCertificate,
Lines 425-430 static struct { Link Here
425
	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
432
	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
426
	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
433
	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
427
#endif
434
#endif
435
#ifdef U2F
436
	{ "u2fauthentication", sU2FAuthentication, SSHCFG_ALL },
437
#else
438
	{ "u2fauthentication", sUnsupported, SSHCFG_ALL },
439
#endif
428
	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
440
	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
429
	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
441
	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
430
	{ "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
442
	{ "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
Lines 1108-1113 process_server_config_line(ServerOptions *options, char *line, Link Here
1108
		intptr = &options->gss_cleanup_creds;
1120
		intptr = &options->gss_cleanup_creds;
1109
		goto parse_flag;
1121
		goto parse_flag;
1110
1122
1123
	case sU2FAuthentication:
1124
		intptr = &options->u2f_authentication;
1125
		goto parse_flag;
1126
1111
	case sPasswordAuthentication:
1127
	case sPasswordAuthentication:
1112
		intptr = &options->password_authentication;
1128
		intptr = &options->password_authentication;
1113
		goto parse_flag;
1129
		goto parse_flag;
Lines 1792-1797 copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) Link Here
1792
1808
1793
	M_CP_INTOPT(password_authentication);
1809
	M_CP_INTOPT(password_authentication);
1794
	M_CP_INTOPT(gss_authentication);
1810
	M_CP_INTOPT(gss_authentication);
1811
	M_CP_INTOPT(u2f_authentication);
1795
	M_CP_INTOPT(rsa_authentication);
1812
	M_CP_INTOPT(rsa_authentication);
1796
	M_CP_INTOPT(pubkey_authentication);
1813
	M_CP_INTOPT(pubkey_authentication);
1797
	M_CP_INTOPT(kerberos_authentication);
1814
	M_CP_INTOPT(kerberos_authentication);
Lines 2044-2049 dump_config(ServerOptions *o) Link Here
2044
	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
2061
	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
2045
	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
2062
	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
2046
#endif
2063
#endif
2064
#ifdef U2F
2065
	dump_cfg_fmtint(sU2FAuthentication, o->u2f_authentication);
2066
#endif
2047
	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
2067
	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
2048
	dump_cfg_fmtint(sKbdInteractiveAuthentication,
2068
	dump_cfg_fmtint(sKbdInteractiveAuthentication,
2049
	    o->kbd_interactive_authentication);
2069
	    o->kbd_interactive_authentication);
(-)a/servconf.h (+1 lines)
Lines 118-123 typedef struct { Link Here
118
						 * authentication. */
118
						 * authentication. */
119
	int     kbd_interactive_authentication;	/* If true, permit */
119
	int     kbd_interactive_authentication;	/* If true, permit */
120
	int     challenge_response_authentication;
120
	int     challenge_response_authentication;
121
	int     u2f_authentication;
121
	int     permit_empty_passwd;	/* If false, do not permit empty
122
	int     permit_empty_passwd;	/* If false, do not permit empty
122
					 * passwords. */
123
					 * passwords. */
123
	int     permit_user_env;	/* If true, read ~/.ssh/environment */
124
	int     permit_user_env;	/* If true, read ~/.ssh/environment */
(-)a/ssh.1 (+1 lines)
Lines 475-480 For full details of the options listed below, and their possible values, see Link Here
475
.It TCPKeepAlive
475
.It TCPKeepAlive
476
.It Tunnel
476
.It Tunnel
477
.It TunnelDevice
477
.It TunnelDevice
478
.It U2FMode
478
.It UsePrivilegedPort
479
.It UsePrivilegedPort
479
.It User
480
.It User
480
.It UserKnownHostsFile
481
.It UserKnownHostsFile
(-)a/ssh.c (+10 lines)
Lines 78-83 Link Here
78
#include "openbsd-compat/openssl-compat.h"
78
#include "openbsd-compat/openssl-compat.h"
79
#include "openbsd-compat/sys-queue.h"
79
#include "openbsd-compat/sys-queue.h"
80
80
81
#ifdef U2F
82
#include <u2f-host.h>
83
#endif
84
81
#include "xmalloc.h"
85
#include "xmalloc.h"
82
#include "ssh.h"
86
#include "ssh.h"
83
#include "ssh1.h"
87
#include "ssh1.h"
Lines 843-848 main(int ac, char **av) Link Here
843
#ifdef WITH_OPENSSL
847
#ifdef WITH_OPENSSL
844
	OpenSSL_add_all_algorithms();
848
	OpenSSL_add_all_algorithms();
845
	ERR_load_crypto_strings();
849
	ERR_load_crypto_strings();
850
	SSL_load_error_strings();
851
#endif
852
853
#ifdef U2F
854
	if (u2fh_global_init(0) != U2FH_OK)
855
		fatal("u2fh_global_init() failed");
846
#endif
856
#endif
847
857
848
	/* Initialize the command to execute on remote host. */
858
	/* Initialize the command to execute on remote host. */
(-)a/ssh_config.5 (+7 lines)
Lines 1419-1424 is not specified, it defaults to Link Here
1419
.Dq any .
1419
.Dq any .
1420
The default is
1420
The default is
1421
.Dq any:any .
1421
.Dq any:any .
1422
.It Cm U2FMode
1423
Specifies which mode the U2F authentication method should use. Can be either
1424
.Dq authentication
1425
or
1426
.Dq registration .
1427
The default is
1428
.Dq authentication .
1422
.It Cm UsePrivilegedPort
1429
.It Cm UsePrivilegedPort
1423
Specifies whether to use a privileged port for outgoing connections.
1430
Specifies whether to use a privileged port for outgoing connections.
1424
The argument must be
1431
The argument must be
(-)a/sshconnect.c (-1 / +1 lines)
Lines 1305-1311 ssh_login(Sensitive *sensitive, const char *orighost, Link Here
1305
	/* authenticate user */
1305
	/* authenticate user */
1306
	if (compat20) {
1306
	if (compat20) {
1307
		ssh_kex2(host, hostaddr, port);
1307
		ssh_kex2(host, hostaddr, port);
1308
		ssh_userauth2(local_user, server_user, host, sensitive);
1308
		ssh_userauth2(local_user, server_user, host, port, sensitive);
1309
	} else {
1309
	} else {
1310
#ifdef WITH_SSH1
1310
#ifdef WITH_SSH1
1311
		ssh_kex(host, hostaddr);
1311
		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 / +174 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 70-75 Link Here
70
#include "pathnames.h"
76
#include "pathnames.h"
71
#include "uidswap.h"
77
#include "uidswap.h"
72
#include "hostfile.h"
78
#include "hostfile.h"
79
#include "u2f.h"
73
80
74
#ifdef GSSAPI
81
#ifdef GSSAPI
75
#include "ssh-gss.h"
82
#include "ssh-gss.h"
Lines 262-267 struct Authctxt { Link Here
262
	const char *server_user;
269
	const char *server_user;
263
	const char *local_user;
270
	const char *local_user;
264
	const char *host;
271
	const char *host;
272
	char *host_port;
265
	const char *service;
273
	const char *service;
266
	Authmethod *method;
274
	Authmethod *method;
267
	sig_atomic_t success;
275
	sig_atomic_t success;
Lines 308-313 void input_gssapi_error(int, u_int32_t, void *); Link Here
308
void	input_gssapi_errtok(int, u_int32_t, void *);
316
void	input_gssapi_errtok(int, u_int32_t, void *);
309
#endif
317
#endif
310
318
319
#ifdef U2F
320
int userauth_u2f(Authctxt *authctxt);
321
void input_userauth_u2f_authenticate(int type, u_int32_t seq, void *ctxt);
322
void input_userauth_u2f_register(int type, u_int32_t seq, void *ctxt);
323
void input_userauth_u2f_register_response(int type, u_int32_t seq, void *ctxt);
324
#endif
325
311
void	userauth(Authctxt *, char *);
326
void	userauth(Authctxt *, char *);
312
327
313
static int sign_and_send_pubkey(Authctxt *, Identity *);
328
static int sign_and_send_pubkey(Authctxt *, Identity *);
Lines 320-325 static Authmethod *authmethod_lookup(const char *name); Link Here
320
static char *authmethods_get(void);
335
static char *authmethods_get(void);
321
336
322
Authmethod authmethods[] = {
337
Authmethod authmethods[] = {
338
	// U2F needs to be the first authentication method, so that we use it once
339
	// the server allows it. This enables server configurations containing e.g.:
340
	// AuthenticationMethods password,u2f pubkey,u2f
341
#ifdef U2F
342
    {"u2f",
343
        userauth_u2f,
344
        NULL,
345
        &options.u2f_authentication,
346
        NULL},
347
#endif
323
#ifdef GSSAPI
348
#ifdef GSSAPI
324
	{"gssapi-with-mic",
349
	{"gssapi-with-mic",
325
		userauth_gssapi,
350
		userauth_gssapi,
Lines 357-363 Authmethod authmethods[] = { Link Here
357
382
358
void
383
void
359
ssh_userauth2(const char *local_user, const char *server_user, char *host,
384
ssh_userauth2(const char *local_user, const char *server_user, char *host,
360
    Sensitive *sensitive)
385
    u_short port, Sensitive *sensitive)
361
{
386
{
362
	Authctxt authctxt;
387
	Authctxt authctxt;
363
	int type;
388
	int type;
Lines 392-397 ssh_userauth2(const char *local_user, const char *server_user, char *host, Link Here
392
	authctxt.server_user = server_user;
417
	authctxt.server_user = server_user;
393
	authctxt.local_user = local_user;
418
	authctxt.local_user = local_user;
394
	authctxt.host = host;
419
	authctxt.host = host;
420
	get_hostfile_hostname_ipaddr(host, NULL, port, &authctxt.host_port, NULL);
395
	authctxt.service = "ssh-connection";		/* service name */
421
	authctxt.service = "ssh-connection";		/* service name */
396
	authctxt.success = 0;
422
	authctxt.success = 0;
397
	authctxt.method = authmethod_lookup("none");
423
	authctxt.method = authmethod_lookup("none");
Lines 838-843 input_gssapi_error(int type, u_int32_t plen, void *ctxt) Link Here
838
}
864
}
839
#endif /* GSSAPI */
865
#endif /* GSSAPI */
840
866
867
#ifdef U2F
868
int
869
userauth_u2f(Authctxt *authctxt)
870
{
871
	// first step: we dont send anything, but install a custom dispatcher.
872
	debug("sshconnect2:userauth_u2f");
873
874
	// For U2F_MODE_REGISTRATION, this code path will return 0, meaning the
875
	// authentication method will not be retried. If we did not do that, we
876
	// would loop endlessly.
877
	if (authctxt->info_req_seen) {
878
		dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL);
879
		return 0;
880
	}
881
882
	packet_start(SSH2_MSG_USERAUTH_REQUEST);
883
	packet_put_cstring(authctxt->server_user);
884
	packet_put_cstring(authctxt->service);
885
	packet_put_cstring(authctxt->method->name);
886
	if (options.u2f_mode == NULL || strcasecmp(options.u2f_mode, "authentication") == 0) {
887
		packet_put_int(U2F_MODE_AUTHENTICATION);
888
		dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_u2f_authenticate);
889
	} else if (options.u2f_mode != NULL && strcasecmp(options.u2f_mode, "registration") == 0) {
890
		packet_put_int(U2F_MODE_REGISTRATION);
891
		dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_u2f_register);
892
	} else {
893
		fatal("Invalid U2F mode (\"%s\"), expected \"authentication\" or \"registration\".",
894
				options.u2f_mode);
895
	}
896
	packet_send();
897
898
	return 1;
899
}
900
901
static void
902
wait_for_u2f_devices(u2fh_devs *devs)
903
{
904
	time_t looking;
905
	int attempts = 0;
906
	u2fh_rc rc;
907
908
	// The U2F implementation considerations recommend 3 seconds as the time a
909
	// client implementation should grant for security keys to respond. We wait
910
	// 3 times that for the user to insert a security key (and it being
911
	// detected).
912
	looking = monotime();
913
	do {
914
		if ((rc = u2fh_devs_discover(devs, NULL)) != U2FH_OK && attempts++ == 0)
915
			error("Please insert and touch your U2F security key.");
916
		if (rc != U2FH_OK)
917
			usleep(50);
918
	} while (rc != U2FH_OK && (monotime() - looking) <= 9);
919
	if (rc != U2FH_OK)
920
		fatal("No U2F devices found (%s). Did you plug in your U2F security key?",
921
				u2fh_strerror(rc));
922
923
	if (attempts == 0)
924
		error("Please touch your U2F security key now.");
925
}
926
927
void
928
input_userauth_u2f_register(int type, u_int32_t seq, void *ctxt)
929
{
930
	Authctxt *authctxt = ctxt;
931
	char *challenge, *response;
932
	u2fh_devs *devs = NULL;
933
	u2fh_rc rc;
934
	const char *origin = authctxt->host_port;
935
936
	if (authctxt == NULL)
937
		fatal("input_userauth_u2f_register: no authentication context");
938
939
	authctxt->info_req_seen = 1;
940
941
	challenge = packet_get_string(NULL);
942
	packet_check_eom();
943
944
	if ((rc = u2fh_devs_init(&devs)) != U2FH_OK)
945
		fatal("u2fh_devs_init() failed: %s", u2fh_strerror(rc));
946
947
	wait_for_u2f_devices(devs);
948
949
	if ((rc = u2fh_register(devs, challenge, origin, &response, U2FH_REQUEST_USER_PRESENCE)) != U2FH_OK)
950
		fatal("u2fh_register() failed: %s", u2fh_strerror(rc));
951
952
	u2fh_devs_done(devs);
953
954
	packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
955
	packet_put_cstring(response);
956
	packet_send();
957
958
	free(response);
959
	dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL);
960
	dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_u2f_register_response);
961
}
962
963
void
964
input_userauth_u2f_register_response(int type, u_int32_t seq, void *ctxt)
965
{
966
	char *response = packet_get_string(NULL);
967
	printf("%s\n", response);
968
	fflush(stdout);
969
}
970
971
void
972
input_userauth_u2f_authenticate(int type, u_int32_t seq, void *ctxt)
973
{
974
	Authctxt *authctxt = ctxt;
975
	char *challenge, *response;
976
	u2fh_devs *devs = NULL;
977
	u2fh_rc rc;
978
	const char *origin = authctxt->host_port;
979
980
	if (authctxt == NULL)
981
		fatal("input_userauth_u2f_authenticate: no authentication context");
982
983
	authctxt->info_req_seen = 1;
984
985
	challenge = packet_get_string(NULL);
986
	packet_check_eom();
987
988
	debug("Starting U2F authentication for origin \"%s\".", origin);
989
990
	if ((rc = u2fh_devs_init(&devs)) != U2FH_OK)
991
		fatal("u2fh_devs_init() failed: %s", u2fh_strerror(rc));
992
993
	wait_for_u2f_devices(devs);
994
995
	// TODO: refactor with input_userauth_u2f_register(), the following line is the only one that is different :)
996
	if ((rc = u2fh_authenticate(devs, challenge, origin, &response, U2FH_REQUEST_USER_PRESENCE)) != U2FH_OK)
997
		fatal("u2fh_authenticate() 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
1007
	// We intentionally do not set SSH2_MSG_USERAUTH_INFO_REQUEST to NULL,
1008
	// because the server might send us more challenges (in case more than one
1009
	// U2F security key is in the authorized_keys).
1010
}
1011
1012
#endif /* U2F */
1013
841
int
1014
int
842
userauth_none(Authctxt *authctxt)
1015
userauth_none(Authctxt *authctxt)
843
{
1016
{
(-)a/sshd.c (+1 lines)
Lines 1562-1567 main(int ac, char **av) Link Here
1562
1562
1563
#ifdef WITH_OPENSSL
1563
#ifdef WITH_OPENSSL
1564
	OpenSSL_add_all_algorithms();
1564
	OpenSSL_add_all_algorithms();
1565
	SSL_load_error_strings();
1565
#endif
1566
#endif
1566
1567
1567
	/* If requested, redirect the logs to the specified logfile. */
1568
	/* If requested, redirect the logs to the specified logfile. */
(-)a/sshd_config.5 (+19 lines)
Lines 1293-1298 for authentication using Link Here
1293
.Cm TrustedUserCAKeys .
1293
.Cm TrustedUserCAKeys .
1294
For more details on certificates, see the CERTIFICATES section in
1294
For more details on certificates, see the CERTIFICATES section in
1295
.Xr ssh-keygen 1 .
1295
.Xr ssh-keygen 1 .
1296
.It Cm U2FAuthentication
1297
Specifies whether user authentication based on U2F (Universal Second Factor) is allowed. The default is
1298
.Dq no .
1299
Note that U2F authentication should never be used alone, so specify for example:
1300
.Bd -literal -offset indent
1301
U2FAuthentication yes
1302
AuthenticationMethods pubkey,u2f
1303
.Ed
1304
.Pp
1305
That way, pubkey authentication will be performed and U2F will be required
1306
after pubkey authentication was successful. In case the user in question does
1307
not have any ssh-u2f lines in their authorized_keys file, the u2f
1308
authentication method will just return success.
1309
.Pp
1310
In order to register a U2F security key, enable this option as outlined above.
1311
Then, run
1312
.Dq ssh -o U2FMode=registration server.example.net
1313
in order to obtain a ssh-u2f line which you can then append to your
1314
authorized_keys.
1296
.It Cm UseDNS
1315
.It Cm UseDNS
1297
Specifies whether
1316
Specifies whether
1298
.Xr sshd 8
1317
.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 52-57 Link Here
52
#include "digest.h"
53
#include "digest.h"
53
#define SSHKEY_INTERNAL
54
#define SSHKEY_INTERNAL
54
#include "sshkey.h"
55
#include "sshkey.h"
56
#include "key.h"
57
#include "hostfile.h"
58
#include "auth.h"
59
#include "u2f.h"
55
60
56
/* openssh private key file format */
61
/* openssh private key file format */
57
#define MARK_BEGIN		"-----BEGIN OPENSSH PRIVATE KEY-----\n"
62
#define MARK_BEGIN		"-----BEGIN OPENSSH PRIVATE KEY-----\n"
Lines 110-115 static const struct keytype keytypes[] = { Link Here
110
	{ "ssh-dss-cert-v00@openssh.com", "DSA-CERT-V00",
115
	{ "ssh-dss-cert-v00@openssh.com", "DSA-CERT-V00",
111
	    KEY_DSA_CERT_V00, 0, 1 },
116
	    KEY_DSA_CERT_V00, 0, 1 },
112
#endif /* WITH_OPENSSL */
117
#endif /* WITH_OPENSSL */
118
	{ "ssh-u2f", "U2F", KEY_U2F, 0, 0 },
113
	{ NULL, NULL, -1, -1, 0 }
119
	{ NULL, NULL, -1, -1, 0 }
114
};
120
};
115
121
Lines 508-513 sshkey_new(int type) Link Here
508
		break;
514
		break;
509
	case KEY_UNSPEC:
515
	case KEY_UNSPEC:
510
		break;
516
		break;
517
	case KEY_U2F:
518
		break;
511
	default:
519
	default:
512
		free(k);
520
		free(k);
513
		return NULL;
521
		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 1208-1213 sshkey_read(struct sshkey *ret, char **cpp) Link Here
1208
		retval = 0;
1227
		retval = 0;
1209
#endif /* WITH_SSH1 */
1228
#endif /* WITH_SSH1 */
1210
		break;
1229
		break;
1230
	case KEY_U2F:
1231
#ifdef U2F
1232
		space = strchr(cp, ' ');
1233
		if (space == NULL)
1234
			return SSH_ERR_INVALID_FORMAT;
1235
		*space = '\0';
1236
		type = sshkey_type_from_name(cp);
1237
		if (type == KEY_UNSPEC)
1238
			return SSH_ERR_INVALID_FORMAT;
1239
		cp = space+1;
1240
		if (*cp == '\0')
1241
			return SSH_ERR_INVALID_FORMAT;
1242
		if (ret->type == KEY_UNSPEC) {
1243
			ret->type = type;
1244
		} else if (ret->type != type)
1245
			return SSH_ERR_KEY_TYPE_MISMATCH;
1246
		cp = space+1;
1247
		/* trim comment */
1248
		space = strchr(cp, ' ');
1249
		if (space)
1250
			*space = '\0';
1251
		blob = sshbuf_new();
1252
		if ((r = sshbuf_b64tod(blob, cp)) != 0) {
1253
			sshbuf_free(blob);
1254
			return r;
1255
		}
1256
		// TODO: why do we _need_ to use malloc here? xmalloc gives memory that crashes!
1257
		ret->u2f_pubkey = malloc(U2F_PUBKEY_LEN);
1258
		memcpy(ret->u2f_pubkey, sshbuf_ptr(blob), U2F_PUBKEY_LEN);
1259
		ret->u2f_key_handle_len = sshbuf_len(blob) - U2F_PUBKEY_LEN;
1260
		ret->u2f_key_handle = malloc(ret->u2f_key_handle_len);
1261
		memcpy(ret->u2f_key_handle, sshbuf_ptr(blob) + U2F_PUBKEY_LEN, ret->u2f_key_handle_len);
1262
		sshbuf_free(blob);
1263
		retval = (r >= 0) ? 0 : 1;
1264
#endif /* U2F */
1265
		break;
1211
	case KEY_UNSPEC:
1266
	case KEY_UNSPEC:
1212
	case KEY_RSA:
1267
	case KEY_RSA:
1213
	case KEY_DSA:
1268
	case KEY_DSA:
Lines 1909-1914 sshkey_from_blob_internal(const u_char *blob, size_t blen, Link Here
1909
#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
1964
#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
1910
	EC_POINT *q = NULL;
1965
	EC_POINT *q = NULL;
1911
#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
1966
#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
1967
#ifdef U2F
1968
	u_char *khandle = NULL;
1969
#endif
1912
1970
1913
#ifdef DEBUG_PK /* XXX */
1971
#ifdef DEBUG_PK /* XXX */
1914
	dump_base64(stderr, blob, blen);
1972
	dump_base64(stderr, blob, blen);
Lines 2046-2051 sshkey_from_blob_internal(const u_char *blob, size_t blen, Link Here
2046
		key->ed25519_pk = pk;
2104
		key->ed25519_pk = pk;
2047
		pk = NULL;
2105
		pk = NULL;
2048
		break;
2106
		break;
2107
#ifdef U2F
2108
	case KEY_U2F:
2109
		if ((ret = sshbuf_get_string(b, &pk, &len)) != 0)
2110
			goto out;
2111
		if (len != U2F_PUBKEY_LEN) {
2112
			ret = SSH_ERR_INVALID_FORMAT;
2113
			goto out;
2114
		}
2115
		if ((ret = sshbuf_get_string(b, &khandle, &len)) != 0)
2116
			goto out;
2117
		if ((key = sshkey_new(type)) == NULL) {
2118
			ret = SSH_ERR_ALLOC_FAIL;
2119
			goto out;
2120
		}
2121
		key->u2f_pubkey = pk;
2122
		key->u2f_key_handle_len = len;
2123
		key->u2f_key_handle = khandle;
2124
		pk = NULL;
2125
		khandle = NULL;
2126
		ret = SSH_ERR_ALLOC_FAIL;
2127
		break;
2128
#endif
2049
	case KEY_UNSPEC:
2129
	case KEY_UNSPEC:
2050
		if ((key = sshkey_new(type)) == NULL) {
2130
		if ((key = sshkey_new(type)) == NULL) {
2051
			ret = SSH_ERR_ALLOC_FAIL;
2131
			ret = SSH_ERR_ALLOC_FAIL;
Lines 2079-2084 sshkey_from_blob_internal(const u_char *blob, size_t blen, Link Here
2079
	if (q != NULL)
2159
	if (q != NULL)
2080
		EC_POINT_free(q);
2160
		EC_POINT_free(q);
2081
#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
2161
#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
2162
#ifdef U2F
2163
	free(khandle);
2164
#endif
2082
	return ret;
2165
	return ret;
2083
}
2166
}
2084
2167
(-)a/sshkey.h (+6 lines)
Lines 64-69 enum sshkey_types { Link Here
64
	KEY_ED25519_CERT,
64
	KEY_ED25519_CERT,
65
	KEY_RSA_CERT_V00,
65
	KEY_RSA_CERT_V00,
66
	KEY_DSA_CERT_V00,
66
	KEY_DSA_CERT_V00,
67
	KEY_U2F,
67
	KEY_UNSPEC
68
	KEY_UNSPEC
68
};
69
};
69
70
Lines 110-115 struct sshkey { Link Here
110
	u_char	*ed25519_sk;
111
	u_char	*ed25519_sk;
111
	u_char	*ed25519_pk;
112
	u_char	*ed25519_pk;
112
	struct sshkey_cert *cert;
113
	struct sshkey_cert *cert;
114
#ifdef U2F
115
	u_char *u2f_pubkey;
116
	u_int   u2f_key_handle_len;
117
	u_char *u2f_key_handle;
118
#endif
113
};
119
};
114
120
115
#define	ED25519_SK_SZ	crypto_sign_ed25519_SECRETKEYBYTES
121
#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