1 From d49f189d9549a316d9213a441323d72b8f40cccf Mon Sep 17 00:00:00 2001
   2 From: oracle <solaris@oracle.com>
   3 Date: Mon, 3 Aug 2015 14:37:24 -0700
   4 Subject: [PATCH 16/36] GSS-API key exchange support
   5 
   6 ---
   7  Makefile.in    |   3 +-
   8  auth2-gss.c    |  41 ++++++-
   9  auth2.c        |   2 +
  10  gss-genr.c     | 179 ++++++++++++++++++++++++++++-
  11  gss-serv.c     |  39 +++++--
  12  kex.c          |  11 +-
  13  kex.h          |  11 ++
  14  kexgssc.c      | 347 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  15  kexgsss.c      | 297 ++++++++++++++++++++++++++++++++++++++++++++++++
  16  monitor.c      |  77 +++++++++++++
  17  monitor.h      |   3 +
  18  monitor_wrap.c |  23 ++++
  19  monitor_wrap.h |   1 +
  20  readconf.c     |  14 +++
  21  readconf.h     |   1 +
  22  servconf.c     |  15 +++
  23  servconf.h     |   1 +
  24  ssh-gss.h      |  19 ++++
  25  ssh_config     |   1 +
  26  ssh_config.4   |   6 +
  27  sshconnect2.c  | 104 ++++++++++++++++-
  28  sshd.c         |  52 +++++++++
  29  sshd_config    |   3 +-
  30  sshd_config.4  |   6 +
  31  sshkey.c       |   1 +
  32  sshkey.h       |   3 +
  33  26 files changed, 1239 insertions(+), 21 deletions(-)
  34  create mode 100644 kexgssc.c
  35  create mode 100644 kexgsss.c
  36 
  37 diff --git a/Makefile.in b/Makefile.in
  38 index 62e6a84..0148742 100644
  39 --- a/Makefile.in
  40 +++ b/Makefile.in
  41 @@ -87,6 +87,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
  42         monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
  43         msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
  44         sftp_provider.o \
  45 +       kexgssc.o \
  46         ssh-pkcs11.o smult_curve25519_ref.o \
  47         poly1305.o chacha.o cipher-chachapoly.o \
  48         ssh-ed25519.o digest-openssl.o digest-libc.o hmac.o \
  49 @@ -108,7 +109,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
  50         auth-skey.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \
  51         auth2-none.o auth2-passwd.o auth2-pubkey.o \
  52         monitor_mm.o monitor.o monitor_wrap.o auth-krb5.o \
  53 -       auth2-gss.o gss-serv.o gss-serv-krb5.o \
  54 +       auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \
  55         loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
  56         sftp-server.o sftp-common.o \
  57         roaming_common.o roaming_serv.o \
  58 diff --git a/auth2-gss.c b/auth2-gss.c
  59 index 1ca8357..24999c8 100644
  60 --- a/auth2-gss.c
  61 +++ b/auth2-gss.c
  62 @@ -1,7 +1,7 @@
  63  /* $OpenBSD: auth2-gss.c,v 1.22 2015/01/19 20:07:45 markus Exp $ */
  64  
  65  /*
  66 - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
  67 + * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
  68   *
  69   * Redistribution and use in source and binary forms, with or without
  70   * modification, are permitted provided that the following conditions
  71 @@ -53,6 +53,39 @@ static int input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
  72  static int input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
  73  static int input_gssapi_errtok(int, u_int32_t, void *);
  74  
  75 +/* 
  76 + * The 'gssapi_keyex' userauth mechanism.
  77 + */
  78 +static int
  79 +userauth_gsskeyex(Authctxt *authctxt)
  80 +{
  81 +       int authenticated = 0;
  82 +       Buffer b;
  83 +       gss_buffer_desc mic, gssbuf;
  84 +       u_int len;
  85 +
  86 +       mic.value = packet_get_string(&len);
  87 +       mic.length = len;
  88 +
  89 +       packet_check_eom();
  90 +
  91 +       ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
  92 +           "gssapi-keyex");
  93 +
  94 +       gssbuf.value = buffer_ptr(&b);
  95 +       gssbuf.length = buffer_len(&b);
  96 +
  97 +       /* gss_kex_context is NULL with privsep, so we can't check it here */
  98 +       if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, 
  99 +           &gssbuf, &mic))))
 100 +               authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
 101 +       
 102 +       buffer_free(&b);
 103 +       free(mic.value);
 104 +
 105 +       return (authenticated);
 106 +}
 107 +
 108  /*
 109   * We only support those mechanisms that we know about (ie ones that we know
 110   * how to check local user kuserok and the like)
 111 @@ -290,6 +323,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
 112         return 0;
 113  }
 114  
 115 +Authmethod method_gsskeyex = {
 116 +       "gssapi-keyex",
 117 +       userauth_gsskeyex,
 118 +       &options.gss_authentication
 119 +};
 120 +
 121  Authmethod method_gssapi = {
 122         "gssapi-with-mic",
 123         userauth_gssapi,
 124 diff --git a/auth2.c b/auth2.c
 125 index 32ba663..5a3ef1b 100644
 126 --- a/auth2.c
 127 +++ b/auth2.c
 128 @@ -70,6 +70,7 @@ extern Authmethod method_passwd;
 129  extern Authmethod method_kbdint;
 130  extern Authmethod method_hostbased;
 131  #ifdef GSSAPI
 132 +extern Authmethod method_gsskeyex;
 133  extern Authmethod method_gssapi;
 134  #endif
 135  
 136 @@ -77,6 +78,7 @@ Authmethod *authmethods[] = {
 137         &method_none,
 138         &method_pubkey,
 139  #ifdef GSSAPI
 140 +       &method_gsskeyex,
 141         &method_gssapi,
 142  #endif
 143         &method_passwd,
 144 diff --git a/gss-genr.c b/gss-genr.c
 145 index d617d60..9dcf51c 100644
 146 --- a/gss-genr.c
 147 +++ b/gss-genr.c
 148 @@ -1,7 +1,7 @@
 149  /* $OpenBSD: gss-genr.c,v 1.23 2015/01/20 23:14:00 deraadt Exp $ */
 150  
 151  /*
 152 - * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
 153 + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
 154   *
 155   * Redistribution and use in source and binary forms, with or without
 156   * modification, are permitted provided that the following conditions
 157 @@ -41,12 +41,167 @@
 158  #include "buffer.h"
 159  #include "log.h"
 160  #include "ssh2.h"
 161 +#include "cipher.h"
 162 +#include "key.h"
 163 +#include "kex.h"
 164 +#include <openssl/evp.h>
 165  
 166  #include "ssh-gss.h"
 167  
 168  extern u_char *session_id2;
 169  extern u_int session_id2_len;
 170  
 171 +typedef struct {
 172 +       char *encoded;
 173 +       gss_OID oid;
 174 +} ssh_gss_kex_mapping;
 175 +
 176 +/*
 177 + * XXX - It would be nice to find a more elegant way of handling the
 178 + * XXX   passing of the key exchange context to the userauth routines
 179 + */
 180 +
 181 +Gssctxt *gss_kex_context = NULL;
 182 +
 183 +static ssh_gss_kex_mapping *gss_enc2oid = NULL;
 184 +
 185 +int 
 186 +ssh_gssapi_oid_table_ok() {
 187 +       return (gss_enc2oid != NULL);
 188 +}
 189 +
 190 +/*
 191 + * Return a list of the gss-group1-sha1 mechanisms supported by this program
 192 + *
 193 + * We test mechanisms to ensure that we can use them, to avoid starting
 194 + * a key exchange with a bad mechanism
 195 + */
 196 +
 197 +char *
 198 +ssh_gssapi_client_mechanisms(const char *host) {
 199 +       gss_OID_set gss_supported;
 200 +       OM_uint32 min_status;
 201 +
 202 +       if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
 203 +               return NULL;
 204 +
 205 +       return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
 206 +           host));
 207 +}
 208 +
 209 +char *
 210 +ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
 211 +    const char *data) {
 212 +       Buffer buf;
 213 +       size_t i;
 214 +       int oidpos, enclen;
 215 +       char *mechs, *encoded;
 216 +       u_char digest[EVP_MAX_MD_SIZE];
 217 +       char deroid[2];
 218 +       const EVP_MD *evp_md = EVP_md5();
 219 +       EVP_MD_CTX md;
 220 +
 221 +       if (gss_enc2oid != NULL) {
 222 +               for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
 223 +                       free(gss_enc2oid[i].encoded);
 224 +               free(gss_enc2oid);
 225 +       }
 226 +
 227 +       gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
 228 +           (gss_supported->count + 1));
 229 +
 230 +       buffer_init(&buf);
 231 +
 232 +       oidpos = 0;
 233 +       for (i = 0; i < gss_supported->count; i++) {
 234 +               if (gss_supported->elements[i].length < 128 &&
 235 +                   (*check)(NULL, &(gss_supported->elements[i]), data)) {
 236 +
 237 +                       deroid[0] = SSH_GSS_OIDTYPE;
 238 +                       deroid[1] = gss_supported->elements[i].length;
 239 +
 240 +                       EVP_DigestInit(&md, evp_md);
 241 +                       EVP_DigestUpdate(&md, deroid, 2);
 242 +                       EVP_DigestUpdate(&md,
 243 +                           gss_supported->elements[i].elements,
 244 +                           gss_supported->elements[i].length);
 245 +                       EVP_DigestFinal(&md, digest, NULL);
 246 +
 247 +                       encoded = xmalloc(EVP_MD_size(evp_md) * 2);
 248 +                       enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
 249 +                           encoded, EVP_MD_size(evp_md) * 2);
 250 +
 251 +                       if (oidpos != 0)
 252 +                               buffer_put_char(&buf, ',');
 253 +
 254 +                       buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
 255 +                           sizeof(KEX_GSS_GEX_SHA1_ID) - 1);
 256 +                       buffer_append(&buf, encoded, enclen);
 257 +                       buffer_put_char(&buf, ',');
 258 +                       buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID, 
 259 +                           sizeof(KEX_GSS_GRP1_SHA1_ID) - 1);
 260 +                       buffer_append(&buf, encoded, enclen);
 261 +                       buffer_put_char(&buf, ',');
 262 +                       buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID,
 263 +                           sizeof(KEX_GSS_GRP14_SHA1_ID) - 1);
 264 +                       buffer_append(&buf, encoded, enclen);
 265 +
 266 +                       gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
 267 +                       gss_enc2oid[oidpos].encoded = encoded;
 268 +                       oidpos++;
 269 +               }
 270 +       }
 271 +       gss_enc2oid[oidpos].oid = NULL;
 272 +       gss_enc2oid[oidpos].encoded = NULL;
 273 +
 274 +       buffer_put_char(&buf, '\0');
 275 +
 276 +       mechs = xmalloc(buffer_len(&buf));
 277 +       buffer_get(&buf, mechs, buffer_len(&buf));
 278 +       buffer_free(&buf);
 279 +
 280 +       if (strlen(mechs) == 0) {
 281 +               free(mechs);
 282 +               mechs = NULL;
 283 +       }
 284 +       
 285 +       return (mechs);
 286 +}
 287 +
 288 +gss_OID
 289 +ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
 290 +       int i = 0;
 291 +       
 292 +       switch (kex_type) {
 293 +       case KEX_GSS_GRP1_SHA1:
 294 +               if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID))
 295 +                       return GSS_C_NO_OID;
 296 +               name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1;
 297 +               break;
 298 +       case KEX_GSS_GRP14_SHA1:
 299 +               if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID))
 300 +                       return GSS_C_NO_OID;
 301 +               name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
 302 +               break;
 303 +       case KEX_GSS_GEX_SHA1:
 304 +               if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID))
 305 +                       return GSS_C_NO_OID;
 306 +               name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
 307 +               break;
 308 +       default:
 309 +               return GSS_C_NO_OID;
 310 +       }
 311 +
 312 +       while (gss_enc2oid[i].encoded != NULL &&
 313 +           strcmp(name, gss_enc2oid[i].encoded) != 0)
 314 +               i++;
 315 +
 316 +       if (gss_enc2oid[i].oid != NULL && ctx != NULL)
 317 +               ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
 318 +
 319 +       return gss_enc2oid[i].oid;
 320 +}
 321 +
 322  /* Check that the OID in a data stream matches that in the context */
 323  int
 324  ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
 325 @@ -231,6 +386,9 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
 326  OM_uint32
 327  ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
 328  {
 329 +       if (ctx == NULL) 
 330 +               return -1;
 331 +
 332         if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
 333             GSS_C_QOP_DEFAULT, buffer, hash)))
 334                 ssh_gssapi_error(ctx);
 335 @@ -238,6 +396,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
 336         return (ctx->major);
 337  }
 338  
 339 +/* Priviledged when used by server */
 340 +OM_uint32
 341 +ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
 342 +{
 343 +       if (ctx == NULL)
 344 +               return -1;
 345 +
 346 +       ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
 347 +           gssbuf, gssmic, NULL);
 348 +
 349 +       return (ctx->major);
 350 +}
 351 +
 352  void
 353  ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
 354      const char *context)
 355 @@ -256,6 +427,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
 356         gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
 357         OM_uint32 major, minor;
 358         gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
 359 +       Gssctxt *intctx = NULL;
 360 +
 361 +       if (ctx == NULL)
 362 +               ctx = &intctx;
 363  
 364         /* RFC 4462 says we MUST NOT do SPNEGO */
 365         if (oid->length == spnego_oid.length && 
 366 @@ -274,7 +449,7 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
 367                             GSS_C_NO_BUFFER);
 368         }
 369  
 370 -       if (GSS_ERROR(major)) 
 371 +       if (GSS_ERROR(major) || intctx != NULL) 
 372                 ssh_gssapi_delete_ctx(ctx);
 373  
 374         return (!GSS_ERROR(major));
 375 diff --git a/gss-serv.c b/gss-serv.c
 376 index 209ffe8..a45d8fd 100644
 377 --- a/gss-serv.c
 378 +++ b/gss-serv.c
 379 @@ -1,7 +1,7 @@
 380  /* $OpenBSD: gss-serv.c,v 1.29 2015/05/22 03:50:02 djm Exp $ */
 381  
 382  /*
 383 - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
 384 + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
 385   *
 386   * Redistribution and use in source and binary forms, with or without
 387   * modification, are permitted provided that the following conditions
 388 @@ -47,6 +47,7 @@
 389  #include "servconf.h"
 390  
 391  #include "ssh-gss.h"
 392 +#include "monitor_wrap.h"
 393  
 394  extern ServerOptions options;
 395  
 396 @@ -142,6 +143,28 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
 397  }
 398  
 399  /* Unprivileged */
 400 +char *
 401 +ssh_gssapi_server_mechanisms() {
 402 +       gss_OID_set     supported;
 403 +
 404 +       ssh_gssapi_supported_oids(&supported);
 405 +       return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
 406 +           NULL));
 407 +}
 408 +
 409 +/* Unprivileged */
 410 +int
 411 +ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data) {
 412 +       Gssctxt *ctx = NULL;
 413 +       int res;
 414 + 
 415 +       res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
 416 +       ssh_gssapi_delete_ctx(&ctx);
 417 +
 418 +       return (res);
 419 +}
 420 +
 421 +/* Unprivileged */
 422  void
 423  ssh_gssapi_supported_oids(gss_OID_set *oidset)
 424  {
 425 @@ -151,7 +174,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset)
 426         gss_OID_set supported;
 427  
 428         gss_create_empty_oid_set(&min_status, oidset);
 429 -       gss_indicate_mechs(&min_status, &supported);
 430 +
 431 +       if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
 432 +               return;
 433  
 434         while (supported_mechs[i]->name != NULL) {
 435                 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
 436 @@ -427,14 +452,4 @@ ssh_gssapi_userok(char *user)
 437         return (0);
 438  }
 439  
 440 -/* Privileged */
 441 -OM_uint32
 442 -ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
 443 -{
 444 -       ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
 445 -           gssbuf, gssmic, NULL);
 446 -
 447 -       return (ctx->major);
 448 -}
 449 -
 450  #endif
 451 diff --git a/kex.c b/kex.c
 452 index b777b7d..ad0598e 100644
 453 --- a/kex.c
 454 +++ b/kex.c
 455 @@ -55,6 +55,10 @@
 456  #include "sshbuf.h"
 457  #include "digest.h"
 458  
 459 +#ifdef GSSAPI
 460 +#include "ssh-gss.h"
 461 +#endif
 462 +
 463  #if OPENSSL_VERSION_NUMBER >= 0x00907000L
 464  # if defined(HAVE_EVP_SHA256)
 465  # define evp_ssh_sha256 EVP_sha256
 466 @@ -95,6 +99,11 @@ static const struct kexalg kexalgs[] = {
 467  #if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL)
 468         { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
 469  #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
 470 +#ifdef GSSAPI
 471 +       { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
 472 +       { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
 473 +       { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
 474 +#endif
 475         { NULL, -1, -1, -1},
 476  };
 477  
 478 @@ -126,7 +135,7 @@ kex_alg_by_name(const char *name)
 479         const struct kexalg *k;
 480  
 481         for (k = kexalgs; k->name != NULL; k++) {
 482 -               if (strcmp(k->name, name) == 0)
 483 +               if (strncmp(k->name, name, strlen(k->name)) == 0)
 484                         return k;
 485         }
 486         return NULL;
 487 diff --git a/kex.h b/kex.h
 488 index d71b532..04b4733 100644
 489 --- a/kex.h
 490 +++ b/kex.h
 491 @@ -93,6 +93,9 @@ enum kex_exchange {
 492         KEX_DH_GEX_SHA256,
 493         KEX_ECDH_SHA2,
 494         KEX_C25519_SHA256,
 495 +       KEX_GSS_GRP1_SHA1,
 496 +       KEX_GSS_GRP14_SHA1,
 497 +       KEX_GSS_GEX_SHA1,
 498         KEX_MAX
 499  };
 500  
 501 @@ -139,6 +142,10 @@ struct kex {
 502         u_int   flags;
 503         int     hash_alg;
 504         int     ec_nid;
 505 +#ifdef GSSAPI
 506 +       int     gss_deleg_creds;
 507 +       char    *gss_host;
 508 +#endif
 509         char    *client_version_string;
 510         char    *server_version_string;
 511         char    *failed_choice;
 512 @@ -186,6 +193,10 @@ int         kexecdh_client(struct ssh *);
 513  int     kexecdh_server(struct ssh *);
 514  int     kexc25519_client(struct ssh *);
 515  int     kexc25519_server(struct ssh *);
 516 +#ifdef GSSAPI
 517 +int     kexgss_client(struct ssh *);
 518 +int     kexgss_server(struct ssh *);
 519 +#endif
 520  
 521  int     kex_dh_hash(const char *, const char *,
 522      const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
 523 diff --git a/kexgssc.c b/kexgssc.c
 524 new file mode 100644
 525 index 0000000..c36d36b
 526 --- /dev/null
 527 +++ b/kexgssc.c
 528 @@ -0,0 +1,347 @@
 529 +/*
 530 + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
 531 + *
 532 + * Redistribution and use in source and binary forms, with or without
 533 + * modification, are permitted provided that the following conditions
 534 + * are met:
 535 + * 1. Redistributions of source code must retain the above copyright
 536 + *    notice, this list of conditions and the following disclaimer.
 537 + * 2. Redistributions in binary form must reproduce the above copyright
 538 + *    notice, this list of conditions and the following disclaimer in the
 539 + *    documentation and/or other materials provided with the distribution.
 540 + *
 541 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
 542 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 543 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 544 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 545 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 546 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 547 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 548 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 549 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 550 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 551 + */
 552 +
 553 +/*
 554 + * May 22, 2015
 555 + * In version 6.8 a new packet interface has been introduced to OpenSSH,
 556 + * while the old packet API has been provided in opacket.c.
 557 + * At this moment we are not rewritting GSS-API key exchange code to the new
 558 + * API, just adjusting it to still work with new struct ssh.
 559 + * Rewritting to the new API can be considered in the future.
 560 + */
 561 +
 562 +#include "includes.h"
 563 +
 564 +#ifdef GSSAPI
 565 +
 566 +#include "includes.h"
 567 +
 568 +#include <openssl/crypto.h>
 569 +#include <openssl/bn.h>
 570 +
 571 +#include <signal.h>      /* for sig_atomic_t in kex.h */
 572 +#include <string.h>
 573 +
 574 +#include "xmalloc.h"
 575 +#include "buffer.h"
 576 +#include "ssh2.h"
 577 +#include "key.h"
 578 +#include "cipher.h"
 579 +#include "digest.h"
 580 +#include "kex.h"
 581 +#include "log.h"
 582 +#include "packet.h"
 583 +#include "dh.h"
 584 +
 585 +#include "ssh-gss.h"
 586 +
 587 +int
 588 +kexgss_client(struct ssh *ssh) {
 589 +       gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
 590 +       gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr;
 591 +       Gssctxt *ctxt;
 592 +       OM_uint32 maj_status, min_status, ret_flags;
 593 +       uint_t klen, kout, slen = 0, strlen;
 594 +       DH *dh;
 595 +       BIGNUM *dh_server_pub = NULL;
 596 +       BIGNUM *shared_secret = NULL;
 597 +       BIGNUM *p = NULL;
 598 +       BIGNUM *g = NULL;
 599 +       uchar_t *kbuf;
 600 +       uchar_t *serverhostkey = NULL;
 601 +       uchar_t *empty = "";
 602 +       char *msg;
 603 +       char *lang;
 604 +       int type = 0;
 605 +       int first = 1;
 606 +       int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
 607 +       struct kex *kex = ssh->kex;
 608 +       int r;
 609 +       uchar_t hash[SSH_DIGEST_MAX_LENGTH];
 610 +       size_t hashlen;
 611 +
 612 +       /* Initialise our GSSAPI world */
 613 +       ssh_gssapi_build_ctx(&ctxt);
 614 +       if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type)
 615 +           == GSS_C_NO_OID)
 616 +               fatal("Couldn't identify host exchange");
 617 +
 618 +       if (ssh_gssapi_import_name(ctxt, kex->gss_host))
 619 +               fatal("Couldn't import hostname");
 620 +
 621 +       switch (kex->kex_type) {
 622 +       case KEX_GSS_GRP1_SHA1:
 623 +               kex->dh = dh_new_group1();
 624 +               break;
 625 +       case KEX_GSS_GRP14_SHA1:
 626 +               kex->dh = dh_new_group14();
 627 +               break;
 628 +       case KEX_GSS_GEX_SHA1:
 629 +               debug("Doing group exchange\n");
 630 +               nbits = dh_estimate(kex->we_need * 8);
 631 +               packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
 632 +               packet_put_int(min);
 633 +               packet_put_int(nbits);
 634 +               packet_put_int(max);
 635 +
 636 +               packet_send();
 637 +
 638 +               packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
 639 +
 640 +               if ((p = BN_new()) == NULL)
 641 +                       fatal("BN_new() failed");
 642 +               packet_get_bignum2(p);
 643 +               if ((g = BN_new()) == NULL)
 644 +                       fatal("BN_new() failed");
 645 +               packet_get_bignum2(g);
 646 +               packet_check_eom();
 647 +
 648 +               if (BN_num_bits(p) < min || BN_num_bits(p) > max)
 649 +                       fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
 650 +                           min, BN_num_bits(p), max);
 651 +
 652 +               kex->dh = dh_new_group(g, p);
 653 +               break;
 654 +       default:
 655 +               fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
 656 +       }
 657 +
 658 +       /* Step 1 - e is dh->pub_key */
 659 +       dh_gen_key(kex->dh, kex->we_need * 8);
 660 +
 661 +       /* This is f, we initialise it now to make life easier */
 662 +       dh_server_pub = BN_new();
 663 +       if (dh_server_pub == NULL)
 664 +               fatal("dh_server_pub == NULL");
 665 +
 666 +       token_ptr = GSS_C_NO_BUFFER;
 667 +
 668 +       do {
 669 +               debug("Calling gss_init_sec_context");
 670 +
 671 +               maj_status = ssh_gssapi_init_ctx(ctxt,
 672 +                   kex->gss_deleg_creds, token_ptr, &send_tok,
 673 +                   &ret_flags);
 674 +
 675 +               if (GSS_ERROR(maj_status)) {
 676 +                       if (send_tok.length != 0) {
 677 +                               packet_start(SSH2_MSG_KEXGSS_CONTINUE);
 678 +                               packet_put_string(send_tok.value,
 679 +                                   send_tok.length);
 680 +                       }
 681 +                       fatal("gss_init_context failed");
 682 +               }
 683 +
 684 +               /* If we've got an old receive buffer get rid of it */
 685 +               if (token_ptr != GSS_C_NO_BUFFER)
 686 +                       free(recv_tok.value);
 687 +
 688 +               if (maj_status == GSS_S_COMPLETE) {
 689 +                       /* If mutual state flag is not true, kex fails */
 690 +                       if (!(ret_flags & GSS_C_MUTUAL_FLAG))
 691 +                               fatal("Mutual authentication failed");
 692 +
 693 +                       /* If integ avail flag is not true kex fails */
 694 +                       if (!(ret_flags & GSS_C_INTEG_FLAG))
 695 +                               fatal("Integrity check failed");
 696 +               }
 697 +
 698 +               /*
 699 +                * If we have data to send, then the last message that we
 700 +                * received cannot have been a 'complete'.
 701 +                */
 702 +               if (send_tok.length != 0) {
 703 +                       if (first) {
 704 +                               packet_start(SSH2_MSG_KEXGSS_INIT);
 705 +                               packet_put_string(send_tok.value,
 706 +                                   send_tok.length);
 707 +                               packet_put_bignum2(kex->dh->pub_key);
 708 +                               first = 0;
 709 +                       } else {
 710 +                               packet_start(SSH2_MSG_KEXGSS_CONTINUE);
 711 +                               packet_put_string(send_tok.value,
 712 +                                   send_tok.length);
 713 +                       }
 714 +                       packet_send();
 715 +                       gss_release_buffer(&min_status, &send_tok);
 716 +
 717 +                       /* If we've sent them data, they should reply */
 718 +                       do {
 719 +                               type = packet_read();
 720 +                               if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
 721 +                                       debug("Received KEXGSS_HOSTKEY");
 722 +                                       if (serverhostkey)
 723 +                                               fatal("Server host key received"
 724 +                                                   "more than once");
 725 +                                       serverhostkey =
 726 +                                           packet_get_string(&slen);
 727 +                               }
 728 +                       } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
 729 +
 730 +                       switch (type) {
 731 +                       case SSH2_MSG_KEXGSS_CONTINUE:
 732 +                               debug("Received GSSAPI_CONTINUE");
 733 +                               if (maj_status == GSS_S_COMPLETE)
 734 +                                       fatal("GSSAPI Continue received from"
 735 +                                           "server when complete");
 736 +                               recv_tok.value = packet_get_string(&strlen);
 737 +                               recv_tok.length = strlen;
 738 +                               break;
 739 +                       case SSH2_MSG_KEXGSS_COMPLETE:
 740 +                               debug("Received GSSAPI_COMPLETE");
 741 +                               packet_get_bignum2(dh_server_pub);
 742 +                               msg_tok.value =  packet_get_string(&strlen);
 743 +                               msg_tok.length = strlen;
 744 +
 745 +                               /* Is there a token included? */
 746 +                               if (packet_get_char()) {
 747 +                                       recv_tok.value=
 748 +                                           packet_get_string(&strlen);
 749 +                                       recv_tok.length = strlen;
 750 +                                       /* If complete - protocol error */
 751 +                                       if (maj_status == GSS_S_COMPLETE)
 752 +                                               packet_disconnect("Protocol"
 753 +                                                   " error: received token"
 754 +                                                   " when complete");
 755 +                               } else {
 756 +                                       /* No token included */
 757 +                                       if (maj_status != GSS_S_COMPLETE)
 758 +                                               packet_disconnect("Protocol"
 759 +                                                   " error: did not receive"
 760 +                                                   " final token");
 761 +                               }
 762 +                               break;
 763 +                       case SSH2_MSG_KEXGSS_ERROR:
 764 +                               debug("Received Error");
 765 +                               maj_status = packet_get_int();
 766 +                               min_status = packet_get_int();
 767 +                               msg = packet_get_string(NULL);
 768 +                               lang = packet_get_string(NULL);
 769 +                               fatal("GSSAPI Error: \n%.400s", msg);
 770 +                       default:
 771 +                               packet_disconnect("Protocol error: didn't"
 772 +                                   " expect packet type %d", type);
 773 +                       }
 774 +                       token_ptr = &recv_tok;
 775 +               } else {
 776 +                       /* No data, and not complete */
 777 +                       if (maj_status != GSS_S_COMPLETE)
 778 +                               fatal("Not complete, and no token output");
 779 +               }
 780 +       } while (maj_status & GSS_S_CONTINUE_NEEDED);
 781 +
 782 +       /*
 783 +        * We _must_ have received a COMPLETE message in reply from the
 784 +        * server, which will have set dh_server_pub and msg_tok
 785 +        */
 786 +
 787 +       if (type != SSH2_MSG_KEXGSS_COMPLETE)
 788 +               fatal("Didn't receive SSH2_MSG_KEXGSS_COMPLETE when expected");
 789 +
 790 +       /* Check f in range [1, p-1] */
 791 +       if (!dh_pub_is_valid(kex->dh, dh_server_pub))
 792 +               packet_disconnect("bad server public DH value");
 793 +
 794 +       /* compute K=f^x mod p */
 795 +       klen = DH_size(kex->dh);
 796 +       kbuf = xmalloc(klen);
 797 +       kout = DH_compute_key(kbuf, dh_server_pub, kex->dh);
 798 +       if (kout < 0)
 799 +               fatal("DH_compute_key: failed");
 800 +
 801 +       shared_secret = BN_new();
 802 +       if (shared_secret == NULL)
 803 +               fatal("kexgss_client: BN_new failed");
 804 +
 805 +       if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
 806 +               fatal("kexdh_client: BN_bin2bn failed");
 807 +
 808 +       memset(kbuf, 0, klen);
 809 +       free(kbuf);
 810 +
 811 +       hashlen = sizeof (hash);
 812 +       switch (kex->kex_type) {
 813 +       case KEX_GSS_GRP1_SHA1:
 814 +       case KEX_GSS_GRP14_SHA1:
 815 +               kex_dh_hash(kex->client_version_string,
 816 +                   kex->server_version_string,
 817 +                   buffer_ptr(kex->my), buffer_len(kex->my),
 818 +                   buffer_ptr(kex->peer), buffer_len(kex->peer),
 819 +                   (serverhostkey ? serverhostkey : empty), slen,
 820 +                   kex->dh->pub_key,     /* e */
 821 +                   dh_server_pub,      /* f */
 822 +                   shared_secret,      /* K */
 823 +                   hash, &hashlen);
 824 +               break;
 825 +       case KEX_GSS_GEX_SHA1:
 826 +               kexgex_hash(
 827 +                   kex->hash_alg,
 828 +                   kex->client_version_string,
 829 +                   kex->server_version_string,
 830 +                   buffer_ptr(kex->my), buffer_len(kex->my),
 831 +                   buffer_ptr(kex->peer), buffer_len(kex->peer),
 832 +                   (serverhostkey ? serverhostkey : empty), slen,
 833 +                   min, nbits, max,
 834 +                   kex->dh->p, kex->dh->g,
 835 +                   kex->dh->pub_key,
 836 +                   dh_server_pub,
 837 +                   shared_secret,
 838 +                   hash, &hashlen);
 839 +               break;
 840 +       default:
 841 +               fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
 842 +       }
 843 +
 844 +       gssbuf.value = hash;
 845 +       gssbuf.length = hashlen;
 846 +
 847 +       /* Verify that the hash matches the MIC we just got. */
 848 +       if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
 849 +               packet_disconnect("Hash's MIC didn't verify");
 850 +
 851 +       free(msg_tok.value);
 852 +
 853 +       DH_free(kex->dh);
 854 +       if (serverhostkey)
 855 +               free(serverhostkey);
 856 +       BN_clear_free(dh_server_pub);
 857 +
 858 +       /* save session id */
 859 +       if (kex->session_id == NULL) {
 860 +               kex->session_id_len = hashlen;
 861 +               kex->session_id = xmalloc(kex->session_id_len);
 862 +               memcpy(kex->session_id, hash, kex->session_id_len);
 863 +       }
 864 +
 865 +       if (gss_kex_context == NULL)
 866 +               gss_kex_context = ctxt;
 867 +       else
 868 +               ssh_gssapi_delete_ctx(&ctxt);
 869 +
 870 +       if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
 871 +               r = kex_send_newkeys(ssh);
 872 +       return (r);
 873 +}
 874 +
 875 +#endif /* GSSAPI */
 876 diff --git a/kexgsss.c b/kexgsss.c
 877 new file mode 100644
 878 index 0000000..2009cd9
 879 --- /dev/null
 880 +++ b/kexgsss.c
 881 @@ -0,0 +1,297 @@
 882 +/*
 883 + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
 884 + *
 885 + * Redistribution and use in source and binary forms, with or without
 886 + * modification, are permitted provided that the following conditions
 887 + * are met:
 888 + * 1. Redistributions of source code must retain the above copyright
 889 + *    notice, this list of conditions and the following disclaimer.
 890 + * 2. Redistributions in binary form must reproduce the above copyright
 891 + *    notice, this list of conditions and the following disclaimer in the
 892 + *    documentation and/or other materials provided with the distribution.
 893 + *
 894 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
 895 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 896 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 897 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 898 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 899 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 900 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 901 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 902 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 903 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 904 + */
 905 +
 906 +/*
 907 + * May 22, 2015
 908 + * In version 6.8 a new packet interface has been introduced to OpenSSH,
 909 + * while the old packet API has been provided in opacket.c.
 910 + * At this moment we are not rewritting GSS-API key exchange code to the new
 911 + * API, just adjusting it to still work with new struct ssh.
 912 + * Rewritting to the new API can be considered in the future.
 913 + */
 914 +
 915 +#include "includes.h"
 916 +
 917 +#ifdef GSSAPI
 918 +
 919 +#include <signal.h>      /* for sig_atomic_t in kex.h */
 920 +#include <string.h>
 921 +
 922 +#include <openssl/crypto.h>
 923 +#include <openssl/bn.h>
 924 +
 925 +#include "xmalloc.h"
 926 +#include "buffer.h"
 927 +#include "ssh2.h"
 928 +#include "key.h"
 929 +#include "cipher.h"
 930 +#include "digest.h"
 931 +#include "kex.h"
 932 +#include "log.h"
 933 +#include "packet.h"
 934 +#include "dh.h"
 935 +#include "ssh-gss.h"
 936 +#include "monitor_wrap.h"
 937 +
 938 +int
 939 +kexgss_server(struct ssh *ssh)
 940 +{
 941 +       OM_uint32 maj_status, min_status;
 942 +
 943 +       /*
 944 +        * Some GSSAPI implementations use the input value of ret_flags (an
 945 +        * output variable) as a means of triggering mechanism specific
 946 +        * features. Initializing it to zero avoids inadvertently
 947 +        * activating this non-standard behaviour.
 948 +        */
 949 +
 950 +       OM_uint32 ret_flags = 0;
 951 +       gss_buffer_desc gssbuf, recv_tok, msg_tok;
 952 +       gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
 953 +       Gssctxt *ctxt = NULL;
 954 +       uint_t slen, klen, kout;
 955 +       uchar_t *kbuf;
 956 +       DH *dh;
 957 +       int min = -1, max = -1, nbits = -1;
 958 +       BIGNUM *shared_secret = NULL;
 959 +       BIGNUM *dh_client_pub = NULL;
 960 +       int type = 0;
 961 +       gss_OID oid;
 962 +       char *mechs;
 963 +       struct kex *kex = ssh->kex;
 964 +       int r;
 965 +       uchar_t hash[SSH_DIGEST_MAX_LENGTH];
 966 +       size_t hashlen;
 967 +
 968 +       /* Initialise GSSAPI */
 969 +
 970 +       /*
 971 +        * If we're rekeying, privsep means that some of the private structures
 972 +        * in the GSSAPI code are no longer available. This kludges them back
 973 +        * into life
 974 +        */
 975 +       if (!ssh_gssapi_oid_table_ok())
 976 +               if ((mechs = ssh_gssapi_server_mechanisms()))
 977 +                       free(mechs);
 978 +
 979 +       debug2("%s: Identifying %s", __func__, kex->name);
 980 +       oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type);
 981 +       if (oid == GSS_C_NO_OID)
 982 +               fatal("Unknown gssapi mechanism");
 983 +
 984 +       debug2("%s: Acquiring credentials", __func__);
 985 +
 986 +       if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
 987 +               fatal("Unable to acquire credentials for the server");
 988 +
 989 +       switch (kex->kex_type) {
 990 +       case KEX_GSS_GRP1_SHA1:
 991 +               kex->dh = dh_new_group1();
 992 +               break;
 993 +       case KEX_GSS_GRP14_SHA1:
 994 +               kex->dh = dh_new_group14();
 995 +               break;
 996 +       case KEX_GSS_GEX_SHA1:
 997 +               debug("Doing group exchange");
 998 +               packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ);
 999 +               min = packet_get_int();
1000 +               nbits = packet_get_int();
1001 +               max = packet_get_int();
1002 +               min = MAX(DH_GRP_MIN, min);
1003 +               max = MIN(DH_GRP_MAX, max);
1004 +               packet_check_eom();
1005 +               if (max < min || nbits < min || max < nbits)
1006 +                       fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
1007 +                           min, nbits, max);
1008 +               kex->dh = PRIVSEP(choose_dh(min, nbits, max));
1009 +               if (kex->dh == NULL)
1010 +                       packet_disconnect("Protocol error:"
1011 +                           " no matching group found");
1012 +
1013 +               packet_start(SSH2_MSG_KEXGSS_GROUP);
1014 +               packet_put_bignum2(kex->dh->p);
1015 +               packet_put_bignum2(kex->dh->g);
1016 +               packet_send();
1017 +
1018 +               packet_write_wait();
1019 +               break;
1020 +       default:
1021 +               fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
1022 +       }
1023 +
1024 +       dh_gen_key(kex->dh, kex->we_need * 8);
1025 +
1026 +       do {
1027 +               debug("Wait SSH2_MSG_GSSAPI_INIT");
1028 +               type = packet_read();
1029 +               switch (type) {
1030 +               case SSH2_MSG_KEXGSS_INIT:
1031 +                       if (dh_client_pub != NULL)
1032 +                               fatal("Received KEXGSS_INIT after"
1033 +                                   " initialising");
1034 +                       recv_tok.value = packet_get_string(&slen);
1035 +                       recv_tok.length = slen;
1036 +
1037 +                       if ((dh_client_pub = BN_new()) == NULL)
1038 +                               fatal("dh_client_pub == NULL");
1039 +
1040 +                       packet_get_bignum2(dh_client_pub);
1041 +
1042 +                       /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
1043 +                       break;
1044 +               case SSH2_MSG_KEXGSS_CONTINUE:
1045 +                       recv_tok.value = packet_get_string(&slen);
1046 +                       recv_tok.length = slen;
1047 +                       break;
1048 +               default:
1049 +                       packet_disconnect(
1050 +                           "Protocol error: didn't expect packet type %d",
1051 +                           type);
1052 +               }
1053 +
1054 +               maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
1055 +                   &send_tok, &ret_flags));
1056 +
1057 +               free(recv_tok.value);
1058 +
1059 +               if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
1060 +                       fatal("Zero length token output when incomplete");
1061 +
1062 +               if (dh_client_pub == NULL)
1063 +                       fatal("No client public key");
1064 +
1065 +               if (maj_status & GSS_S_CONTINUE_NEEDED) {
1066 +                       debug("Sending GSSAPI_CONTINUE");
1067 +                       packet_start(SSH2_MSG_KEXGSS_CONTINUE);
1068 +                       packet_put_string(send_tok.value, send_tok.length);
1069 +                       packet_send();
1070 +                       gss_release_buffer(&min_status, &send_tok);
1071 +               }
1072 +       } while (maj_status & GSS_S_CONTINUE_NEEDED);
1073 +
1074 +       if (GSS_ERROR(maj_status)) {
1075 +               if (send_tok.length > 0) {
1076 +                       packet_start(SSH2_MSG_KEXGSS_CONTINUE);
1077 +                       packet_put_string(send_tok.value, send_tok.length);
1078 +                       packet_send();
1079 +               }
1080 +               fatal("accept_ctx died");
1081 +       }
1082 +
1083 +       if (!(ret_flags & GSS_C_MUTUAL_FLAG))
1084 +               fatal("Mutual Authentication flag wasn't set");
1085 +
1086 +       if (!(ret_flags & GSS_C_INTEG_FLAG))
1087 +               fatal("Integrity flag wasn't set");
1088 +
1089 +       if (!dh_pub_is_valid(kex->dh, dh_client_pub))
1090 +               packet_disconnect("bad client public DH value");
1091 +
1092 +       klen = DH_size(kex->dh);
1093 +       kbuf = xmalloc(klen);
1094 +       kout = DH_compute_key(kbuf, dh_client_pub, kex->dh);
1095 +       if (kout < 0)
1096 +               fatal("DH_compute_key: failed");
1097 +
1098 +       shared_secret = BN_new();
1099 +       if (shared_secret == NULL)
1100 +               fatal("kexgss_server: BN_new failed");
1101 +
1102 +       if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
1103 +               fatal("kexgss_server: BN_bin2bn failed");
1104 +
1105 +       memset(kbuf, 0, klen);
1106 +       free(kbuf);
1107 +
1108 +       hashlen = sizeof (hash);
1109 +       switch (kex->kex_type) {
1110 +       case KEX_GSS_GRP1_SHA1:
1111 +       case KEX_GSS_GRP14_SHA1:
1112 +               kex_dh_hash(
1113 +                   kex->client_version_string, kex->server_version_string,
1114 +                   buffer_ptr(kex->peer), buffer_len(kex->peer),
1115 +                   buffer_ptr(kex->my), buffer_len(kex->my),
1116 +                   NULL, 0, /* Change this if we start sending host keys */
1117 +                   dh_client_pub, kex->dh->pub_key, shared_secret,
1118 +                   hash, &hashlen);
1119 +               break;
1120 +       case KEX_GSS_GEX_SHA1:
1121 +               kexgex_hash(
1122 +                   kex->hash_alg,
1123 +                   kex->client_version_string, kex->server_version_string,
1124 +                   buffer_ptr(kex->peer), buffer_len(kex->peer),
1125 +                   buffer_ptr(kex->my), buffer_len(kex->my),
1126 +                   NULL, 0,
1127 +                   min, nbits, max,
1128 +                   kex->dh->p, kex->dh->g,
1129 +                   dh_client_pub,
1130 +                   kex->dh->pub_key,
1131 +                   shared_secret,
1132 +                   hash, &hashlen);
1133 +               break;
1134 +       default:
1135 +               fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
1136 +       }
1137 +
1138 +       BN_clear_free(dh_client_pub);
1139 +
1140 +       if (kex->session_id == NULL) {
1141 +               kex->session_id_len = hashlen;
1142 +               kex->session_id = xmalloc(kex->session_id_len);
1143 +               memcpy(kex->session_id, hash, kex->session_id_len);
1144 +       }
1145 +
1146 +       gssbuf.value = hash;
1147 +       gssbuf.length = hashlen;
1148 +
1149 +       if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt, &gssbuf, &msg_tok))))
1150 +               fatal("Couldn't get MIC");
1151 +
1152 +       packet_start(SSH2_MSG_KEXGSS_COMPLETE);
1153 +       packet_put_bignum2(kex->dh->pub_key);
1154 +       packet_put_string(msg_tok.value, msg_tok.length);
1155 +
1156 +       if (send_tok.length != 0) {
1157 +               packet_put_char(1); /* true */
1158 +               packet_put_string(send_tok.value, send_tok.length);
1159 +       } else {
1160 +               packet_put_char(0); /* false */
1161 +       }
1162 +       packet_send();
1163 +
1164 +       gss_release_buffer(&min_status, &send_tok);
1165 +       gss_release_buffer(&min_status, &msg_tok);
1166 +
1167 +       if (gss_kex_context == NULL)
1168 +               gss_kex_context = ctxt;
1169 +       else
1170 +               ssh_gssapi_delete_ctx(&ctxt);
1171 +
1172 +       DH_free(kex->dh);
1173 +
1174 +       if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
1175 +               r = kex_send_newkeys(ssh);
1176 +       return (r);
1177 +}
1178 +#endif /* GSSAPI */
1179 diff --git a/monitor.c b/monitor.c
1180 index b3efbb0..7ac4c61 100644
1181 --- a/monitor.c
1182 +++ b/monitor.c
1183 @@ -160,6 +160,7 @@ int mm_answer_gss_setup_ctx(int, Buffer *);
1184  int mm_answer_gss_accept_ctx(int, Buffer *);
1185  int mm_answer_gss_userok(int, Buffer *);
1186  int mm_answer_gss_checkmic(int, Buffer *);
1187 +int mm_answer_gss_sign(int, Buffer *);
1188  #endif
1189  
1190  #ifdef SSH_AUDIT_EVENTS
1191 @@ -244,11 +245,17 @@ struct mon_table mon_dispatch_proto20[] = {
1192      {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
1193      {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
1194      {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
1195 +    {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
1196  #endif
1197      {0, 0, NULL}
1198  };
1199  
1200  struct mon_table mon_dispatch_postauth20[] = {
1201 +#ifdef GSSAPI
1202 +    {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
1203 +    {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
1204 +    {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
1205 +#endif
1206  #ifdef WITH_OPENSSL
1207      {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
1208  #endif
1209 @@ -363,6 +370,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
1210                 /* Permit requests for moduli and signatures */
1211                 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
1212                 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
1213 +#ifdef GSSAPI
1214 +               /* and for the GSSAPI key exchange */
1215 +               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
1216 +#endif
1217         } else {
1218                 mon_dispatch = mon_dispatch_proto15;
1219  
1220 @@ -502,6 +513,10 @@ monitor_child_postauth(struct monitor *pmonitor)
1221                 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
1222                 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
1223                 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
1224 +#ifdef GSSAPI
1225 +               /* and for the GSSAPI key exchange */
1226 +               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
1227 +#endif         
1228         } else {
1229                 mon_dispatch = mon_dispatch_postauth15;
1230                 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
1231 @@ -1927,6 +1942,13 @@ monitor_apply_keystate(struct monitor *pmonitor)
1232  # endif
1233  #endif /* WITH_OPENSSL */
1234                 kex->kex[KEX_C25519_SHA256] = kexc25519_server;
1235 +#ifdef GSSAPI
1236 +               if (options.gss_keyex) {
1237 +                       kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
1238 +                       kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
1239 +                       kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
1240 +               }
1241 +#endif
1242                 kex->load_host_public_key=&get_hostkey_public_by_type;
1243                 kex->load_host_private_key=&get_hostkey_private_by_type;
1244                 kex->host_key_index=&get_hostkey_index;
1245 @@ -2026,6 +2048,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer *m)
1246         OM_uint32 major;
1247         u_int len;
1248  
1249 +       if (!options.gss_authentication && !options.gss_keyex)
1250 +               fatal("In GSSAPI monitor when GSSAPI is disabled");
1251 +
1252         goid.elements = buffer_get_string(m, &len);
1253         goid.length = len;
1254  
1255 @@ -2053,6 +2078,9 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
1256         OM_uint32 flags = 0; /* GSI needs this */
1257         u_int len;
1258  
1259 +       if (!options.gss_authentication && !options.gss_keyex)
1260 +               fatal("In GSSAPI monitor when GSSAPI is disabled");
1261 +
1262         in.value = buffer_get_string(m, &len);
1263         in.length = len;
1264         major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
1265 @@ -2070,6 +2098,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
1266                 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
1267                 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
1268                 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
1269 +               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
1270         }
1271         return (0);
1272  }
1273 @@ -2081,6 +2110,9 @@ mm_answer_gss_checkmic(int sock, Buffer *m)
1274         OM_uint32 ret;
1275         u_int len;
1276  
1277 +       if (!options.gss_authentication && !options.gss_keyex)
1278 +               fatal("In GSSAPI monitor when GSSAPI is disabled");
1279 +
1280         gssbuf.value = buffer_get_string(m, &len);
1281         gssbuf.length = len;
1282         mic.value = buffer_get_string(m, &len);
1283 @@ -2107,6 +2139,9 @@ mm_answer_gss_userok(int sock, Buffer *m)
1284  {
1285         int authenticated;
1286  
1287 +       if (!options.gss_authentication && !options.gss_keyex)
1288 +               fatal("In GSSAPI monitor when GSSAPI is disabled");
1289 +
1290         authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
1291  
1292         buffer_clear(m);
1293 @@ -2120,5 +2155,47 @@ mm_answer_gss_userok(int sock, Buffer *m)
1294         /* Monitor loop will terminate if authenticated */
1295         return (authenticated);
1296  }
1297 +
1298 +int 
1299 +mm_answer_gss_sign(int socket, Buffer *m)
1300 +{
1301 +       gss_buffer_desc data;
1302 +       gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
1303 +       OM_uint32 major, minor;
1304 +       u_int len;
1305 +
1306 +       if (!options.gss_authentication && !options.gss_keyex)
1307 +               fatal("In GSSAPI monitor when GSSAPI is disabled");
1308 +
1309 +       data.value = buffer_get_string(m, &len);
1310 +       data.length = len;
1311 +       if (data.length != 20) 
1312 +               fatal("%s: data length incorrect: %d", __func__, 
1313 +                   (int) data.length);
1314 +
1315 +       /* Save the session ID on the first time around */
1316 +       if (session_id2_len == 0) {
1317 +               session_id2_len = data.length;
1318 +               session_id2 = xmalloc(session_id2_len);
1319 +               memcpy(session_id2, data.value, session_id2_len);
1320 +       }
1321 +       major = ssh_gssapi_sign(gsscontext, &data, &hash);
1322 +
1323 +       free(data.value);
1324 +
1325 +       buffer_clear(m);
1326 +       buffer_put_int(m, major);
1327 +       buffer_put_string(m, hash.value, hash.length);
1328 +
1329 +       mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
1330 +
1331 +       gss_release_buffer(&minor, &hash);
1332 +
1333 +       /* Turn on getpwnam permissions */
1334 +       monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
1335 +
1336 +       return (0);
1337 +}
1338 +
1339  #endif /* GSSAPI */
1340  
1341 diff --git a/monitor.h b/monitor.h
1342 index da63e7d..1be1545 100644
1343 --- a/monitor.h
1344 +++ b/monitor.h
1345 @@ -68,6 +68,9 @@ enum monitor_reqtype {
1346  #ifdef PAM_ENHANCEMENT
1347          MONITOR_REQ_AUTHMETHOD = 114,
1348  #endif        
1349 +#ifdef GSSAPI
1350 +       MONITOR_REQ_GSSSIGN = 130, MONITOR_ANS_GSSSIGN = 131,
1351 +#endif        
1352  };
1353  
1354  struct mm_master;
1355 diff --git a/monitor_wrap.c b/monitor_wrap.c
1356 index 95231a3..2b9ba06 100644
1357 --- a/monitor_wrap.c
1358 +++ b/monitor_wrap.c
1359 @@ -1103,5 +1103,28 @@ mm_ssh_gssapi_userok(char *user)
1360         debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
1361         return (authenticated);
1362  }
1363 +
1364 +OM_uint32
1365 +mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
1366 +{
1367 +       Buffer m;
1368 +       OM_uint32 major;
1369 +       u_int len;
1370 +
1371 +       buffer_init(&m);
1372 +       buffer_put_string(&m, data->value, data->length);
1373 +
1374 +       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
1375 +       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
1376 +
1377 +       major = buffer_get_int(&m);
1378 +       hash->value = buffer_get_string(&m, &len);
1379 +       hash->length = len;
1380 +
1381 +       buffer_free(&m);
1382 +
1383 +       return(major);
1384 +}
1385 +
1386  #endif /* GSSAPI */
1387  
1388 diff --git a/monitor_wrap.h b/monitor_wrap.h
1389 index de4a08f..5c9b2b7 100644
1390 --- a/monitor_wrap.h
1391 +++ b/monitor_wrap.h
1392 @@ -60,6 +60,7 @@ OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
1393     gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
1394  int mm_ssh_gssapi_userok(char *user);
1395  OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
1396 +OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
1397  #endif
1398  
1399  #ifdef USE_PAM
1400 diff --git a/readconf.c b/readconf.c
1401 index db37809..50254b6 100644
1402 --- a/readconf.c
1403 +++ b/readconf.c
1404 @@ -147,6 +147,7 @@ typedef enum {
1405         oClearAllForwardings, oNoHostAuthenticationForLocalhost,
1406         oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
1407         oAddressFamily, oGssAuthentication, oGssDelegateCreds,
1408 +       oGssKeyEx,
1409         oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
1410         oSendEnv, oControlPath, oControlMaster, oControlPersist,
1411         oHashKnownHosts,
1412 @@ -196,9 +197,11 @@ static struct {
1413  #if defined(GSSAPI)
1414         { "gssapiauthentication", oGssAuthentication },
1415         { "gssapidelegatecredentials", oGssDelegateCreds },
1416 +       { "gssapikeyexchange", oGssKeyEx },
1417  #else
1418         { "gssapiauthentication", oUnsupported },
1419         { "gssapidelegatecredentials", oUnsupported },
1420 +       { "gssapikeyexchange", oUnsupported },
1421  #endif
1422         { "fallbacktorsh", oDeprecated },
1423         { "usersh", oDeprecated },
1424 @@ -929,6 +932,10 @@ parse_time:
1425                 intptr = &options->gss_authentication;
1426                 goto parse_flag;
1427  
1428 +       case oGssKeyEx:
1429 +               intptr = &options->gss_keyex;
1430 +               goto parse_flag;
1431 +
1432         case oGssDelegateCreds:
1433                 intptr = &options->gss_deleg_creds;
1434                 goto parse_flag;
1435 @@ -1643,6 +1650,7 @@ initialize_options(Options * options)
1436         options->pubkey_authentication = -1;
1437         options->challenge_response_authentication = -1;
1438         options->gss_authentication = -1;
1439 +       options->gss_keyex = -1;
1440         options->gss_deleg_creds = -1;
1441         options->password_authentication = -1;
1442         options->kbd_interactive_authentication = -1;
1443 @@ -1782,6 +1790,12 @@ fill_default_options(Options * options)
1444  #else
1445                 options->gss_authentication = 0;
1446  #endif
1447 +       if (options->gss_keyex == -1)
1448 +#ifdef OPTION_DEFAULT_VALUE
1449 +               options->gss_keyex = 1;
1450 +#else
1451 +               options->gss_keyex = 0;
1452 +#endif
1453         if (options->gss_deleg_creds == -1)
1454                 options->gss_deleg_creds = 0;
1455         if (options->password_authentication == -1)
1456 diff --git a/readconf.h b/readconf.h
1457 index b961309..10ba93a 100644
1458 --- a/readconf.h
1459 +++ b/readconf.h
1460 @@ -45,6 +45,7 @@ typedef struct {
1461         int     challenge_response_authentication;
1462                                         /* Try S/Key or TIS, authentication. */
1463         int     gss_authentication;     /* Try GSS authentication */
1464 +       int     gss_keyex;              /* Try GSS key exchange */
1465         int     gss_deleg_creds;        /* Delegate GSS credentials */
1466         int     password_authentication;        /* Try password
1467                                                  * authentication. */
1468 diff --git a/servconf.c b/servconf.c
1469 index 1a68479..53146af 100644
1470 --- a/servconf.c
1471 +++ b/servconf.c
1472 @@ -117,6 +117,7 @@ initialize_server_options(ServerOptions *options)
1473         options->kerberos_ticket_cleanup = -1;
1474         options->kerberos_get_afs_token = -1;
1475         options->gss_authentication=-1;
1476 +       options->gss_keyex = -1;
1477         options->gss_cleanup_creds = -1;
1478         options->gss_strict_acceptor = -1;
1479         options->password_authentication = -1;
1480 @@ -300,6 +301,12 @@ fill_default_server_options(ServerOptions *options)
1481  #else
1482                 options->gss_authentication = 0;
1483  #endif
1484 +       if (options->gss_keyex == -1)
1485 +#ifdef OPTION_DEFAULT_VALUE
1486 +               options->gss_keyex = 1;
1487 +#else
1488 +               options->gss_keyex = 0;
1489 +#endif
1490         if (options->gss_cleanup_creds == -1)
1491                 options->gss_cleanup_creds = 1;
1492         if (options->gss_strict_acceptor == -1)
1493 @@ -442,6 +449,7 @@ typedef enum {
1494         sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedKeyTypes,
1495         sHostKeyAlgorithms,
1496         sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
1497 +       sGssKeyEx,
1498         sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
1499         sAcceptEnv, sPermitTunnel,
1500         sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
1501 @@ -518,6 +526,7 @@ static struct {
1502         { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
1503  #ifdef GSSAPI
1504         { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
1505 +       { "gssapikeyexchange", sGssKeyEx, SSHCFG_ALL },
1506  #ifdef USE_GSS_STORE_CRED
1507         { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
1508  #else /* USE_GSS_STORE_CRED */
1509 @@ -526,6 +535,7 @@ static struct {
1510         { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
1511  #else
1512         { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
1513 +       { "gssapikeyexchange", sUnsupported, SSHCFG_ALL },
1514         { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
1515         { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
1516  #endif
1517 @@ -1309,6 +1319,10 @@ process_server_config_line(ServerOptions *options, char *line,
1518                 intptr = &options->gss_authentication;
1519                 goto parse_flag;
1520  
1521 +       case sGssKeyEx:
1522 +               intptr = &options->gss_keyex;
1523 +               goto parse_flag;
1524 +
1525         case sGssCleanupCreds:
1526                 intptr = &options->gss_cleanup_creds;
1527                 goto parse_flag;
1528 @@ -2355,6 +2369,7 @@ dump_config(ServerOptions *o)
1529  #endif
1530  #ifdef GSSAPI
1531         dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
1532 +       dump_cfg_fmtint(sGssKeyEx, o->gss_keyex);
1533         dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
1534  #endif
1535         dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
1536 diff --git a/servconf.h b/servconf.h
1537 index 8c86b57..2175645 100644
1538 --- a/servconf.h
1539 +++ b/servconf.h
1540 @@ -122,6 +122,7 @@ typedef struct {
1541         int     kerberos_get_afs_token;         /* If true, try to get AFS token if
1542                                                  * authenticated with Kerberos. */
1543         int     gss_authentication;     /* If true, permit GSSAPI authentication */
1544 +       int     gss_keyex;              /* If true, permit GSSAPI key exchange */
1545         int     gss_cleanup_creds;      /* If true, destroy cred cache on logout */
1546         int     gss_strict_acceptor;    /* If true, restrict the GSSAPI acceptor name */
1547         int     password_authentication;        /* If true, permit password
1548 diff --git a/ssh-gss.h b/ssh-gss.h
1549 index a99d7f0..43c33f9 100644
1550 --- a/ssh-gss.h
1551 +++ b/ssh-gss.h
1552 @@ -61,6 +61,17 @@
1553  
1554  #define SSH_GSS_OIDTYPE 0x06
1555  
1556 +#define SSH2_MSG_KEXGSS_INIT                            30
1557 +#define SSH2_MSG_KEXGSS_CONTINUE                        31
1558 +#define SSH2_MSG_KEXGSS_COMPLETE                        32
1559 +#define SSH2_MSG_KEXGSS_HOSTKEY                         33
1560 +#define SSH2_MSG_KEXGSS_ERROR                           34
1561 +#define SSH2_MSG_KEXGSS_GROUPREQ                       40
1562 +#define SSH2_MSG_KEXGSS_GROUP                          41
1563 +#define KEX_GSS_GRP1_SHA1_ID                           "gss-group1-sha1-"
1564 +#define KEX_GSS_GRP14_SHA1_ID                          "gss-group14-sha1-"
1565 +#define KEX_GSS_GEX_SHA1_ID                            "gss-gex-sha1-"
1566 +
1567  typedef struct {
1568         char *filename;
1569         char *envvar;
1570 @@ -98,6 +109,7 @@ typedef struct {
1571  } Gssctxt;
1572  
1573  extern ssh_gssapi_mech *supported_mechs[];
1574 +extern Gssctxt *gss_kex_context;
1575  
1576  int  ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
1577  void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
1578 @@ -122,6 +134,11 @@ void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
1579  int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *);
1580  
1581  /* In the server */
1582 +typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *);
1583 +char *ssh_gssapi_client_mechanisms(const char *host);
1584 +char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *);
1585 +gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int);
1586 +int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *);
1587  OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
1588  int ssh_gssapi_userok(char *name);
1589  OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
1590 @@ -129,6 +146,8 @@ void ssh_gssapi_do_child(char ***, u_int *);
1591  void ssh_gssapi_cleanup_creds(void);
1592  void ssh_gssapi_storecreds(void);
1593  
1594 +char *ssh_gssapi_server_mechanisms(void);
1595 +int ssh_gssapi_oid_table_ok();
1596  #endif /* GSSAPI */
1597  
1598  #endif /* _SSH_GSS_H */
1599 diff --git a/ssh_config b/ssh_config
1600 index 03a228f..ff42df6 100644
1601 --- a/ssh_config
1602 +++ b/ssh_config
1603 @@ -26,6 +26,7 @@
1604  #   HostbasedAuthentication no
1605  #   GSSAPIAuthentication no
1606  #   GSSAPIDelegateCredentials no
1607 +#   GSSAPIKeyExchange yes
1608  #   BatchMode no
1609  #   CheckHostIP yes
1610  #   AddressFamily any
1611 diff --git a/ssh_config.4 b/ssh_config.4
1612 index 720451e..016adda 100644
1613 --- a/ssh_config.4
1614 +++ b/ssh_config.4
1615 @@ -757,6 +757,12 @@ Specifies whether user authentication based on GSSAPI is allowed.
1616  The default on Solaris is
1617  .Dq yes .
1618  Note that this option applies to protocol version 2 only.
1619 +.It Cm GSSAPIKeyExchange
1620 +Specifies whether key exchange based on GSSAPI may be used. When using
1621 +GSSAPI key exchange the server need not have a host key.
1622 +The default on Solaris is
1623 +.Dq yes .
1624 +Note that this option applies to protocol version 2 only.
1625  .It Cm GSSAPIDelegateCredentials
1626  Forward (delegate) credentials to the server.
1627  The default is
1628 diff --git a/sshconnect2.c b/sshconnect2.c
1629 index 95593b9..54ddccb 100644
1630 --- a/sshconnect2.c
1631 +++ b/sshconnect2.c
1632 @@ -164,11 +164,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
1633         struct kex *kex;
1634         int r;
1635  
1636 +#ifdef GSSAPI
1637 +       char *orig = NULL, *gss = NULL;
1638 +       char *gss_host = NULL;
1639 +#endif
1640 +
1641         xxx_host = host;
1642         xxx_hostaddr = hostaddr;
1643  
1644         myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
1645             options.kex_algorithms);
1646 +
1647 +#ifdef GSSAPI
1648 +       if (options.gss_keyex) {
1649 +               /* Add the GSSAPI mechanisms currently supported on this 
1650 +                * client to the key exchange algorithm proposal */
1651 +               orig = myproposal[PROPOSAL_KEX_ALGS];
1652 +
1653 +               gss_host = (char *)get_canonical_hostname(1);
1654 +
1655 +               gss = ssh_gssapi_client_mechanisms(gss_host);
1656 +               if (gss) {
1657 +                       debug("Offering GSSAPI proposal: %s", gss);
1658 +                       xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
1659 +                           "%s,%s", gss, orig);
1660 +               }
1661 +       }
1662 +#endif
1663 +
1664         myproposal[PROPOSAL_ENC_ALGS_CTOS] =
1665             compat_cipher_proposal(options.ciphers);
1666         myproposal[PROPOSAL_ENC_ALGS_STOC] =
1667 @@ -197,6 +220,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
1668                     order_hostkeyalgs(host, hostaddr, port));
1669         }
1670  
1671 +#ifdef GSSAPI
1672 +       /* If we've got GSSAPI algorithms, then we also support the
1673 +        * 'null' hostkey, as a last resort */
1674 +       if (options.gss_keyex && gss) {
1675 +               orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
1676 +               xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], 
1677 +                   "%s,null", orig);
1678 +               free(gss);
1679 +       }
1680 +#endif
1681 +
1682         if (options.rekey_limit || options.rekey_interval)
1683                 packet_set_rekey_limits((u_int32_t)options.rekey_limit,
1684                     (time_t)options.rekey_interval);
1685 @@ -215,9 +249,22 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
1686  # endif
1687  #endif
1688         kex->kex[KEX_C25519_SHA256] = kexc25519_client;
1689 +#ifdef GSSAPI
1690 +       if (options.gss_keyex) {
1691 +               kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
1692 +               kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
1693 +               kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
1694 +       }
1695 +#endif
1696         kex->client_version_string=client_version_string;
1697         kex->server_version_string=server_version_string;
1698         kex->verify_host_key=&verify_host_key_callback;
1699 +#ifdef GSSAPI
1700 +       if (options.gss_keyex) {
1701 +               kex->gss_deleg_creds = options.gss_deleg_creds;
1702 +               kex->gss_host = gss_host;
1703 +       }
1704 +#endif
1705  
1706         dispatch_run(DISPATCH_BLOCK, &kex->done, active_state);
1707  
1708 @@ -310,6 +357,7 @@ int input_gssapi_token(int type, u_int32_t, void *);
1709  int    input_gssapi_hash(int type, u_int32_t, void *);
1710  int    input_gssapi_error(int, u_int32_t, void *);
1711  int    input_gssapi_errtok(int, u_int32_t, void *);
1712 +int    userauth_gsskeyex(Authctxt *authctxt);
1713  #endif
1714  
1715  void   userauth(Authctxt *, char *);
1716 @@ -325,6 +373,11 @@ static char *authmethods_get(void);
1717  
1718  Authmethod authmethods[] = {
1719  #ifdef GSSAPI
1720 +       {"gssapi-keyex",
1721 +               userauth_gsskeyex,
1722 +               NULL,
1723 +               &options.gss_authentication,
1724 +               NULL},
1725         {"gssapi-with-mic",
1726                 userauth_gssapi,
1727                 NULL,
1728 @@ -649,7 +702,10 @@ userauth_gssapi(Authctxt *authctxt)
1729          * once. */
1730  
1731         if (gss_supported == NULL)
1732 -               gss_indicate_mechs(&min, &gss_supported);
1733 +               if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
1734 +                       gss_supported = NULL;
1735 +                       return 0;
1736 +               }
1737  
1738         /* Check to see if the mechanism is usable before we offer it */
1739         while (mech < gss_supported->count && !ok) {
1740 @@ -753,8 +809,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
1741  {
1742         Authctxt *authctxt = ctxt;
1743         Gssctxt *gssctxt;
1744 -       int oidlen;
1745 -       char *oidv;
1746 +       u_int oidlen;
1747 +       u_char *oidv;
1748  
1749         if (authctxt == NULL)
1750                 fatal("input_gssapi_response: no authentication context");
1751 @@ -867,6 +923,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
1752         free(lang);
1753         return 0;
1754  }
1755 +
1756 +int
1757 +userauth_gsskeyex(Authctxt *authctxt)
1758 +{
1759 +       Buffer b;
1760 +       gss_buffer_desc gssbuf;
1761 +       gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
1762 +       OM_uint32 ms;
1763 +
1764 +       static int attempt = 0;
1765 +       if (attempt++ >= 1)
1766 +               return (0);
1767 +
1768 +       if (gss_kex_context == NULL) {
1769 +               debug("No valid Key exchange context"); 
1770 +               return (0);
1771 +       }
1772 +
1773 +       ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
1774 +           "gssapi-keyex");
1775 +
1776 +       gssbuf.value = buffer_ptr(&b);
1777 +       gssbuf.length = buffer_len(&b);
1778 +
1779 +       if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
1780 +               buffer_free(&b);
1781 +               return (0);
1782 +       }
1783 +
1784 +       packet_start(SSH2_MSG_USERAUTH_REQUEST);
1785 +       packet_put_cstring(authctxt->server_user);
1786 +       packet_put_cstring(authctxt->service);
1787 +       packet_put_cstring(authctxt->method->name);
1788 +       packet_put_string(mic.value, mic.length);
1789 +       packet_send();
1790 +
1791 +       buffer_free(&b);
1792 +       gss_release_buffer(&ms, &mic);
1793 +
1794 +       return (1);
1795 +}
1796 +
1797  #endif /* GSSAPI */
1798  
1799  int
1800 diff --git a/sshd.c b/sshd.c
1801 index 87032ec..6215b2c 100644
1802 --- a/sshd.c
1803 +++ b/sshd.c
1804 @@ -1833,10 +1833,13 @@ main(int ac, char **av)
1805                 logit("Disabling protocol version 1. Could not load host key");
1806                 options.protocol &= ~SSH_PROTO_1;
1807         }
1808 +#ifndef GSSAPI
1809 +       /* The GSSAPI key exchange can run without a host key */
1810         if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
1811                 logit("Disabling protocol version 2. Could not load host key");
1812                 options.protocol &= ~SSH_PROTO_2;
1813         }
1814 +#endif
1815         if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
1816                 logit("sshd: no hostkeys available -- exiting.");
1817                 exit(1);
1818 @@ -2594,6 +2597,48 @@ do_ssh2_kex(void)
1819         myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal(
1820             list_hostkey_types());
1821  
1822 +#ifdef GSSAPI
1823 +       {
1824 +       char *orig;
1825 +       char *gss = NULL;
1826 +       char *newstr = NULL;
1827 +       orig = myproposal[PROPOSAL_KEX_ALGS];
1828 +
1829 +       /* 
1830 +        * If we don't have a host key, then there's no point advertising
1831 +        * the other key exchange algorithms
1832 +        */
1833 +
1834 +       if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
1835 +               orig = NULL;
1836 +
1837 +       if (options.gss_keyex)
1838 +               gss = ssh_gssapi_server_mechanisms();
1839 +       else
1840 +               gss = NULL;
1841 +
1842 +       if (gss && orig)
1843 +               xasprintf(&newstr, "%s,%s", gss, orig);
1844 +       else if (gss)
1845 +               newstr = gss;
1846 +       else if (orig)
1847 +               newstr = orig;
1848 +
1849 +       /* 
1850 +        * If we've got GSSAPI mechanisms, then we've got the 'null' host
1851 +        * key alg, but we can't tell people about it unless its the only
1852 +        * host key algorithm we support
1853 +        */
1854 +       if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
1855 +               myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
1856 +
1857 +       if (newstr)
1858 +               myproposal[PROPOSAL_KEX_ALGS] = newstr;
1859 +       else
1860 +               fatal("No supported key exchange algorithms");
1861 +       }
1862 +#endif
1863 +
1864         /* start key exchange */
1865         if ((r = kex_setup(active_state, myproposal)) != 0)
1866                 fatal("kex_setup: %s", ssh_err(r));
1867 @@ -2608,6 +2653,13 @@ do_ssh2_kex(void)
1868  # endif
1869  #endif
1870         kex->kex[KEX_C25519_SHA256] = kexc25519_server;
1871 +#ifdef GSSAPI
1872 +       if (options.gss_keyex) {
1873 +               kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
1874 +               kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
1875 +               kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
1876 +       }
1877 +#endif
1878         kex->server = 1;
1879         kex->client_version_string=client_version_string;
1880         kex->server_version_string=server_version_string;
1881 diff --git a/sshd_config b/sshd_config
1882 index 4d77f05..611656b 100644
1883 --- a/sshd_config
1884 +++ b/sshd_config
1885 @@ -82,8 +82,9 @@ AuthorizedKeysFile    .ssh/authorized_keys
1886  #KerberosGetAFSToken no
1887  
1888  # GSSAPI options
1889 -#GSSAPIAuthentication no
1890 +#GSSAPIAuthentication yes
1891  #GSSAPICleanupCredentials yes
1892 +#GSSAPIKeyExchange yes
1893  
1894  # Set this to 'yes' to enable PAM authentication, account processing,
1895  # and session processing. If this is enabled, PAM authentication will
1896 diff --git a/sshd_config.4 b/sshd_config.4
1897 index 03c5b52..bd70a68 100644
1898 --- a/sshd_config.4
1899 +++ b/sshd_config.4
1900 @@ -621,6 +621,12 @@ Specifies whether user authentication based on GSSAPI is allowed.
1901  The default on Solaris is
1902  .Dq yes .
1903  Note that this option applies to protocol version 2 only.
1904 +.It Cm GSSAPIKeyExchange
1905 +Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
1906 +doesn't rely on ssh keys to verify host identity.
1907 +The default on Solaris is
1908 +.Dq yes .
1909 +Note that this option applies to protocol version 2 only.
1910  .It Cm GSSAPICleanupCredentials
1911  Specifies whether to automatically destroy the user's credentials cache
1912  on logout.
1913 diff --git a/sshkey.c b/sshkey.c
1914 index 32dd8f2..afe5579 100644
1915 --- a/sshkey.c
1916 +++ b/sshkey.c
1917 @@ -112,6 +112,7 @@ static const struct keytype keytypes[] = {
1918  #  endif /* OPENSSL_HAS_NISTP521 */
1919  # endif /* OPENSSL_HAS_ECC */
1920  #endif /* WITH_OPENSSL */
1921 +       { "null", "null", KEY_NULL, 0, 0 },
1922         { NULL, NULL, -1, -1, 0 }
1923  };
1924  
1925 diff --git a/sshkey.h b/sshkey.h
1926 index c8d3cdd..47bd017 100644
1927 --- a/sshkey.h
1928 +++ b/sshkey.h
1929 @@ -62,6 +62,9 @@ enum sshkey_types {
1930         KEY_DSA_CERT,
1931         KEY_ECDSA_CERT,
1932         KEY_ED25519_CERT,
1933 +       KEY_RSA_CERT_V00,
1934 +       KEY_DSA_CERT_V00,
1935 +       KEY_NULL,
1936         KEY_UNSPEC
1937  };
1938  
1939 -- 
1940 2.5.4 (Apple Git-61)
1941