[BACK]Return to auth2-jpake.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/auth2-jpake.c, Revision 1.3

1.3     ! djm         1: /* $OpenBSD: auth2-jpake.c,v 1.2 2008/11/07 23:34:48 dtucker Exp $ */
1.1       djm         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:
1.2       dtucker    28: #ifdef JPAKE
                     29:
1.1       djm        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:
1.3     ! djm        58: #include "schnorr.h"
1.1       djm        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
                     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
                    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
                    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
                    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:        default:
                    166:                fatal("%s: unknown key type %d", __func__, k->type);
                    167:        }
                    168:        if (hash_buffer(buffer_ptr(&b), buffer_len(&b), EVP_sha256(),
                    169:            &digest, &digest_len) != 0)
                    170:                fatal("%s: hash_buffer", __func__);
                    171:        buffer_free(&b);
                    172:        if (len > digest_len)
                    173:                fatal("%s: not enough bytes for rawsalt (want %u have %u)",
                    174:                    __func__, len, digest_len);
                    175:        memcpy(rawsalt, digest, len);
                    176:        bzero(digest, digest_len);
                    177:        xfree(digest);
                    178: }
                    179:
                    180: /* ASCII an integer [0, 64) for inclusion in a password/salt */
                    181: static char
                    182: pw_encode64(u_int i64)
                    183: {
                    184:        const u_char e64[] =
                    185:            "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
                    186:        return e64[i64 % 64];
                    187: }
                    188:
                    189: /* Generate ASCII salt bytes for user */
                    190: static char *
                    191: makesalt(u_int want, const char *user)
                    192: {
                    193:        u_char rawsalt[32];
                    194:        static char ret[33];
                    195:        u_int i;
                    196:
                    197:        if (want > sizeof(ret) - 1)
                    198:                fatal("%s: want %u", __func__, want);
                    199:
                    200:        derive_rawsalt(user, rawsalt, sizeof(rawsalt));
                    201:        bzero(ret, sizeof(ret));
                    202:        for (i = 0; i < want; i++)
                    203:                ret[i] = pw_encode64(rawsalt[i]);
                    204:        bzero(rawsalt, sizeof(rawsalt));
                    205:
                    206:        return ret;
                    207: }
                    208:
                    209: /*
                    210:  * Select the system's default password hashing scheme and generate
                    211:  * a stable fake salt under it for use by a non-existent account.
                    212:  * Prevents jpake method being used to infer the validity of accounts.
                    213:  */
                    214: static void
                    215: fake_salt_and_scheme(Authctxt *authctxt, char **salt, char **scheme)
                    216: {
                    217:        char *rounds_s, *style;
                    218:        long long rounds;
                    219:        login_cap_t *lc;
                    220:
                    221:
                    222:        if ((lc = login_getclass(authctxt->pw->pw_class)) == NULL &&
                    223:            (lc = login_getclass(NULL)) == NULL)
                    224:                fatal("%s: login_getclass failed", __func__);
                    225:        style = login_getcapstr(lc, "localcipher", NULL, NULL);
                    226:        if (style == NULL)
                    227:                style = xstrdup("blowfish,6");
                    228:        login_close(lc);
                    229:
                    230:        if ((rounds_s = strchr(style, ',')) != NULL)
                    231:                *rounds_s++ = '\0';
                    232:        rounds = strtonum(rounds_s, 1, 1<<31, NULL);
                    233:
                    234:        if (strcmp(style, "md5") == 0) {
                    235:                xasprintf(salt, "$1$%s$", makesalt(8, authctxt->user));
                    236:                *scheme = xstrdup("md5");
                    237:        } else if (strcmp(style, "old") == 0) {
                    238:                *salt = xstrdup(makesalt(2, authctxt->user));
                    239:                *scheme = xstrdup("crypt");
                    240:        } else if (strcmp(style, "newsalt") == 0) {
                    241:                rounds = MAX(rounds, 7250);
                    242:                rounds = MIN(rounds, (1<<24) - 1);
                    243:                xasprintf(salt, "_%c%c%c%c%s",
                    244:                    pw_encode64(rounds), pw_encode64(rounds >> 6),
                    245:                    pw_encode64(rounds >> 12), pw_encode64(rounds >> 18),
                    246:                    makesalt(4, authctxt->user));
                    247:                *scheme = xstrdup("crypt-extended");
                    248:        } else {
                    249:                /* Default to blowfish */
                    250:                rounds = MAX(rounds, 3);
                    251:                rounds = MIN(rounds, 31);
                    252:                xasprintf(salt, "$2a$%02lld$%s", rounds,
                    253:                    makesalt(22, authctxt->user));
                    254:                *scheme = xstrdup("bcrypt");
                    255:        }
                    256:        xfree(style);
                    257:        debug3("%s: fake %s salt for user %s: %s",
                    258:            __func__, *scheme, authctxt->user, *salt);
                    259: }
                    260:
                    261: /*
                    262:  * Fetch password hashing scheme, password salt and derive shared secret
                    263:  * for user. If user does not exist, a fake but stable and user-unique
                    264:  * salt will be returned.
                    265:  */
                    266: void
                    267: auth2_jpake_get_pwdata(Authctxt *authctxt, BIGNUM **s,
                    268:     char **hash_scheme, char **salt)
                    269: {
                    270:        char *cp;
                    271:        u_char *secret;
                    272:        u_int secret_len, salt_len;
                    273:
                    274: #ifdef JPAKE_DEBUG
                    275:        debug3("%s: valid %d pw %.5s...", __func__,
                    276:            authctxt->valid, authctxt->pw->pw_passwd);
                    277: #endif
                    278:
                    279:        *salt = NULL;
                    280:        *hash_scheme = NULL;
                    281:        if (authctxt->valid) {
                    282:                if (strncmp(authctxt->pw->pw_passwd, "$2$", 3) == 0 &&
                    283:                    strlen(authctxt->pw->pw_passwd) > 28) {
                    284:                        /*
                    285:                         * old-variant bcrypt:
                    286:                         *     "$2$", 2 digit rounds, "$", 22 bytes salt
                    287:                         */
                    288:                        salt_len = 3 + 2 + 1 + 22 + 1;
                    289:                        *salt = xmalloc(salt_len);
                    290:                        strlcpy(*salt, authctxt->pw->pw_passwd, salt_len);
                    291:                        *hash_scheme = xstrdup("bcrypt");
                    292:                } else if (strncmp(authctxt->pw->pw_passwd, "$2a$", 4) == 0 &&
                    293:                    strlen(authctxt->pw->pw_passwd) > 29) {
                    294:                        /*
                    295:                         * current-variant bcrypt:
                    296:                         *     "$2a$", 2 digit rounds, "$", 22 bytes salt
                    297:                         */
                    298:                        salt_len = 4 + 2 + 1 + 22 + 1;
                    299:                        *salt = xmalloc(salt_len);
                    300:                        strlcpy(*salt, authctxt->pw->pw_passwd, salt_len);
                    301:                        *hash_scheme = xstrdup("bcrypt");
                    302:                } else if (strncmp(authctxt->pw->pw_passwd, "$1$", 3) == 0 &&
                    303:                    strlen(authctxt->pw->pw_passwd) > 5) {
                    304:                        /*
                    305:                         * md5crypt:
                    306:                         *     "$1$", salt until "$"
                    307:                         */
                    308:                        cp = strchr(authctxt->pw->pw_passwd + 3, '$');
                    309:                        if (cp != NULL) {
                    310:                                salt_len = (cp - authctxt->pw->pw_passwd) + 1;
                    311:                                *salt = xmalloc(salt_len);
                    312:                                strlcpy(*salt, authctxt->pw->pw_passwd,
                    313:                                    salt_len);
                    314:                                *hash_scheme = xstrdup("md5crypt");
                    315:                        }
                    316:                } else if (strncmp(authctxt->pw->pw_passwd, "_", 1) == 0 &&
                    317:                    strlen(authctxt->pw->pw_passwd) > 9) {
                    318:                        /*
                    319:                         * BSDI extended crypt:
                    320:                         *     "_", 4 digits count, 4 chars salt
                    321:                         */
                    322:                        salt_len = 1 + 4 + 4 + 1;
                    323:                        *salt = xmalloc(salt_len);
                    324:                        strlcpy(*salt, authctxt->pw->pw_passwd, salt_len);
                    325:                        *hash_scheme = xstrdup("crypt-extended");
                    326:                } else if (strlen(authctxt->pw->pw_passwd) == 13  &&
                    327:                    valid_crypt_salt(authctxt->pw->pw_passwd[0]) &&
                    328:                    valid_crypt_salt(authctxt->pw->pw_passwd[1])) {
                    329:                        /*
                    330:                         * traditional crypt:
                    331:                         *     2 chars salt
                    332:                         */
                    333:                        salt_len = 2 + 1;
                    334:                        *salt = xmalloc(salt_len);
                    335:                        strlcpy(*salt, authctxt->pw->pw_passwd, salt_len);
                    336:                        *hash_scheme = xstrdup("crypt");
                    337:                }
                    338:                if (*salt == NULL) {
                    339:                        debug("%s: unrecognised crypt scheme for user %s",
                    340:                            __func__, authctxt->pw->pw_name);
                    341:                }
                    342:        }
                    343:        if (*salt == NULL)
                    344:                fake_salt_and_scheme(authctxt, salt, hash_scheme);
                    345:
                    346:        if (hash_buffer(authctxt->pw->pw_passwd,
                    347:            strlen(authctxt->pw->pw_passwd), EVP_sha256(),
                    348:            &secret, &secret_len) != 0)
                    349:                fatal("%s: hash_buffer", __func__);
                    350:        if ((*s = BN_bin2bn(secret, secret_len, NULL)) == NULL)
                    351:                fatal("%s: BN_bin2bn (secret)", __func__);
                    352: #ifdef JPAKE_DEBUG
                    353:        debug3("%s: salt = %s (len %u)", __func__,
                    354:            *salt, (u_int)strlen(*salt));
                    355:        debug3("%s: scheme = %s", __func__, *hash_scheme);
                    356:        JPAKE_DEBUG_BN((*s, "%s: s = ", __func__));
                    357: #endif
                    358:        bzero(secret, secret_len);
                    359:        xfree(secret);
                    360: }
                    361:
                    362: /*
1.3     ! djm       363:  * Begin authentication attempt.
1.1       djm       364:  * Note, sets authctxt->postponed while in subprotocol
                    365:  */
                    366: static int
                    367: auth2_jpake_start(Authctxt *authctxt)
                    368: {
                    369:        struct jpake_ctx *pctx = authctxt->jpake_ctx;
                    370:        u_char *x3_proof, *x4_proof;
                    371:        u_int x3_proof_len, x4_proof_len;
                    372:        char *salt, *hash_scheme;
                    373:
                    374:        debug("%s: start", __func__);
                    375:
                    376:        PRIVSEP(jpake_step1(pctx->grp,
                    377:            &pctx->server_id, &pctx->server_id_len,
                    378:            &pctx->x3, &pctx->x4, &pctx->g_x3, &pctx->g_x4,
                    379:            &x3_proof, &x3_proof_len,
                    380:            &x4_proof, &x4_proof_len));
                    381:
                    382:        PRIVSEP(auth2_jpake_get_pwdata(authctxt, &pctx->s,
                    383:            &hash_scheme, &salt));
                    384:
                    385:        if (!use_privsep)
                    386:                JPAKE_DEBUG_CTX((pctx, "step 1 sending in %s", __func__));
                    387:
                    388:        packet_start(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1);
                    389:        packet_put_cstring(hash_scheme);
                    390:        packet_put_cstring(salt);
                    391:        packet_put_string(pctx->server_id, pctx->server_id_len);
                    392:        packet_put_bignum2(pctx->g_x3);
                    393:        packet_put_bignum2(pctx->g_x4);
                    394:        packet_put_string(x3_proof, x3_proof_len);
                    395:        packet_put_string(x4_proof, x4_proof_len);
                    396:        packet_send();
                    397:        packet_write_wait();
                    398:
                    399:        bzero(hash_scheme, strlen(hash_scheme));
                    400:        bzero(salt, strlen(salt));
                    401:        xfree(hash_scheme);
                    402:        xfree(salt);
                    403:        bzero(x3_proof, x3_proof_len);
                    404:        bzero(x4_proof, x4_proof_len);
                    405:        xfree(x3_proof);
                    406:        xfree(x4_proof);
                    407:
                    408:        /* Expect step 1 packet from peer */
                    409:        dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1,
                    410:            input_userauth_jpake_client_step1);
                    411:
                    412:        authctxt->postponed = 1;
                    413:        return 0;
                    414: }
                    415:
                    416: /* ARGSUSED */
                    417: static void
                    418: input_userauth_jpake_client_step1(int type, u_int32_t seq, void *ctxt)
                    419: {
                    420:        Authctxt *authctxt = ctxt;
                    421:        struct jpake_ctx *pctx = authctxt->jpake_ctx;
                    422:        u_char *x1_proof, *x2_proof, *x4_s_proof;
                    423:        u_int x1_proof_len, x2_proof_len, x4_s_proof_len;
                    424:
                    425:        /* Disable this message */
                    426:        dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1, NULL);
                    427:
                    428:        /* Fetch step 1 values */
                    429:        if ((pctx->g_x1 = BN_new()) == NULL ||
                    430:            (pctx->g_x2 = BN_new()) == NULL)
                    431:                fatal("%s: BN_new", __func__);
                    432:        pctx->client_id = packet_get_string(&pctx->client_id_len);
                    433:        packet_get_bignum2(pctx->g_x1);
                    434:        packet_get_bignum2(pctx->g_x2);
                    435:        x1_proof = packet_get_string(&x1_proof_len);
                    436:        x2_proof = packet_get_string(&x2_proof_len);
                    437:        packet_check_eom();
                    438:
                    439:        if (!use_privsep)
                    440:                JPAKE_DEBUG_CTX((pctx, "step 1 received in %s", __func__));
                    441:
                    442:        PRIVSEP(jpake_step2(pctx->grp, pctx->s, pctx->g_x3,
                    443:            pctx->g_x1, pctx->g_x2, pctx->x4,
                    444:            pctx->client_id, pctx->client_id_len,
                    445:            pctx->server_id, pctx->server_id_len,
                    446:            x1_proof, x1_proof_len,
                    447:            x2_proof, x2_proof_len,
                    448:            &pctx->b,
                    449:            &x4_s_proof, &x4_s_proof_len));
                    450:
                    451:        bzero(x1_proof, x1_proof_len);
                    452:        bzero(x2_proof, x2_proof_len);
                    453:        xfree(x1_proof);
                    454:        xfree(x2_proof);
                    455:
                    456:        if (!use_privsep)
                    457:                JPAKE_DEBUG_CTX((pctx, "step 2 sending in %s", __func__));
                    458:
                    459:        /* Send values for step 2 */
                    460:        packet_start(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2);
                    461:        packet_put_bignum2(pctx->b);
                    462:        packet_put_string(x4_s_proof, x4_s_proof_len);
                    463:        packet_send();
                    464:        packet_write_wait();
                    465:
                    466:        bzero(x4_s_proof, x4_s_proof_len);
                    467:        xfree(x4_s_proof);
                    468:
                    469:        /* Expect step 2 packet from peer */
                    470:        dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2,
                    471:            input_userauth_jpake_client_step2);
                    472: }
                    473:
                    474: /* ARGSUSED */
                    475: static void
                    476: input_userauth_jpake_client_step2(int type, u_int32_t seq, void *ctxt)
                    477: {
                    478:        Authctxt *authctxt = ctxt;
                    479:        struct jpake_ctx *pctx = authctxt->jpake_ctx;
                    480:        u_char *x2_s_proof;
                    481:        u_int x2_s_proof_len;
                    482:
                    483:        /* Disable this message */
                    484:        dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2, NULL);
                    485:
                    486:        if ((pctx->a = BN_new()) == NULL)
                    487:                fatal("%s: BN_new", __func__);
                    488:
                    489:        /* Fetch step 2 values */
                    490:        packet_get_bignum2(pctx->a);
                    491:        x2_s_proof = packet_get_string(&x2_s_proof_len);
                    492:        packet_check_eom();
                    493:
                    494:        if (!use_privsep)
                    495:                JPAKE_DEBUG_CTX((pctx, "step 2 received in %s", __func__));
                    496:
                    497:        /* Derive shared key and calculate confirmation hash */
                    498:        PRIVSEP(jpake_key_confirm(pctx->grp, pctx->s, pctx->a,
                    499:            pctx->x4, pctx->g_x3, pctx->g_x4, pctx->g_x1, pctx->g_x2,
                    500:            pctx->server_id, pctx->server_id_len,
                    501:            pctx->client_id, pctx->client_id_len,
                    502:            session_id2, session_id2_len,
                    503:            x2_s_proof, x2_s_proof_len,
                    504:            &pctx->k,
                    505:            &pctx->h_k_sid_sessid, &pctx->h_k_sid_sessid_len));
                    506:
                    507:        bzero(x2_s_proof, x2_s_proof_len);
                    508:        xfree(x2_s_proof);
                    509:
                    510:        if (!use_privsep)
                    511:                JPAKE_DEBUG_CTX((pctx, "confirm sending in %s", __func__));
                    512:
                    513:        /* Send key confirmation proof */
                    514:        packet_start(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM);
                    515:        packet_put_string(pctx->h_k_sid_sessid, pctx->h_k_sid_sessid_len);
                    516:        packet_send();
                    517:        packet_write_wait();
                    518:
                    519:        /* Expect confirmation from peer */
                    520:        dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM,
                    521:            input_userauth_jpake_client_confirm);
                    522: }
                    523:
                    524: /* ARGSUSED */
                    525: static void
                    526: input_userauth_jpake_client_confirm(int type, u_int32_t seq, void *ctxt)
                    527: {
                    528:        Authctxt *authctxt = ctxt;
                    529:        struct jpake_ctx *pctx = authctxt->jpake_ctx;
                    530:        int authenticated = 0;
                    531:
                    532:        /* Disable this message */
                    533:        dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM, NULL);
                    534:
                    535:        pctx->h_k_cid_sessid = packet_get_string(&pctx->h_k_cid_sessid_len);
                    536:        packet_check_eom();
                    537:
                    538:        if (!use_privsep)
                    539:                JPAKE_DEBUG_CTX((pctx, "confirm received in %s", __func__));
                    540:
                    541:        /* Verify expected confirmation hash */
                    542:        if (PRIVSEP(jpake_check_confirm(pctx->k,
                    543:            pctx->client_id, pctx->client_id_len,
                    544:            session_id2, session_id2_len,
                    545:            pctx->h_k_cid_sessid, pctx->h_k_cid_sessid_len)) == 1)
                    546:                authenticated = authctxt->valid ? 1 : 0;
                    547:        else
                    548:                debug("%s: confirmation mismatch", __func__);
                    549:
                    550:        /* done */
                    551:        authctxt->postponed = 0;
                    552:        jpake_free(authctxt->jpake_ctx);
                    553:        authctxt->jpake_ctx = NULL;
                    554:        userauth_finish(authctxt, authenticated, method_jpake.name);
                    555: }
                    556:
                    557: #endif /* JPAKE */
                    558: