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

1.1     ! djm         1: /* $OpenBSD$ */
        !             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: #include <sys/types.h>
        !            29: #include <sys/param.h>
        !            30:
        !            31: #include <pwd.h>
        !            32: #include <stdio.h>
        !            33: #include <string.h>
        !            34: #include <login_cap.h>
        !            35:
        !            36: #include <openssl/bn.h>
        !            37: #include <openssl/evp.h>
        !            38:
        !            39: #include "xmalloc.h"
        !            40: #include "ssh2.h"
        !            41: #include "key.h"
        !            42: #include "hostfile.h"
        !            43: #include "auth.h"
        !            44: #include "buffer.h"
        !            45: #include "packet.h"
        !            46: #include "dispatch.h"
        !            47: #include "log.h"
        !            48: #include "servconf.h"
        !            49: #include "auth-options.h"
        !            50: #include "canohost.h"
        !            51: #ifdef GSSAPI
        !            52: #include "ssh-gss.h"
        !            53: #endif
        !            54: #include "monitor_wrap.h"
        !            55:
        !            56: #include "jpake.h"
        !            57:
        !            58: #ifdef JPAKE
        !            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: