-/* $OpenBSD: monitor.c,v 1.91 2007/05/17 20:52:13 djm Exp $ */
+/* $OpenBSD: monitor.c,v 1.104 2009/06/12 20:43:22 andreas Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org>
#include <openssl/dh.h>
+#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "ssh.h"
#include "key.h"
#include "misc.h"
#include "compat.h"
#include "ssh2.h"
+#include "jpake.h"
+#include "roaming.h"
#ifdef GSSAPI
static Gssctxt *gsscontext = NULL;
extern z_stream incoming_stream;
extern z_stream outgoing_stream;
extern u_char session_id[];
-extern Buffer input, output;
extern Buffer auth_debug;
extern int auth_debug_init;
extern Buffer loginmsg;
u_int ilen;
u_char *output;
u_int olen;
+ u_int64_t sent_bytes;
+ u_int64_t recv_bytes;
} child_state;
/* Functions on the monitor that answer unprivileged requests */
int mm_answer_rsa_response(int, Buffer *);
int mm_answer_sesskey(int, Buffer *);
int mm_answer_sessid(int, Buffer *);
+int mm_answer_jpake_get_pwdata(int, Buffer *);
+int mm_answer_jpake_step1(int, Buffer *);
+int mm_answer_jpake_step2(int, Buffer *);
+int mm_answer_jpake_key_confirm(int, Buffer *);
+int mm_answer_jpake_check_confirm(int, Buffer *);
#ifdef USE_PAM
int mm_answer_pam_start(int, Buffer *);
int mm_answer_gss_accept_ctx(int, Buffer *);
int mm_answer_gss_userok(int, Buffer *);
int mm_answer_gss_checkmic(int, Buffer *);
+int mm_answer_gss_sign(int, Buffer *);
+int mm_answer_gss_error(int, Buffer *);
+int mm_answer_gss_indicate_mechs(int, Buffer *);
+int mm_answer_gss_localname(int, Buffer *);
+int mm_answer_gss_updatecreds(int, Buffer *);
#endif
#ifdef SSH_AUDIT_EVENTS
struct mon_table mon_dispatch_proto20[] = {
{MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli},
{MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
- {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
+ {MONITOR_REQ_PWNAM, MON_AUTH, mm_answer_pwnamallow},
{MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
{MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
{MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
#ifdef USE_PAM
- {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
+ {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start},
{MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
{MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
{MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
{MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
{MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
{MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
+ {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
+ {MONITOR_REQ_GSSERR, MON_ISAUTH | MON_ONCE, mm_answer_gss_error},
+ {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs},
+ {MONITOR_REQ_GSSLOCALNAME, MON_ISAUTH, mm_answer_gss_localname},
+#endif
+#ifdef JPAKE
+ {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata},
+ {MONITOR_REQ_JPAKE_STEP1, MON_ISAUTH, mm_answer_jpake_step1},
+ {MONITOR_REQ_JPAKE_STEP2, MON_ONCE, mm_answer_jpake_step2},
+ {MONITOR_REQ_JPAKE_KEY_CONFIRM, MON_ONCE, mm_answer_jpake_key_confirm},
+ {MONITOR_REQ_JPAKE_CHECK_CONFIRM, MON_AUTH, mm_answer_jpake_check_confirm},
#endif
{0, 0, NULL}
};
struct mon_table mon_dispatch_postauth20[] = {
+#ifdef GSSAPI
+ {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
+ {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
+ {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
+ {MONITOR_REQ_GSSERR, 0, mm_answer_gss_error},
+ {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs},
+ {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
+#endif
{MONITOR_REQ_MODULI, 0, mm_answer_moduli},
{MONITOR_REQ_SIGN, 0, mm_answer_sign},
{MONITOR_REQ_PTY, 0, mm_answer_pty},
{MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery},
{MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond},
#endif
+#ifdef GSSAPI
+ {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx},
+ {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
+ {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
+ {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
+ {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs},
+#endif
#ifdef USE_PAM
- {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
+ {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start},
{MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
{MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
{MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
/* Permit requests for moduli and signatures */
monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
+#ifdef GSSAPI
+ /* and for the GSSAPI key exchange */
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1);
+#endif
} else {
mon_dispatch = mon_dispatch_proto15;
if (!authenticated)
authctxt->failures++;
}
+#ifdef JPAKE
+ /* Cleanup JPAKE context after authentication */
+ if (ent->flags & MON_AUTHDECIDE) {
+ if (authctxt->jpake_ctx != NULL) {
+ jpake_free(authctxt->jpake_ctx);
+ authctxt->jpake_ctx = NULL;
+ }
+ }
+#endif
}
if (!authctxt->valid)
monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
+
+#ifdef GSSAPI
+ /* and for the GSSAPI key exchange */
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS,1);
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP,1);
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR,1);
+#endif
+
} else {
mon_dispatch = mon_dispatch_postauth15;
monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
}
+#ifdef GSSAPI
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
+#endif
if (!no_pty_flag) {
monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1);
debug3("%s", __func__);
- if (authctxt->attempt++ != 0)
- fatal("%s: multiple attempts for getpwnam", __func__);
-
username = buffer_get_string(m, NULL);
pwent = getpwnamallow(username);
+ if (authctxt->user) xfree(authctxt->user);
authctxt->user = xstrdup(username);
+#ifdef USE_PAM
+ if (options.permit_pam_user_change)
+ setproctitle("%s [priv]", pwent ? "[pam]" : "unknown");
+ else
+#endif
setproctitle("%s [priv]", pwent ? username : "unknown");
xfree(username);
#endif
buffer_put_cstring(m, pwent->pw_dir);
buffer_put_cstring(m, pwent->pw_shell);
+
+ out:
buffer_put_string(m, &options, sizeof(options));
if (options.banner != NULL)
buffer_put_cstring(m, options.banner);
-
- out:
debug3("%s: sending MONITOR_ANS_PWNAM: %d", __func__, allowed);
mm_request_send(sock, MONITOR_ANS_PWNAM, m);
allowed = options.pubkey_authentication &&
user_key_allowed(authctxt->pw, key);
auth_method = "publickey";
+ if (options.pubkey_authentication && allowed != 1)
+ auth_clear_options();
break;
case MM_HOSTKEY:
allowed = options.hostbased_authentication &&
allowed = options.rhosts_rsa_authentication &&
auth_rhosts_rsa_key_allowed(authctxt->pw,
cuser, chost, key);
+ if (options.rhosts_rsa_authentication && allowed != 1)
+ auth_clear_options();
auth_method = "rsa";
break;
default:
}
debug3("%s: key %p is %s",
- __func__, key, allowed ? "allowed" : "disallowed");
+ __func__, key, allowed ? "allowed" : "not allowed");
buffer_clear(m);
buffer_put_int(m, allowed);
debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd);
session_pty_cleanup2(s);
}
- s->used = 0;
+ session_unused(s->self);
}
int
mm_request_send(sock, MONITOR_ANS_PTY, m);
- mm_send_fd(sock, s->ptyfd);
- mm_send_fd(sock, s->ttyfd);
+ if (mm_send_fd(sock, s->ptyfd) == -1 ||
+ mm_send_fd(sock, s->ttyfd) == -1)
+ fatal("%s: send fds failed", __func__);
/* make sure nothing uses fd 0 */
if ((fd0 = open(_PATH_DEVNULL, O_RDONLY)) < 0)
fatal("%s: key type mismatch", __func__);
if ((key = key_from_blob(blob, blen)) == NULL)
fatal("%s: received bad key", __func__);
-
+ if (key->type != KEY_RSA)
+ fatal("%s: received bad key type %d", __func__, key->type);
+ key->type = KEY_RSA1;
if (ssh1_challenge)
BN_clear_free(ssh1_challenge);
ssh1_challenge = auth_rsa_generate_challenge(key);
/* The child is terminating */
session_destroy_all(&mm_session_close);
+#ifdef USE_PAM
+ if (options.use_pam)
+ sshpam_cleanup();
+#endif
+
while (waitpid(pmonitor->m_pid, &status, 0) == -1)
if (errno != EINTR)
exit(1);
/* Network I/O buffers */
/* XXX inefficient for large buffers, need: buffer_init_from_string */
- buffer_clear(&input);
- buffer_append(&input, child_state.input, child_state.ilen);
+ buffer_clear(packet_get_input());
+ buffer_append(packet_get_input(), child_state.input, child_state.ilen);
memset(child_state.input, 0, child_state.ilen);
xfree(child_state.input);
- buffer_clear(&output);
- buffer_append(&output, child_state.output, child_state.olen);
+ buffer_clear(packet_get_output());
+ buffer_append(packet_get_output(), child_state.output,
+ child_state.olen);
memset(child_state.output, 0, child_state.olen);
xfree(child_state.output);
+
+ /* Roaming */
+ if (compat20)
+ roam_set_bytes(child_state.sent_bytes, child_state.recv_bytes);
}
static Kex *
kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
+#ifdef GSSAPI
+ if (options.gss_keyex) {
+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
+ }
+#endif
kex->server = 1;
kex->hostkey_type = buffer_get_int(m);
kex->kex_type = buffer_get_int(m);
u_char *blob, *p;
u_int bloblen, plen;
u_int32_t seqnr, packets;
- u_int64_t blocks;
+ u_int64_t blocks, bytes;
debug3("%s: Waiting for new keys", __func__);
seqnr = buffer_get_int(&m);
blocks = buffer_get_int64(&m);
packets = buffer_get_int(&m);
- packet_set_state(MODE_OUT, seqnr, blocks, packets);
+ bytes = buffer_get_int64(&m);
+ packet_set_state(MODE_OUT, seqnr, blocks, packets, bytes);
seqnr = buffer_get_int(&m);
blocks = buffer_get_int64(&m);
packets = buffer_get_int(&m);
- packet_set_state(MODE_IN, seqnr, blocks, packets);
+ bytes = buffer_get_int64(&m);
+ packet_set_state(MODE_IN, seqnr, blocks, packets, bytes);
skip:
/* Get the key context */
child_state.input = buffer_get_string(&m, &child_state.ilen);
child_state.output = buffer_get_string(&m, &child_state.olen);
+ /* Roaming */
+ if (compat20) {
+ child_state.sent_bytes = buffer_get_int64(&m);
+ child_state.recv_bytes = buffer_get_int64(&m);
+ }
+
buffer_free(&m);
}
OM_uint32 major;
u_int len;
+ if (!options.gss_authentication && !options.gss_keyex)
+ fatal("In GSSAPI monitor when GSSAPI is disabled");
+
goid.elements = buffer_get_string(m, &len);
goid.length = len;
OM_uint32 flags = 0; /* GSI needs this */
u_int len;
+ if (!options.gss_authentication && !options.gss_keyex)
+ fatal("In GSSAPI monitor when GSSAPI is disabled");
+
in.value = buffer_get_string(m, &len);
in.length = len;
major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
if (major == GSS_S_COMPLETE) {
monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
}
return (0);
}
OM_uint32 ret;
u_int len;
+ if (!options.gss_authentication && !options.gss_keyex)
+ fatal("In GSSAPI monitor when GSSAPI is disabled");
+
gssbuf.value = buffer_get_string(m, &len);
gssbuf.length = len;
mic.value = buffer_get_string(m, &len);
mm_answer_gss_userok(int sock, Buffer *m)
{
int authenticated;
+ int gssapi_keyex;
+
+ if (!options.gss_authentication && !options.gss_keyex)
+ fatal("In GSSAPI monitor when GSSAPI is disabled");
+
+ gssapi_keyex = buffer_get_int(m);
- authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
+ authenticated = authctxt->valid &&
+ ssh_gssapi_userok(authctxt->user, authctxt->pw, gssapi_keyex);
buffer_clear(m);
buffer_put_int(m, authenticated);
debug3("%s: sending result %d", __func__, authenticated);
mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m);
- auth_method = "gssapi-with-mic";
+ if (gssapi_keyex)
+ auth_method = "gssapi-keyex";
+ else
+ auth_method = "gssapi-with-mic";
/* Monitor loop will terminate if authenticated */
return (authenticated);
}
+
+int
+mm_answer_gss_error(int socket, Buffer *m) {
+ OM_uint32 major,minor;
+ char *msg;
+
+ msg=ssh_gssapi_last_error(gsscontext,&major,&minor);
+ buffer_clear(m);
+ buffer_put_int(m,major);
+ buffer_put_int(m,minor);
+ buffer_put_cstring(m,msg);
+
+ mm_request_send(socket,MONITOR_ANS_GSSERR,m);
+
+ xfree(msg);
+
+ return(0);
+}
+
+int
+mm_answer_gss_indicate_mechs(int socket, Buffer *m) {
+ OM_uint32 major,minor;
+ gss_OID_set mech_set;
+ size_t i;
+
+ major=gss_indicate_mechs(&minor, &mech_set);
+
+ buffer_clear(m);
+ buffer_put_int(m, major);
+ buffer_put_int(m, mech_set->count);
+ for (i=0; i < mech_set->count; i++) {
+ buffer_put_string(m, mech_set->elements[i].elements,
+ mech_set->elements[i].length);
+ }
+
+#if !defined(MECHGLUE) /* mechglue memory management bug ??? */
+ gss_release_oid_set(&minor,&mech_set);
+#endif
+
+ mm_request_send(socket,MONITOR_ANS_GSSMECHS,m);
+
+ return(0);
+}
+
+int
+mm_answer_gss_localname(int socket, Buffer *m) {
+ char *name;
+
+ ssh_gssapi_localname(&name);
+
+ buffer_clear(m);
+ if (name) {
+ buffer_put_cstring(m, name);
+ debug3("%s: sending result %s", __func__, name);
+ xfree(name);
+ } else {
+ buffer_put_cstring(m, "");
+ debug3("%s: sending result \"\"", __func__);
+ }
+
+ mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m);
+
+ return(0);
+}
+
+int
+mm_answer_gss_sign(int socket, Buffer *m)
+{
+ gss_buffer_desc data;
+ gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
+ OM_uint32 major, minor;
+ u_int len;
+
+ if (!options.gss_authentication && !options.gss_keyex)
+ fatal("In GSSAPI monitor when GSSAPI is disabled");
+
+ data.value = buffer_get_string(m, &len);
+ data.length = len;
+ if (data.length != 20)
+ fatal("%s: data length incorrect: %d", __func__,
+ (int) data.length);
+
+ /* Save the session ID on the first time around */
+ if (session_id2_len == 0) {
+ session_id2_len = data.length;
+ session_id2 = xmalloc(session_id2_len);
+ memcpy(session_id2, data.value, session_id2_len);
+ }
+ major = ssh_gssapi_sign(gsscontext, &data, &hash);
+
+ xfree(data.value);
+
+ buffer_clear(m);
+ buffer_put_int(m, major);
+ buffer_put_string(m, hash.value, hash.length);
+
+ mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
+
+ gss_release_buffer(&minor, &hash);
+
+ /* Turn on getpwnam permissions */
+ monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
+
+ /* And credential updating, for when rekeying */
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1);
+
+ return (0);
+}
+
+int
+mm_answer_gss_updatecreds(int socket, Buffer *m) {
+ ssh_gssapi_ccache store;
+ int ok;
+
+ store.filename = buffer_get_string(m, NULL);
+ store.envvar = buffer_get_string(m, NULL);
+ store.envval = buffer_get_string(m, NULL);
+
+ ok = ssh_gssapi_update_creds(&store);
+
+ xfree(store.filename);
+ xfree(store.envvar);
+ xfree(store.envval);
+
+ buffer_clear(m);
+ buffer_put_int(m, ok);
+
+ mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m);
+
+ return(0);
+}
+
#endif /* GSSAPI */
+
+#ifdef JPAKE
+int
+mm_answer_jpake_step1(int sock, Buffer *m)
+{
+ struct jpake_ctx *pctx;
+ u_char *x3_proof, *x4_proof;
+ u_int x3_proof_len, x4_proof_len;
+
+ if (!options.zero_knowledge_password_authentication)
+ fatal("zero_knowledge_password_authentication disabled");
+
+ if (authctxt->jpake_ctx != NULL)
+ fatal("%s: authctxt->jpake_ctx already set (%p)",
+ __func__, authctxt->jpake_ctx);
+ authctxt->jpake_ctx = pctx = jpake_new();
+
+ jpake_step1(pctx->grp,
+ &pctx->server_id, &pctx->server_id_len,
+ &pctx->x3, &pctx->x4, &pctx->g_x3, &pctx->g_x4,
+ &x3_proof, &x3_proof_len,
+ &x4_proof, &x4_proof_len);
+
+ JPAKE_DEBUG_CTX((pctx, "step1 done in %s", __func__));
+
+ buffer_clear(m);
+
+ buffer_put_string(m, pctx->server_id, pctx->server_id_len);
+ buffer_put_bignum2(m, pctx->g_x3);
+ buffer_put_bignum2(m, pctx->g_x4);
+ buffer_put_string(m, x3_proof, x3_proof_len);
+ buffer_put_string(m, x4_proof, x4_proof_len);
+
+ debug3("%s: sending step1", __func__);
+ mm_request_send(sock, MONITOR_ANS_JPAKE_STEP1, m);
+
+ bzero(x3_proof, x3_proof_len);
+ bzero(x4_proof, x4_proof_len);
+ xfree(x3_proof);
+ xfree(x4_proof);
+
+ monitor_permit(mon_dispatch, MONITOR_REQ_JPAKE_GET_PWDATA, 1);
+ monitor_permit(mon_dispatch, MONITOR_REQ_JPAKE_STEP1, 0);
+
+ return 0;
+}
+
+int
+mm_answer_jpake_get_pwdata(int sock, Buffer *m)
+{
+ struct jpake_ctx *pctx = authctxt->jpake_ctx;
+ char *hash_scheme, *salt;
+
+ if (pctx == NULL)
+ fatal("%s: pctx == NULL", __func__);
+
+ auth2_jpake_get_pwdata(authctxt, &pctx->s, &hash_scheme, &salt);
+
+ buffer_clear(m);
+ /* pctx->s is sensitive, not returned to slave */
+ buffer_put_cstring(m, hash_scheme);
+ buffer_put_cstring(m, salt);
+
+ debug3("%s: sending pwdata", __func__);
+ mm_request_send(sock, MONITOR_ANS_JPAKE_GET_PWDATA, m);
+
+ bzero(hash_scheme, strlen(hash_scheme));
+ bzero(salt, strlen(salt));
+ xfree(hash_scheme);
+ xfree(salt);
+
+ monitor_permit(mon_dispatch, MONITOR_REQ_JPAKE_STEP2, 1);
+
+ return 0;
+}
+
+int
+mm_answer_jpake_step2(int sock, Buffer *m)
+{
+ struct jpake_ctx *pctx = authctxt->jpake_ctx;
+ u_char *x1_proof, *x2_proof, *x4_s_proof;
+ u_int x1_proof_len, x2_proof_len, x4_s_proof_len;
+
+ if (pctx == NULL)
+ fatal("%s: pctx == NULL", __func__);
+
+ if ((pctx->g_x1 = BN_new()) == NULL ||
+ (pctx->g_x2 = BN_new()) == NULL)
+ fatal("%s: BN_new", __func__);
+ buffer_get_bignum2(m, pctx->g_x1);
+ buffer_get_bignum2(m, pctx->g_x2);
+ pctx->client_id = buffer_get_string(m, &pctx->client_id_len);
+ x1_proof = buffer_get_string(m, &x1_proof_len);
+ x2_proof = buffer_get_string(m, &x2_proof_len);
+
+ jpake_step2(pctx->grp, pctx->s, pctx->g_x3,
+ pctx->g_x1, pctx->g_x2, pctx->x4,
+ pctx->client_id, pctx->client_id_len,
+ pctx->server_id, pctx->server_id_len,
+ x1_proof, x1_proof_len,
+ x2_proof, x2_proof_len,
+ &pctx->b,
+ &x4_s_proof, &x4_s_proof_len);
+
+ JPAKE_DEBUG_CTX((pctx, "step2 done in %s", __func__));
+
+ bzero(x1_proof, x1_proof_len);
+ bzero(x2_proof, x2_proof_len);
+ xfree(x1_proof);
+ xfree(x2_proof);
+
+ buffer_clear(m);
+
+ buffer_put_bignum2(m, pctx->b);
+ buffer_put_string(m, x4_s_proof, x4_s_proof_len);
+
+ debug3("%s: sending step2", __func__);
+ mm_request_send(sock, MONITOR_ANS_JPAKE_STEP2, m);
+
+ bzero(x4_s_proof, x4_s_proof_len);
+ xfree(x4_s_proof);
+
+ monitor_permit(mon_dispatch, MONITOR_REQ_JPAKE_KEY_CONFIRM, 1);
+
+ return 0;
+}
+
+int
+mm_answer_jpake_key_confirm(int sock, Buffer *m)
+{
+ struct jpake_ctx *pctx = authctxt->jpake_ctx;
+ u_char *x2_s_proof;
+ u_int x2_s_proof_len;
+
+ if (pctx == NULL)
+ fatal("%s: pctx == NULL", __func__);
+
+ if ((pctx->a = BN_new()) == NULL)
+ fatal("%s: BN_new", __func__);
+ buffer_get_bignum2(m, pctx->a);
+ x2_s_proof = buffer_get_string(m, &x2_s_proof_len);
+
+ jpake_key_confirm(pctx->grp, pctx->s, pctx->a,
+ pctx->x4, pctx->g_x3, pctx->g_x4, pctx->g_x1, pctx->g_x2,
+ pctx->server_id, pctx->server_id_len,
+ pctx->client_id, pctx->client_id_len,
+ session_id2, session_id2_len,
+ x2_s_proof, x2_s_proof_len,
+ &pctx->k,
+ &pctx->h_k_sid_sessid, &pctx->h_k_sid_sessid_len);
+
+ JPAKE_DEBUG_CTX((pctx, "key_confirm done in %s", __func__));
+
+ bzero(x2_s_proof, x2_s_proof_len);
+ buffer_clear(m);
+
+ /* pctx->k is sensitive, not sent */
+ buffer_put_string(m, pctx->h_k_sid_sessid, pctx->h_k_sid_sessid_len);
+
+ debug3("%s: sending confirmation hash", __func__);
+ mm_request_send(sock, MONITOR_ANS_JPAKE_KEY_CONFIRM, m);
+
+ monitor_permit(mon_dispatch, MONITOR_REQ_JPAKE_CHECK_CONFIRM, 1);
+
+ return 0;
+}
+
+int
+mm_answer_jpake_check_confirm(int sock, Buffer *m)
+{
+ int authenticated = 0;
+ u_char *peer_confirm_hash;
+ u_int peer_confirm_hash_len;
+ struct jpake_ctx *pctx = authctxt->jpake_ctx;
+
+ if (pctx == NULL)
+ fatal("%s: pctx == NULL", __func__);
+
+ peer_confirm_hash = buffer_get_string(m, &peer_confirm_hash_len);
+
+ authenticated = jpake_check_confirm(pctx->k,
+ pctx->client_id, pctx->client_id_len,
+ session_id2, session_id2_len,
+ peer_confirm_hash, peer_confirm_hash_len) && authctxt->valid;
+
+ JPAKE_DEBUG_CTX((pctx, "check_confirm done in %s", __func__));
+
+ bzero(peer_confirm_hash, peer_confirm_hash_len);
+ xfree(peer_confirm_hash);
+
+ buffer_clear(m);
+ buffer_put_int(m, authenticated);
+
+ debug3("%s: sending result %d", __func__, authenticated);
+ mm_request_send(sock, MONITOR_ANS_JPAKE_CHECK_CONFIRM, m);
+
+ monitor_permit(mon_dispatch, MONITOR_REQ_JPAKE_STEP1, 1);
+
+ auth_method = "jpake-01@openssh.com";
+ return authenticated;
+}
+
+#endif /* JPAKE */