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