[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.2

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