1/*	$NetBSD: auth2-jpake.c,v 1.3 2009/12/27 01:40:46 christos Exp $	*/
2/* $OpenBSD: auth2-jpake.c,v 1.4 2010/08/31 11:54:45 djm Exp $ */
3/*
4 * Copyright (c) 2008 Damien Miller.  All rights reserved.
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/*
20 * Server side of zero-knowledge password auth using J-PAKE protocol
21 * as described in:
22 *
23 * F. Hao, P. Ryan, "Password Authenticated Key Exchange by Juggling",
24 * 16th Workshop on Security Protocols, Cambridge, April 2008
25 *
26 * http://grouper.ieee.org/groups/1363/Research/contributions/hao-ryan-2008.pdf
27 */
28
29#ifdef JPAKE
30
31#include <sys/types.h>
32#include <sys/param.h>
33
34#include <pwd.h>
35#include <stdio.h>
36#include <string.h>
37#include <login_cap.h>
38
39#include <openssl/bn.h>
40#include <openssl/evp.h>
41
42#include "xmalloc.h"
43#include "ssh2.h"
44#include "key.h"
45#include "hostfile.h"
46#include "auth.h"
47#include "buffer.h"
48#include "packet.h"
49#include "dispatch.h"
50#include "log.h"
51#include "servconf.h"
52#include "auth-options.h"
53#include "canohost.h"
54#ifdef GSSAPI
55#include "ssh-gss.h"
56#endif
57#include "monitor_wrap.h"
58
59#include "schnorr.h"
60#include "jpake.h"
61
62/*
63 * XXX options->permit_empty_passwd (at the moment, they will be refused
64 * anyway because they will mismatch on fake salt.
65 */
66
67/* Dispatch handlers */
68static void input_userauth_jpake_client_step1(int, u_int32_t, void *);
69static void input_userauth_jpake_client_step2(int, u_int32_t, void *);
70static void input_userauth_jpake_client_confirm(int, u_int32_t, void *);
71
72static int auth2_jpake_start(Authctxt *);
73
74/* import */
75extern ServerOptions options;
76extern u_char *session_id2;
77extern u_int session_id2_len;
78
79/*
80 * Attempt J-PAKE authentication.
81 */
82static int
83userauth_jpake(Authctxt *authctxt)
84{
85	int authenticated = 0;
86
87	packet_check_eom();
88
89	debug("jpake-01@openssh.com requested");
90
91	if (authctxt->user != NULL) {
92		if (authctxt->jpake_ctx == NULL)
93			authctxt->jpake_ctx = jpake_new();
94		if (options.zero_knowledge_password_authentication)
95			authenticated = auth2_jpake_start(authctxt);
96	}
97
98	return authenticated;
99}
100
101Authmethod method_jpake = {
102	"jpake-01@openssh.com",
103	userauth_jpake,
104	&options.zero_knowledge_password_authentication
105};
106
107/* Clear context and callbacks */
108void
109auth2_jpake_stop(Authctxt *authctxt)
110{
111	/* unregister callbacks */
112	dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1, NULL);
113	dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2, NULL);
114	dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM, NULL);
115	if (authctxt->jpake_ctx != NULL) {
116		jpake_free(authctxt->jpake_ctx);
117		authctxt->jpake_ctx = NULL;
118	}
119}
120
121/* Returns 1 if 'c' is a valid crypt(3) salt character, 0 otherwise */
122static int
123valid_crypt_salt(int c)
124{
125	if (c >= 'A' && c <= 'Z')
126		return 1;
127	if (c >= 'a' && c <= 'z')
128		return 1;
129	if (c >= '.' && c <= '9')
130		return 1;
131	return 0;
132}
133
134/*
135 * Derive fake salt as H(username || first_private_host_key)
136 * This provides relatively stable fake salts for non-existent
137 * users and avoids the jpake method becoming an account validity
138 * oracle.
139 */
140static void
141derive_rawsalt(const char *username, u_char *rawsalt, u_int len)
142{
143	u_char *digest;
144	u_int digest_len;
145	Buffer b;
146	Key *k;
147
148	buffer_init(&b);
149	buffer_put_cstring(&b, username);
150	if ((k = get_hostkey_by_index(0)) == NULL ||
151	    (k->flags & KEY_FLAG_EXT))
152		fatal("%s: no hostkeys", __func__);
153	switch (k->type) {
154	case KEY_RSA1:
155	case KEY_RSA:
156		if (k->rsa->p == NULL || k->rsa->q == NULL)
157			fatal("%s: RSA key missing p and/or q", __func__);
158		buffer_put_bignum2(&b, k->rsa->p);
159		buffer_put_bignum2(&b, k->rsa->q);
160		break;
161	case KEY_DSA:
162		if (k->dsa->priv_key == NULL)
163			fatal("%s: DSA key missing priv_key", __func__);
164		buffer_put_bignum2(&b, k->dsa->priv_key);
165		break;
166	case KEY_ECDSA:
167		if (EC_KEY_get0_private_key(k->ecdsa) == NULL)
168			fatal("%s: ECDSA key missing priv_key", __func__);
169		buffer_put_bignum2(&b, EC_KEY_get0_private_key(k->ecdsa));
170		break;
171	default:
172		fatal("%s: unknown key type %d", __func__, k->type);
173	}
174	if (hash_buffer(buffer_ptr(&b), buffer_len(&b), EVP_sha256(),
175	    &digest, &digest_len) != 0)
176		fatal("%s: hash_buffer", __func__);
177	buffer_free(&b);
178	if (len > digest_len)
179		fatal("%s: not enough bytes for rawsalt (want %u have %u)",
180		    __func__, len, digest_len);
181	memcpy(rawsalt, digest, len);
182	bzero(digest, digest_len);
183	xfree(digest);
184}
185
186/* ASCII an integer [0, 64) for inclusion in a password/salt */
187static char
188pw_encode64(u_int i64)
189{
190	const u_char e64[] =
191	    "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
192	return e64[i64 % 64];
193}
194
195/* Generate ASCII salt bytes for user */
196static char *
197makesalt(u_int want, const char *user)
198{
199	u_char rawsalt[32];
200	static char ret[33];
201	u_int i;
202
203	if (want > sizeof(ret) - 1)
204		fatal("%s: want %u", __func__, want);
205
206	derive_rawsalt(user, rawsalt, sizeof(rawsalt));
207	bzero(ret, sizeof(ret));
208	for (i = 0; i < want; i++)
209		ret[i] = pw_encode64(rawsalt[i]);
210	bzero(rawsalt, sizeof(rawsalt));
211
212	return ret;
213}
214
215/*
216 * Select the system's default password hashing scheme and generate
217 * a stable fake salt under it for use by a non-existent account.
218 * Prevents jpake method being used to infer the validity of accounts.
219 */
220static void
221fake_salt_and_scheme(Authctxt *authctxt, char **salt, char **scheme)
222{
223	char *rounds_s, *style;
224	long long rounds;
225	login_cap_t *lc;
226
227
228	if ((lc = login_getclass(authctxt->pw->pw_class)) == NULL &&
229	    (lc = login_getclass(NULL)) == NULL)
230		fatal("%s: login_getclass failed", __func__);
231	style = login_getcapstr(lc, "localcipher", NULL, NULL);
232	if (style == NULL)
233		style = xstrdup("blowfish,6");
234	login_close(lc);
235
236	if ((rounds_s = strchr(style, ',')) != NULL)
237		*rounds_s++ = '\0';
238	rounds = strtonum(rounds_s, 1, 1<<31, NULL);
239
240	if (strcmp(style, "md5") == 0) {
241		xasprintf(salt, "$1$%s$", makesalt(8, authctxt->user));
242		*scheme = xstrdup("md5");
243	} else if (strcmp(style, "old") == 0) {
244		*salt = xstrdup(makesalt(2, authctxt->user));
245		*scheme = xstrdup("crypt");
246	} else if (strcmp(style, "newsalt") == 0) {
247		rounds = MAX(rounds, 7250);
248		rounds = MIN(rounds, (1<<24) - 1);
249		xasprintf(salt, "_%c%c%c%c%s",
250		    pw_encode64(rounds), pw_encode64(rounds >> 6),
251		    pw_encode64(rounds >> 12), pw_encode64(rounds >> 18),
252		    makesalt(4, authctxt->user));
253		*scheme = xstrdup("crypt-extended");
254	} else {
255		/* Default to blowfish */
256		rounds = MAX(rounds, 3);
257		rounds = MIN(rounds, 31);
258		xasprintf(salt, "$2a$%02lld$%s", rounds,
259		    makesalt(22, authctxt->user));
260		*scheme = xstrdup("bcrypt");
261	}
262	xfree(style);
263	debug3("%s: fake %s salt for user %s: %s",
264	    __func__, *scheme, authctxt->user, *salt);
265}
266
267/*
268 * Fetch password hashing scheme, password salt and derive shared secret
269 * for user. If user does not exist, a fake but stable and user-unique
270 * salt will be returned.
271 */
272void
273auth2_jpake_get_pwdata(Authctxt *authctxt, BIGNUM **s,
274    char **hash_scheme, char **salt)
275{
276	char *cp;
277	u_char *secret;
278	u_int secret_len, salt_len;
279
280#ifdef JPAKE_DEBUG
281	debug3("%s: valid %d pw %.5s...", __func__,
282	    authctxt->valid, authctxt->pw->pw_passwd);
283#endif
284
285	*salt = NULL;
286	*hash_scheme = NULL;
287	if (authctxt->valid) {
288		if (strncmp(authctxt->pw->pw_passwd, "$2$", 3) == 0 &&
289		    strlen(authctxt->pw->pw_passwd) > 28) {
290			/*
291			 * old-variant bcrypt:
292			 *     "$2$", 2 digit rounds, "$", 22 bytes salt
293			 */
294			salt_len = 3 + 2 + 1 + 22 + 1;
295			*salt = xmalloc(salt_len);
296			strlcpy(*salt, authctxt->pw->pw_passwd, salt_len);
297			*hash_scheme = xstrdup("bcrypt");
298		} else if (strncmp(authctxt->pw->pw_passwd, "$2a$", 4) == 0 &&
299		    strlen(authctxt->pw->pw_passwd) > 29) {
300			/*
301			 * current-variant bcrypt:
302			 *     "$2a$", 2 digit rounds, "$", 22 bytes salt
303			 */
304			salt_len = 4 + 2 + 1 + 22 + 1;
305			*salt = xmalloc(salt_len);
306			strlcpy(*salt, authctxt->pw->pw_passwd, salt_len);
307			*hash_scheme = xstrdup("bcrypt");
308		} else if (strncmp(authctxt->pw->pw_passwd, "$1$", 3) == 0 &&
309		    strlen(authctxt->pw->pw_passwd) > 5) {
310			/*
311			 * md5crypt:
312			 *     "$1$", salt until "$"
313			 */
314			cp = strchr(authctxt->pw->pw_passwd + 3, '$');
315			if (cp != NULL) {
316				salt_len = (cp - authctxt->pw->pw_passwd) + 1;
317				*salt = xmalloc(salt_len);
318				strlcpy(*salt, authctxt->pw->pw_passwd,
319				    salt_len);
320				*hash_scheme = xstrdup("md5crypt");
321			}
322		} else if (strncmp(authctxt->pw->pw_passwd, "_", 1) == 0 &&
323		    strlen(authctxt->pw->pw_passwd) > 9) {
324			/*
325			 * BSDI extended crypt:
326			 *     "_", 4 digits count, 4 chars salt
327			 */
328			salt_len = 1 + 4 + 4 + 1;
329			*salt = xmalloc(salt_len);
330			strlcpy(*salt, authctxt->pw->pw_passwd, salt_len);
331			*hash_scheme = xstrdup("crypt-extended");
332		} else if (strlen(authctxt->pw->pw_passwd) == 13  &&
333		    valid_crypt_salt(authctxt->pw->pw_passwd[0]) &&
334		    valid_crypt_salt(authctxt->pw->pw_passwd[1])) {
335			/*
336			 * traditional crypt:
337			 *     2 chars salt
338			 */
339			salt_len = 2 + 1;
340			*salt = xmalloc(salt_len);
341			strlcpy(*salt, authctxt->pw->pw_passwd, salt_len);
342			*hash_scheme = xstrdup("crypt");
343		}
344		if (*salt == NULL) {
345			debug("%s: unrecognised crypt scheme for user %s",
346			    __func__, authctxt->pw->pw_name);
347		}
348	}
349	if (*salt == NULL)
350		fake_salt_and_scheme(authctxt, salt, hash_scheme);
351
352	if (hash_buffer(authctxt->pw->pw_passwd,
353	    strlen(authctxt->pw->pw_passwd), EVP_sha256(),
354	    &secret, &secret_len) != 0)
355		fatal("%s: hash_buffer", __func__);
356	if ((*s = BN_bin2bn(secret, secret_len, NULL)) == NULL)
357		fatal("%s: BN_bin2bn (secret)", __func__);
358#ifdef JPAKE_DEBUG
359	debug3("%s: salt = %s (len %u)", __func__,
360	    *salt, (u_int)strlen(*salt));
361	debug3("%s: scheme = %s", __func__, *hash_scheme);
362	JPAKE_DEBUG_BN((*s, "%s: s = ", __func__));
363#endif
364	bzero(secret, secret_len);
365	xfree(secret);
366}
367
368/*
369 * Begin authentication attempt.
370 * Note, sets authctxt->postponed while in subprotocol
371 */
372static int
373auth2_jpake_start(Authctxt *authctxt)
374{
375	struct jpake_ctx *pctx = authctxt->jpake_ctx;
376	u_char *x3_proof, *x4_proof;
377	u_int x3_proof_len, x4_proof_len;
378	char *salt, *hash_scheme;
379
380	debug("%s: start", __func__);
381
382	PRIVSEP(jpake_step1(pctx->grp,
383	    &pctx->server_id, &pctx->server_id_len,
384	    &pctx->x3, &pctx->x4, &pctx->g_x3, &pctx->g_x4,
385	    &x3_proof, &x3_proof_len,
386	    &x4_proof, &x4_proof_len));
387
388	PRIVSEP(auth2_jpake_get_pwdata(authctxt, &pctx->s,
389	    &hash_scheme, &salt));
390
391	if (!use_privsep)
392		JPAKE_DEBUG_CTX((pctx, "step 1 sending in %s", __func__));
393
394	packet_start(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1);
395	packet_put_cstring(hash_scheme);
396	packet_put_cstring(salt);
397	packet_put_string(pctx->server_id, pctx->server_id_len);
398	packet_put_bignum2(pctx->g_x3);
399	packet_put_bignum2(pctx->g_x4);
400	packet_put_string(x3_proof, x3_proof_len);
401	packet_put_string(x4_proof, x4_proof_len);
402	packet_send();
403	packet_write_wait();
404
405	bzero(hash_scheme, strlen(hash_scheme));
406	bzero(salt, strlen(salt));
407	xfree(hash_scheme);
408	xfree(salt);
409	bzero(x3_proof, x3_proof_len);
410	bzero(x4_proof, x4_proof_len);
411	xfree(x3_proof);
412	xfree(x4_proof);
413
414	/* Expect step 1 packet from peer */
415	dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1,
416	    input_userauth_jpake_client_step1);
417
418	authctxt->postponed = 1;
419	return 0;
420}
421
422/* ARGSUSED */
423static void
424input_userauth_jpake_client_step1(int type, u_int32_t seq, void *ctxt)
425{
426	Authctxt *authctxt = ctxt;
427	struct jpake_ctx *pctx = authctxt->jpake_ctx;
428	u_char *x1_proof, *x2_proof, *x4_s_proof;
429	u_int x1_proof_len, x2_proof_len, x4_s_proof_len;
430
431	/* Disable this message */
432	dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1, NULL);
433
434	/* Fetch step 1 values */
435	if ((pctx->g_x1 = BN_new()) == NULL ||
436	    (pctx->g_x2 = BN_new()) == NULL)
437		fatal("%s: BN_new", __func__);
438	pctx->client_id = packet_get_string(&pctx->client_id_len);
439	packet_get_bignum2(pctx->g_x1);
440	packet_get_bignum2(pctx->g_x2);
441	x1_proof = packet_get_string(&x1_proof_len);
442	x2_proof = packet_get_string(&x2_proof_len);
443	packet_check_eom();
444
445	if (!use_privsep)
446		JPAKE_DEBUG_CTX((pctx, "step 1 received in %s", __func__));
447
448	PRIVSEP(jpake_step2(pctx->grp, pctx->s, pctx->g_x3,
449	    pctx->g_x1, pctx->g_x2, pctx->x4,
450	    pctx->client_id, pctx->client_id_len,
451	    pctx->server_id, pctx->server_id_len,
452	    x1_proof, x1_proof_len,
453	    x2_proof, x2_proof_len,
454	    &pctx->b,
455	    &x4_s_proof, &x4_s_proof_len));
456
457	bzero(x1_proof, x1_proof_len);
458	bzero(x2_proof, x2_proof_len);
459	xfree(x1_proof);
460	xfree(x2_proof);
461
462	if (!use_privsep)
463		JPAKE_DEBUG_CTX((pctx, "step 2 sending in %s", __func__));
464
465	/* Send values for step 2 */
466	packet_start(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2);
467	packet_put_bignum2(pctx->b);
468	packet_put_string(x4_s_proof, x4_s_proof_len);
469	packet_send();
470	packet_write_wait();
471
472	bzero(x4_s_proof, x4_s_proof_len);
473	xfree(x4_s_proof);
474
475	/* Expect step 2 packet from peer */
476	dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2,
477	    input_userauth_jpake_client_step2);
478}
479
480/* ARGSUSED */
481static void
482input_userauth_jpake_client_step2(int type, u_int32_t seq, void *ctxt)
483{
484	Authctxt *authctxt = ctxt;
485	struct jpake_ctx *pctx = authctxt->jpake_ctx;
486	u_char *x2_s_proof;
487	u_int x2_s_proof_len;
488
489	/* Disable this message */
490	dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2, NULL);
491
492	if ((pctx->a = BN_new()) == NULL)
493		fatal("%s: BN_new", __func__);
494
495	/* Fetch step 2 values */
496	packet_get_bignum2(pctx->a);
497	x2_s_proof = packet_get_string(&x2_s_proof_len);
498	packet_check_eom();
499
500	if (!use_privsep)
501		JPAKE_DEBUG_CTX((pctx, "step 2 received in %s", __func__));
502
503	/* Derive shared key and calculate confirmation hash */
504	PRIVSEP(jpake_key_confirm(pctx->grp, pctx->s, pctx->a,
505	    pctx->x4, pctx->g_x3, pctx->g_x4, pctx->g_x1, pctx->g_x2,
506	    pctx->server_id, pctx->server_id_len,
507	    pctx->client_id, pctx->client_id_len,
508	    session_id2, session_id2_len,
509	    x2_s_proof, x2_s_proof_len,
510	    &pctx->k,
511	    &pctx->h_k_sid_sessid, &pctx->h_k_sid_sessid_len));
512
513	bzero(x2_s_proof, x2_s_proof_len);
514	xfree(x2_s_proof);
515
516	if (!use_privsep)
517		JPAKE_DEBUG_CTX((pctx, "confirm sending in %s", __func__));
518
519	/* Send key confirmation proof */
520	packet_start(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM);
521	packet_put_string(pctx->h_k_sid_sessid, pctx->h_k_sid_sessid_len);
522	packet_send();
523	packet_write_wait();
524
525	/* Expect confirmation from peer */
526	dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM,
527	    input_userauth_jpake_client_confirm);
528}
529
530/* ARGSUSED */
531static void
532input_userauth_jpake_client_confirm(int type, u_int32_t seq, void *ctxt)
533{
534	Authctxt *authctxt = ctxt;
535	struct jpake_ctx *pctx = authctxt->jpake_ctx;
536	int authenticated = 0;
537
538	/* Disable this message */
539	dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM, NULL);
540
541	pctx->h_k_cid_sessid = packet_get_string(&pctx->h_k_cid_sessid_len);
542	packet_check_eom();
543
544	if (!use_privsep)
545		JPAKE_DEBUG_CTX((pctx, "confirm received in %s", __func__));
546
547	/* Verify expected confirmation hash */
548	if (PRIVSEP(jpake_check_confirm(pctx->k,
549	    pctx->client_id, pctx->client_id_len,
550	    session_id2, session_id2_len,
551	    pctx->h_k_cid_sessid, pctx->h_k_cid_sessid_len)) == 1)
552		authenticated = authctxt->valid ? 1 : 0;
553	else
554		debug("%s: confirmation mismatch", __func__);
555
556	/* done */
557	authctxt->postponed = 0;
558	jpake_free(authctxt->jpake_ctx);
559	authctxt->jpake_ctx = NULL;
560	userauth_finish(authctxt, authenticated, method_jpake.name);
561}
562
563#endif /* JPAKE */
564
565