Ticket #27250: openssh-5.9p1-gsskex-all-20110920.patch

File openssh-5.9p1-gsskex-all-20110920.patch, 88.4 KB (added by lassi.tuura@…, 13 years ago)

Updated patch for openssh 5.9p1

  • new file ChangeLog.gssapi

    diff --git a/ChangeLog.gssapi b/ChangeLog.gssapi
    new file mode 100644
    index 0000000..f117a33
    - +  
     120110101
     2  - Finally update for OpenSSH 5.6p1
     3  - Add GSSAPIServerIdentity option from Jim Basney
     4 
     520100308
     6  - [ Makefile.in, key.c, key.h ]
     7    Updates for OpenSSH 5.4p1
     8  - [ servconf.c ]
     9    Include GSSAPI options in the sshd -T configuration dump, and flag
     10    some older configuration options as being unsupported. Thanks to Colin
     11    Watson.
     12  -
     13
     1420100124
     15  - [ sshconnect2.c ]
     16    Adapt to deal with additional element in Authmethod structure. Thanks to
     17    Colin Watson
     18
     1920090615
     20  - [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c
     21      sshd.c ]
     22    Fix issues identified by Greg Hudson following a code review
     23        Check return value of gss_indicate_mechs
     24        Protect GSSAPI calls in monitor, so they can only be used if enabled
     25        Check return values of bignum functions in key exchange
     26        Use BN_clear_free to clear other side's DH value
     27        Make ssh_gssapi_id_kex more robust
     28        Only configure kex table pointers if GSSAPI is enabled
     29        Don't leak mechanism list, or gss mechanism list
     30        Cast data.length before printing
     31        If serverkey isn't provided, use an empty string, rather than NULL
     32
     3320090201
     34  - [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h
     35      ssh_config.5 sshconnet2.c ]
     36    Add support for the GSSAPIClientIdentity option, which allows the user
     37    to specify which GSSAPI identity to use to contact a given server
     38
     3920080404
     40  - [ gss-serv.c ]
     41    Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow
     42    been omitted from a previous version of this patch. Reported by Borislav
     43    Stoichkov
     44
     4520070317
     46  - [ gss-serv-krb5.c ]
     47    Remove C99ism, where new_ccname was being declared in the middle of a
     48    function
     49
     5020061220
     51  - [ servconf.c ]
     52    Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and
     53    documented, behaviour. Reported by Dan Watson.
     54
     5520060910
     56  - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c
     57      ssh-gss.h ]
     58    add support for gss-group14-sha1 key exchange mechanisms
     59  - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ]
     60    Add GSSAPIStrictAcceptorCheck option to allow the disabling of
     61    acceptor principal checking on multi-homed machines.
     62    <Bugzilla #928>
     63  - [ sshd_config ssh_config ]
     64    Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample
     65    configuration files
     66  - [ kexgss.c kegsss.c sshconnect2.c sshd.c ]
     67    Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf()
     68    Limit length of error messages displayed by client
     69
     7020060909
     71  - [ gss-genr.c gss-serv.c ]
     72    move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server
     73    only, where they belong
     74    <Bugzilla #1225>
     75
     7620060829
     77  - [ gss-serv-krb5.c ]
     78    Fix CCAPI credentials cache name when creating KRB5CCNAME environment
     79    variable
     80
     8120060828
     82  - [ gss-genr.c ]
     83    Avoid Heimdal context freeing problem
     84    <Fixed upstream 20060829>
     85
     8620060818
     87  - [ gss-genr.c ssh-gss.h sshconnect2.c ]
     88    Make sure that SPENGO is disabled
     89    <Bugzilla #1218 - Fixed upstream 20060818>
     90
     9120060421
     92  - [ gssgenr.c, sshconnect2.c ]
     93    a few type changes (signed versus unsigned, int versus size_t) to
     94    fix compiler errors/warnings
     95    (from jbasney AT ncsa.uiuc.edu)
     96  - [ kexgssc.c, sshconnect2.c ]
     97    fix uninitialized variable warnings
     98    (from jbasney AT ncsa.uiuc.edu)
     99  - [ gssgenr.c ]
     100    pass oid to gss_display_status (helpful when using GSSAPI mechglue)
     101    (from jbasney AT ncsa.uiuc.edu)
     102    <Bugzilla #1220 >
     103  - [ gss-serv-krb5.c ]
     104    #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H
     105    (from jbasney AT ncsa.uiuc.edu)
     106    <Fixed upstream 20060304>
     107  - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c
     108    add client-side GssapiKeyExchange option
     109    (from jbasney AT ncsa.uiuc.edu)
     110  - [ sshconnect2.c ]
     111    add support for GssapiTrustDns option for gssapi-with-mic
     112    (from jbasney AT ncsa.uiuc.edu)
     113    <gssapi-with-mic support is Bugzilla #1008>
  • Makefile.in

    diff --git a/Makefile.in b/Makefile.in
    index 77a78aa..947eec0 100644
    a b LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \ 
    7474        atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
    7575        monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
    7676        kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \
     77        kexgssc.o \
    7778        msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o jpake.o \
    7879        schnorr.o ssh-pkcs11.o
    7980
    SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ 
    9091        auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-jpake.o \
    9192        monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \
    9293        auth-krb5.o \
    93         auth2-gss.o gss-serv.o gss-serv-krb5.o \
     94        auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\
    9495        loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
    9596        sftp-server.o sftp-common.o \
    9697        roaming_common.o roaming_serv.o
  • auth-krb5.c

    diff --git a/auth-krb5.c b/auth-krb5.c
    index d019fe2..8219133 100644
    a b auth_krb5_password(Authctxt *authctxt, const char *password) 
    170170
    171171        len = strlen(authctxt->krb5_ticket_file) + 6;
    172172        authctxt->krb5_ccname = xmalloc(len);
     173#ifdef USE_CCAPI
     174        snprintf(authctxt->krb5_ccname, len, "API:%s",
     175            authctxt->krb5_ticket_file);
     176#else
    173177        snprintf(authctxt->krb5_ccname, len, "FILE:%s",
    174178            authctxt->krb5_ticket_file);
     179#endif
    175180
    176181#ifdef USE_PAM
    177182        if (options.use_pam)
    krb5_cleanup_proc(Authctxt *authctxt) 
    226231#ifndef HEIMDAL
    227232krb5_error_code
    228233ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
    229         int tmpfd, ret;
     234        int ret;
    230235        char ccname[40];
    231236        mode_t old_umask;
     237#ifdef USE_CCAPI
     238        char cctemplate[] = "API:krb5cc_%d";
     239#else
     240        char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX";
     241        int tmpfd;
     242#endif
    232243
    233244        ret = snprintf(ccname, sizeof(ccname),
    234             "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
     245            cctemplate, geteuid());
    235246        if (ret < 0 || (size_t)ret >= sizeof(ccname))
    236247                return ENOMEM;
    237248
     249#ifndef USE_CCAPI
    238250        old_umask = umask(0177);
    239251        tmpfd = mkstemp(ccname + strlen("FILE:"));
    240252        umask(old_umask);
    ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { 
    249261                return errno;
    250262        }
    251263        close(tmpfd);
     264#endif
    252265
    253266        return (krb5_cc_resolve(ctx, ccname, ccache));
    254267}
  • auth2-gss.c

    diff --git a/auth2-gss.c b/auth2-gss.c
    index 0e08d88..a192d28 100644
    a b  
    11/* $OpenBSD: auth2-gss.c,v 1.16 2007/10/29 00:52:45 dtucker Exp $ */
    22
    33/*
    4  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
     4 * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
    55 *
    66 * Redistribution and use in source and binary forms, with or without
    77 * modification, are permitted provided that the following conditions
    static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt); 
    5252static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
    5353static void input_gssapi_errtok(int, u_int32_t, void *);
    5454
     55/*
     56 * The 'gssapi_keyex' userauth mechanism.
     57 */
     58static int
     59userauth_gsskeyex(Authctxt *authctxt)
     60{
     61        int authenticated = 0;
     62        Buffer b;
     63        gss_buffer_desc mic, gssbuf;
     64        u_int len;
     65
     66        mic.value = packet_get_string(&len);
     67        mic.length = len;
     68
     69        packet_check_eom();
     70
     71        ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
     72            "gssapi-keyex");
     73
     74        gssbuf.value = buffer_ptr(&b);
     75        gssbuf.length = buffer_len(&b);
     76
     77        /* gss_kex_context is NULL with privsep, so we can't check it here */
     78        if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
     79            &gssbuf, &mic))))
     80                authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
     81                    authctxt->pw));
     82       
     83        buffer_free(&b);
     84        xfree(mic.value);
     85
     86        return (authenticated);
     87}
     88
    5589/*
    5690 * We only support those mechanisms that we know about (ie ones that we know
    5791 * how to check local user kuserok and the like)
    input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt) 
    242278
    243279        packet_check_eom();
    244280
    245         authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
     281        authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
     282            authctxt->pw));
    246283
    247284        authctxt->postponed = 0;
    248285        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
    input_gssapi_mic(int type, u_int32_t plen, void *ctxt) 
    277314        gssbuf.length = buffer_len(&b);
    278315
    279316        if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
    280                 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
     317                authenticated =
     318                    PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
    281319        else
    282320                logit("GSSAPI MIC check failed");
    283321
    input_gssapi_mic(int type, u_int32_t plen, void *ctxt) 
    292330        userauth_finish(authctxt, authenticated, "gssapi-with-mic");
    293331}
    294332
     333Authmethod method_gsskeyex = {
     334        "gssapi-keyex",
     335        userauth_gsskeyex,
     336        &options.gss_authentication
     337};
     338
    295339Authmethod method_gssapi = {
    296340        "gssapi-with-mic",
    297341        userauth_gssapi,
  • auth2.c

    diff --git a/auth2.c b/auth2.c
    index 95820f9..3c38cdd 100644
    a b extern Authmethod method_passwd; 
    6969extern Authmethod method_kbdint;
    7070extern Authmethod method_hostbased;
    7171#ifdef GSSAPI
     72extern Authmethod method_gsskeyex;
    7273extern Authmethod method_gssapi;
    7374#endif
    7475#ifdef JPAKE
    Authmethod *authmethods[] = { 
    7980        &method_none,
    8081        &method_pubkey,
    8182#ifdef GSSAPI
     83        &method_gsskeyex,
    8284        &method_gssapi,
    8385#endif
    8486#ifdef JPAKE
  • clientloop.c

    diff --git a/clientloop.c b/clientloop.c
    index f6c1444..ed19023 100644
    a b  
    111111#include "msg.h"
    112112#include "roaming.h"
    113113
     114#ifdef GSSAPI
     115#include "ssh-gss.h"
     116#endif
     117
    114118/* import options */
    115119extern Options options;
    116120
    client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) 
    14831487                /* Do channel operations unless rekeying in progress. */
    14841488                if (!rekeying) {
    14851489                        channel_after_select(readset, writeset);
     1490
     1491#ifdef GSSAPI
     1492                        if (options.gss_renewal_rekey &&
     1493                            ssh_gssapi_credentials_updated(GSS_C_NO_CONTEXT)) {
     1494                                debug("credentials updated - forcing rekey");
     1495                                need_rekeying = 1;
     1496                        }
     1497#endif
     1498
    14861499                        if (need_rekeying || packet_need_rekeying()) {
    14871500                                debug("need rekeying");
    14881501                                xxx_kex->done = 0;
  • configure.ac

    diff --git a/configure.ac b/configure.ac
    index 769e835..d7d1a98 100644
    a b  
    515515            [Use tunnel device compatibility to OpenBSD])
    516516        AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
    517517            [Prepend the address family to IP tunnel traffic])
     518        AC_MSG_CHECKING(if we have the Security Authorization Session API)
     519        AC_TRY_COMPILE([#include <Security/AuthSession.h>],
     520                [SessionCreate(0, 0);],
     521                [ac_cv_use_security_session_api="yes"
     522                 AC_DEFINE(USE_SECURITY_SESSION_API, 1,
     523                        [platform has the Security Authorization Session API])
     524                 LIBS="$LIBS -framework Security"
     525                 AC_MSG_RESULT(yes)],
     526                [ac_cv_use_security_session_api="no"
     527                 AC_MSG_RESULT(no)])
     528        AC_MSG_CHECKING(if we have an in-memory credentials cache)
     529        AC_TRY_COMPILE(
     530                [#include <Kerberos/Kerberos.h>],
     531                [cc_context_t c;
     532                 (void) cc_initialize (&c, 0, NULL, NULL);],
     533                [AC_DEFINE(USE_CCAPI, 1,
     534                        [platform uses an in-memory credentials cache])
     535                 LIBS="$LIBS -framework Security"
     536                 AC_MSG_RESULT(yes)
     537                 if test "x$ac_cv_use_security_session_api" = "xno"; then
     538                        AC_MSG_ERROR(*** Need a security framework to use the credentials cache API ***)
     539                fi],
     540                [AC_MSG_RESULT(no)]
     541        )
    518542        m4_pattern_allow([AU_IPv])
    519543        AC_CHECK_DECL([AU_IPv4], [],
    520544            AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records])
  • gss-genr.c

    diff --git a/gss-genr.c b/gss-genr.c
    index 842f385..f9b39cf 100644
    a b  
    11/* $OpenBSD: gss-genr.c,v 1.20 2009/06/22 05:39:28 dtucker Exp $ */
    22
    33/*
    4  * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
     4 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
    55 *
    66 * Redistribution and use in source and binary forms, with or without
    77 * modification, are permitted provided that the following conditions
     
    3939#include "buffer.h"
    4040#include "log.h"
    4141#include "ssh2.h"
     42#include "cipher.h"
     43#include "key.h"
     44#include "kex.h"
     45#include <openssl/evp.h>
    4246
    4347#include "ssh-gss.h"
    4448
    4549extern u_char *session_id2;
    4650extern u_int session_id2_len;
    4751
     52typedef struct {
     53        char *encoded;
     54        gss_OID oid;
     55} ssh_gss_kex_mapping;
     56
     57/*
     58 * XXX - It would be nice to find a more elegant way of handling the
     59 * XXX   passing of the key exchange context to the userauth routines
     60 */
     61
     62Gssctxt *gss_kex_context = NULL;
     63
     64static ssh_gss_kex_mapping *gss_enc2oid = NULL;
     65
     66int
     67ssh_gssapi_oid_table_ok() {
     68        return (gss_enc2oid != NULL);
     69}
     70
     71/*
     72 * Return a list of the gss-group1-sha1 mechanisms supported by this program
     73 *
     74 * We test mechanisms to ensure that we can use them, to avoid starting
     75 * a key exchange with a bad mechanism
     76 */
     77
     78char *
     79ssh_gssapi_client_mechanisms(const char *host, const char *client) {
     80        gss_OID_set gss_supported;
     81        OM_uint32 min_status;
     82
     83        if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
     84                return NULL;
     85
     86        return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
     87            host, client));
     88}
     89
     90char *
     91ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
     92    const char *host, const char *client) {
     93        Buffer buf;
     94        size_t i;
     95        int oidpos, enclen;
     96        char *mechs, *encoded;
     97        u_char digest[EVP_MAX_MD_SIZE];
     98        char deroid[2];
     99        const EVP_MD *evp_md = EVP_md5();
     100        EVP_MD_CTX md;
     101
     102        if (gss_enc2oid != NULL) {
     103                for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
     104                        xfree(gss_enc2oid[i].encoded);
     105                xfree(gss_enc2oid);
     106        }
     107
     108        gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
     109            (gss_supported->count + 1));
     110
     111        buffer_init(&buf);
     112
     113        oidpos = 0;
     114        for (i = 0; i < gss_supported->count; i++) {
     115                if (gss_supported->elements[i].length < 128 &&
     116                    (*check)(NULL, &(gss_supported->elements[i]), host, client)) {
     117
     118                        deroid[0] = SSH_GSS_OIDTYPE;
     119                        deroid[1] = gss_supported->elements[i].length;
     120
     121                        EVP_DigestInit(&md, evp_md);
     122                        EVP_DigestUpdate(&md, deroid, 2);
     123                        EVP_DigestUpdate(&md,
     124                            gss_supported->elements[i].elements,
     125                            gss_supported->elements[i].length);
     126                        EVP_DigestFinal(&md, digest, NULL);
     127
     128                        encoded = xmalloc(EVP_MD_size(evp_md) * 2);
     129                        enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
     130                            encoded, EVP_MD_size(evp_md) * 2);
     131
     132                        if (oidpos != 0)
     133                                buffer_put_char(&buf, ',');
     134
     135                        buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
     136                            sizeof(KEX_GSS_GEX_SHA1_ID) - 1);
     137                        buffer_append(&buf, encoded, enclen);
     138                        buffer_put_char(&buf, ',');
     139                        buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID,
     140                            sizeof(KEX_GSS_GRP1_SHA1_ID) - 1);
     141                        buffer_append(&buf, encoded, enclen);
     142                        buffer_put_char(&buf, ',');
     143                        buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID,
     144                            sizeof(KEX_GSS_GRP14_SHA1_ID) - 1);
     145                        buffer_append(&buf, encoded, enclen);
     146
     147                        gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
     148                        gss_enc2oid[oidpos].encoded = encoded;
     149                        oidpos++;
     150                }
     151        }
     152        gss_enc2oid[oidpos].oid = NULL;
     153        gss_enc2oid[oidpos].encoded = NULL;
     154
     155        buffer_put_char(&buf, '\0');
     156
     157        mechs = xmalloc(buffer_len(&buf));
     158        buffer_get(&buf, mechs, buffer_len(&buf));
     159        buffer_free(&buf);
     160
     161        if (strlen(mechs) == 0) {
     162                xfree(mechs);
     163                mechs = NULL;
     164        }
     165       
     166        return (mechs);
     167}
     168
     169gss_OID
     170ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
     171        int i = 0;
     172       
     173        switch (kex_type) {
     174        case KEX_GSS_GRP1_SHA1:
     175                if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID))
     176                        return GSS_C_NO_OID;
     177                name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1;
     178                break;
     179        case KEX_GSS_GRP14_SHA1:
     180                if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID))
     181                        return GSS_C_NO_OID;
     182                name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
     183                break;
     184        case KEX_GSS_GEX_SHA1:
     185                if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID))
     186                        return GSS_C_NO_OID;
     187                name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
     188                break;
     189        default:
     190                return GSS_C_NO_OID;
     191        }
     192
     193        while (gss_enc2oid[i].encoded != NULL &&
     194            strcmp(name, gss_enc2oid[i].encoded) != 0)
     195                i++;
     196
     197        if (gss_enc2oid[i].oid != NULL && ctx != NULL)
     198                ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
     199
     200        return gss_enc2oid[i].oid;
     201}
     202
    48203/* Check that the OID in a data stream matches that in the context */
    49204int
    50205ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
    ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, 
    197352        }
    198353
    199354        ctx->major = gss_init_sec_context(&ctx->minor,
    200             GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid,
     355            ctx->client_creds, &ctx->context, ctx->name, ctx->oid,
    201356            GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
    202357            0, NULL, recv_tok, NULL, send_tok, flags, NULL);
    203358
    ssh_gssapi_import_name(Gssctxt *ctx, const char *host) 
    227382}
    228383
    229384OM_uint32
     385ssh_gssapi_client_identity(Gssctxt *ctx, const char *name)
     386{
     387        gss_buffer_desc gssbuf;
     388        gss_name_t gssname;
     389        OM_uint32 status;
     390        gss_OID_set oidset;
     391
     392        gssbuf.value = (void *) name;
     393        gssbuf.length = strlen(gssbuf.value);
     394
     395        gss_create_empty_oid_set(&status, &oidset);
     396        gss_add_oid_set_member(&status, ctx->oid, &oidset);
     397
     398        ctx->major = gss_import_name(&ctx->minor, &gssbuf,
     399            GSS_C_NT_USER_NAME, &gssname);
     400
     401        if (!ctx->major)
     402                ctx->major = gss_acquire_cred(&ctx->minor,
     403                    gssname, 0, oidset, GSS_C_INITIATE,
     404                    &ctx->client_creds, NULL, NULL);
     405
     406        gss_release_name(&status, &gssname);
     407        gss_release_oid_set(&status, &oidset);
     408
     409        if (ctx->major)
     410                ssh_gssapi_error(ctx);
     411
     412        return(ctx->major);
     413}
     414
     415OM_uint32
    230416ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
    231417{
     418        if (ctx == NULL)
     419                return -1;
     420
    232421        if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
    233422            GSS_C_QOP_DEFAULT, buffer, hash)))
    234423                ssh_gssapi_error(ctx);
    ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) 
    236425        return (ctx->major);
    237426}
    238427
     428/* Priviledged when used by server */
     429OM_uint32
     430ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
     431{
     432        if (ctx == NULL)
     433                return -1;
     434
     435        ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
     436            gssbuf, gssmic, NULL);
     437
     438        return (ctx->major);
     439}
     440
    239441void
    240442ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
    241443    const char *context)
    ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, 
    249451}
    250452
    251453int
    252 ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
     454ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host,
     455    const char *client)
    253456{
    254457        gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
    255458        OM_uint32 major, minor;
    256459        gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
     460        Gssctxt *intctx = NULL;
     461
     462        if (ctx == NULL)
     463                ctx = &intctx;
    257464
    258465        /* RFC 4462 says we MUST NOT do SPNEGO */
    259466        if (oid->length == spnego_oid.length &&
    ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) 
    263470        ssh_gssapi_build_ctx(ctx);
    264471        ssh_gssapi_set_oid(*ctx, oid);
    265472        major = ssh_gssapi_import_name(*ctx, host);
     473
     474        if (!GSS_ERROR(major) && client)
     475                major = ssh_gssapi_client_identity(*ctx, client);
     476
    266477        if (!GSS_ERROR(major)) {
    267478                major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token,
    268479                    NULL);
    ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) 
    272483                            GSS_C_NO_BUFFER);
    273484        }
    274485
    275         if (GSS_ERROR(major))
     486        if (GSS_ERROR(major) || intctx != NULL)
    276487                ssh_gssapi_delete_ctx(ctx);
    277488
    278489        return (!GSS_ERROR(major));
    279490}
    280491
     492int
     493ssh_gssapi_credentials_updated(Gssctxt *ctxt) {
     494        static gss_name_t saved_name = GSS_C_NO_NAME;
     495        static OM_uint32 saved_lifetime = 0;
     496        static gss_OID saved_mech = GSS_C_NO_OID;
     497        static gss_name_t name;
     498        static OM_uint32 last_call = 0;
     499        OM_uint32 lifetime, now, major, minor;
     500        int equal;
     501        gss_cred_usage_t usage = GSS_C_INITIATE;
     502       
     503        now = time(NULL);
     504
     505        if (ctxt) {
     506                debug("Rekey has happened - updating saved versions");
     507
     508                if (saved_name != GSS_C_NO_NAME)
     509                        gss_release_name(&minor, &saved_name);
     510
     511                major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
     512                    &saved_name, &saved_lifetime, NULL, NULL);
     513
     514                if (!GSS_ERROR(major)) {
     515                        saved_mech = ctxt->oid;
     516                        saved_lifetime+= now;
     517                } else {
     518                        /* Handle the error */
     519                }
     520                return 0;
     521        }
     522
     523        if (now - last_call < 10)
     524                return 0;
     525
     526        last_call = now;
     527
     528        if (saved_mech == GSS_C_NO_OID)
     529                return 0;
     530       
     531        major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
     532            &name, &lifetime, NULL, NULL);
     533        if (major == GSS_S_CREDENTIALS_EXPIRED)
     534                return 0;
     535        else if (GSS_ERROR(major))
     536                return 0;
     537
     538        major = gss_compare_name(&minor, saved_name, name, &equal);
     539        gss_release_name(&minor, &name);
     540        if (GSS_ERROR(major))
     541                return 0;
     542
     543        if (equal && (saved_lifetime < lifetime + now - 10))
     544                return 1;
     545
     546        return 0;
     547}
     548
    281549#endif /* GSSAPI */
  • gss-serv-krb5.c

    diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
    index 5a625ac..e7170ee 100644
    a b  
    11/* $OpenBSD: gss-serv-krb5.c,v 1.7 2006/08/03 03:34:42 deraadt Exp $ */
    22
    33/*
    4  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
     4 * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
    55 *
    66 * Redistribution and use in source and binary forms, with or without
    77 * modification, are permitted provided that the following conditions
    ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) 
    120120        krb5_principal princ;
    121121        OM_uint32 maj_status, min_status;
    122122        int len;
     123        const char *new_ccname;
    123124
    124125        if (client->creds == NULL) {
    125126                debug("No credentials stored");
    ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) 
    168169                return;
    169170        }
    170171
    171         client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache));
     172        new_ccname = krb5_cc_get_name(krb_context, ccache);
     173
    172174        client->store.envvar = "KRB5CCNAME";
    173         len = strlen(client->store.filename) + 6;
    174         client->store.envval = xmalloc(len);
    175         snprintf(client->store.envval, len, "FILE:%s", client->store.filename);
     175#ifdef USE_CCAPI
     176        xasprintf(&client->store.envval, "API:%s", new_ccname);
     177        client->store.filename = NULL;
     178#else
     179        xasprintf(&client->store.envval, "FILE:%s", new_ccname);
     180        client->store.filename = xstrdup(new_ccname);
     181#endif
    176182
    177183#ifdef USE_PAM
    178184        if (options.use_pam)
    ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) 
    184190        return;
    185191}
    186192
     193int
     194ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store,
     195    ssh_gssapi_client *client)
     196{
     197        krb5_ccache ccache = NULL;
     198        krb5_principal principal = NULL;
     199        char *name = NULL;
     200        krb5_error_code problem;
     201        OM_uint32 maj_status, min_status;
     202
     203        if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) {
     204                logit("krb5_cc_resolve(): %.100s",
     205                    krb5_get_err_text(krb_context, problem));
     206                return 0;
     207        }
     208       
     209        /* Find out who the principal in this cache is */
     210        if ((problem = krb5_cc_get_principal(krb_context, ccache,
     211            &principal))) {
     212                logit("krb5_cc_get_principal(): %.100s",
     213                    krb5_get_err_text(krb_context, problem));
     214                krb5_cc_close(krb_context, ccache);
     215                return 0;
     216        }
     217
     218        if ((problem = krb5_unparse_name(krb_context, principal, &name))) {
     219                logit("krb5_unparse_name(): %.100s",
     220                    krb5_get_err_text(krb_context, problem));
     221                krb5_free_principal(krb_context, principal);
     222                krb5_cc_close(krb_context, ccache);
     223                return 0;
     224        }
     225
     226
     227        if (strcmp(name,client->exportedname.value)!=0) {
     228                debug("Name in local credentials cache differs. Not storing");
     229                krb5_free_principal(krb_context, principal);
     230                krb5_cc_close(krb_context, ccache);
     231                krb5_free_unparsed_name(krb_context, name);
     232                return 0;
     233        }
     234        krb5_free_unparsed_name(krb_context, name);
     235
     236        /* Name matches, so lets get on with it! */
     237
     238        if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) {
     239                logit("krb5_cc_initialize(): %.100s",
     240                    krb5_get_err_text(krb_context, problem));
     241                krb5_free_principal(krb_context, principal);
     242                krb5_cc_close(krb_context, ccache);
     243                return 0;
     244        }
     245
     246        krb5_free_principal(krb_context, principal);
     247
     248        if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds,
     249            ccache))) {
     250                logit("gss_krb5_copy_ccache() failed. Sorry!");
     251                krb5_cc_close(krb_context, ccache);
     252                return 0;
     253        }
     254
     255        return 1;
     256}
     257
    187258ssh_gssapi_mech gssapi_kerberos_mech = {
    188259        "toWM5Slw5Ew8Mqkay+al2g==",
    189260        "Kerberos",
    ssh_gssapi_mech gssapi_kerberos_mech = { 
    191262        NULL,
    192263        &ssh_gssapi_krb5_userok,
    193264        NULL,
    194         &ssh_gssapi_krb5_storecreds
     265        &ssh_gssapi_krb5_storecreds,
     266        &ssh_gssapi_krb5_updatecreds
    195267};
    196268
    197269#endif /* KRB5 */
  • gss-serv.c

    diff --git a/gss-serv.c b/gss-serv.c
    index 2ec7ea1..365e48d 100644
    a b  
    11/* $OpenBSD: gss-serv.c,v 1.22 2008/05/08 12:02:23 djm Exp $ */
    22
    33/*
    4  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
     4 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
    55 *
    66 * Redistribution and use in source and binary forms, with or without
    77 * modification, are permitted provided that the following conditions
     
    4545#include "channels.h"
    4646#include "session.h"
    4747#include "misc.h"
     48#include "servconf.h"
     49#include "uidswap.h"
    4850
    4951#include "ssh-gss.h"
     52#include "monitor_wrap.h"
     53
     54extern ServerOptions options;
    5055
    5156static ssh_gssapi_client gssapi_client =
    5257    { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
    53     GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}};
     58    GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME,  NULL, {NULL, NULL, NULL}, 0, 0};
    5459
    5560ssh_gssapi_mech gssapi_null_mech =
    56     { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
     61    { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
    5762
    5863#ifdef KRB5
    5964extern ssh_gssapi_mech gssapi_kerberos_mech;
    ssh_gssapi_acquire_cred(Gssctxt *ctx) 
    8186        char lname[MAXHOSTNAMELEN];
    8287        gss_OID_set oidset;
    8388
    84         gss_create_empty_oid_set(&status, &oidset);
    85         gss_add_oid_set_member(&status, ctx->oid, &oidset);
     89        if (options.gss_strict_acceptor) {
     90                gss_create_empty_oid_set(&status, &oidset);
     91                gss_add_oid_set_member(&status, ctx->oid, &oidset);
    8692
    87         if (gethostname(lname, MAXHOSTNAMELEN)) {
    88                 gss_release_oid_set(&status, &oidset);
    89                 return (-1);
    90         }
     93                if (gethostname(lname, MAXHOSTNAMELEN)) {
     94                        gss_release_oid_set(&status, &oidset);
     95                        return (-1);
     96                }
     97
     98                if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
     99                        gss_release_oid_set(&status, &oidset);
     100                        return (ctx->major);
     101                }
     102
     103                if ((ctx->major = gss_acquire_cred(&ctx->minor,
     104                    ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds,
     105                    NULL, NULL)))
     106                        ssh_gssapi_error(ctx);
    91107
    92         if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
    93108                gss_release_oid_set(&status, &oidset);
    94109                return (ctx->major);
     110        } else {
     111                ctx->name = GSS_C_NO_NAME;
     112                ctx->creds = GSS_C_NO_CREDENTIAL;
    95113        }
    96 
    97         if ((ctx->major = gss_acquire_cred(&ctx->minor,
    98             ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
    99                 ssh_gssapi_error(ctx);
    100 
    101         gss_release_oid_set(&status, &oidset);
    102         return (ctx->major);
     114        return GSS_S_COMPLETE;
    103115}
    104116
    105117/* Privileged */
    ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) 
    114126}
    115127
    116128/* Unprivileged */
     129char *
     130ssh_gssapi_server_mechanisms() {
     131        gss_OID_set     supported;
     132
     133        ssh_gssapi_supported_oids(&supported);
     134        return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
     135            NULL, NULL));
     136}
     137
     138/* Unprivileged */
     139int
     140ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data,
     141    const char *dummy) {
     142        Gssctxt *ctx = NULL;
     143        int res;
     144 
     145        res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
     146        ssh_gssapi_delete_ctx(&ctx);
     147
     148        return (res);
     149}
     150
     151/* Unprivileged */
    117152void
    118153ssh_gssapi_supported_oids(gss_OID_set *oidset)
    119154{
    ssh_gssapi_supported_oids(gss_OID_set *oidset) 
    123158        gss_OID_set supported;
    124159
    125160        gss_create_empty_oid_set(&min_status, oidset);
    126         gss_indicate_mechs(&min_status, &supported);
     161
     162        if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
     163                return;
    127164
    128165        while (supported_mechs[i]->name != NULL) {
    129166                if (GSS_ERROR(gss_test_oid_set_member(&min_status,
    OM_uint32 
    247284ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
    248285{
    249286        int i = 0;
     287        int equal = 0;
     288        gss_name_t new_name = GSS_C_NO_NAME;
     289        gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
     290
     291        if (options.gss_store_rekey && client->used && ctx->client_creds) {
     292                if (client->mech->oid.length != ctx->oid->length ||
     293                    (memcmp(client->mech->oid.elements,
     294                     ctx->oid->elements, ctx->oid->length) !=0)) {
     295                        debug("Rekeyed credentials have different mechanism");
     296                        return GSS_S_COMPLETE;
     297                }
     298
     299                if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
     300                    ctx->client_creds, ctx->oid, &new_name,
     301                    NULL, NULL, NULL))) {
     302                        ssh_gssapi_error(ctx);
     303                        return (ctx->major);
     304                }
     305
     306                ctx->major = gss_compare_name(&ctx->minor, client->name,
     307                    new_name, &equal);
    250308
    251         gss_buffer_desc ename;
     309                if (GSS_ERROR(ctx->major)) {
     310                        ssh_gssapi_error(ctx);
     311                        return (ctx->major);
     312                }
     313 
     314                if (!equal) {
     315                        debug("Rekeyed credentials have different name");
     316                        return GSS_S_COMPLETE;
     317                }
     318
     319                debug("Marking rekeyed credentials for export");
     320
     321                gss_release_name(&ctx->minor, &client->name);
     322                gss_release_cred(&ctx->minor, &client->creds);
     323                client->name = new_name;
     324                client->creds = ctx->client_creds;
     325                ctx->client_creds = GSS_C_NO_CREDENTIAL;
     326                client->updated = 1;
     327                return GSS_S_COMPLETE;
     328        }
    252329
    253330        client->mech = NULL;
    254331
    ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) 
    263340        if (client->mech == NULL)
    264341                return GSS_S_FAILURE;
    265342
     343        if (ctx->client_creds &&
     344            (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
     345             ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
     346                ssh_gssapi_error(ctx);
     347                return (ctx->major);
     348        }
     349
    266350        if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
    267351            &client->displayname, NULL))) {
    268352                ssh_gssapi_error(ctx);
    ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) 
    280364                return (ctx->major);
    281365        }
    282366
     367        gss_release_buffer(&ctx->minor, &ename);
     368
    283369        /* We can't copy this structure, so we just move the pointer to it */
    284370        client->creds = ctx->client_creds;
    285371        ctx->client_creds = GSS_C_NO_CREDENTIAL;
    ssh_gssapi_do_child(char ***envp, u_int *envsizep) 
    327413
    328414/* Privileged */
    329415int
    330 ssh_gssapi_userok(char *user)
     416ssh_gssapi_userok(char *user, struct passwd *pw)
    331417{
    332418        OM_uint32 lmin;
    333419
    ssh_gssapi_userok(char *user) 
    337423                return 0;
    338424        }
    339425        if (gssapi_client.mech && gssapi_client.mech->userok)
    340                 if ((*gssapi_client.mech->userok)(&gssapi_client, user))
     426                if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
     427                        gssapi_client.used = 1;
     428                        gssapi_client.store.owner = pw;
    341429                        return 1;
    342                 else {
     430                } else {
    343431                        /* Destroy delegated credentials if userok fails */
    344432                        gss_release_buffer(&lmin, &gssapi_client.displayname);
    345433                        gss_release_buffer(&lmin, &gssapi_client.exportedname);
    ssh_gssapi_userok(char *user) 
    352440        return (0);
    353441}
    354442
    355 /* Privileged */
    356 OM_uint32
    357 ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
     443/* These bits are only used for rekeying. The unpriviledged child is running
     444 * as the user, the monitor is root.
     445 *
     446 * In the child, we want to :
     447 *    *) Ask the monitor to store our credentials into the store we specify
     448 *    *) If it succeeds, maybe do a PAM update
     449 */
     450
     451/* Stuff for PAM */
     452
     453#ifdef USE_PAM
     454static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg,
     455    struct pam_response **resp, void *data)
    358456{
    359         ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
    360             gssbuf, gssmic, NULL);
     457        return (PAM_CONV_ERR);
     458}
     459#endif
    361460
    362         return (ctx->major);
     461void
     462ssh_gssapi_rekey_creds() {
     463        int ok;
     464        int ret;
     465#ifdef USE_PAM
     466        pam_handle_t *pamh = NULL;
     467        struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
     468        char *envstr;
     469#endif
     470
     471        if (gssapi_client.store.filename == NULL &&
     472            gssapi_client.store.envval == NULL &&
     473            gssapi_client.store.envvar == NULL)
     474                return;
     475 
     476        ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));
     477
     478        if (!ok)
     479                return;
     480
     481        debug("Rekeyed credentials stored successfully");
     482
     483        /* Actually managing to play with the ssh pam stack from here will
     484         * be next to impossible. In any case, we may want different options
     485         * for rekeying. So, use our own :)
     486         */
     487#ifdef USE_PAM 
     488        if (!use_privsep) {
     489                debug("Not even going to try and do PAM with privsep disabled");
     490                return;
     491        }
     492
     493        ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name,
     494            &pamconv, &pamh);
     495        if (ret)
     496                return;
     497
     498        xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar,
     499            gssapi_client.store.envval);
     500
     501        ret = pam_putenv(pamh, envstr);
     502        if (!ret)
     503                pam_setcred(pamh, PAM_REINITIALIZE_CRED);
     504        pam_end(pamh, PAM_SUCCESS);
     505#endif
     506}
     507
     508int
     509ssh_gssapi_update_creds(ssh_gssapi_ccache *store) {
     510        int ok = 0;
     511
     512        /* Check we've got credentials to store */
     513        if (!gssapi_client.updated)
     514                return 0;
     515
     516        gssapi_client.updated = 0;
     517
     518        temporarily_use_uid(gssapi_client.store.owner);
     519        if (gssapi_client.mech && gssapi_client.mech->updatecreds)
     520                ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client);
     521        else
     522                debug("No update function for this mechanism");
     523
     524        restore_uid();
     525
     526        return ok;
    363527}
    364528
    365529#endif
  • kex.c

    diff --git a/kex.c b/kex.c
    index c65e28f..58349fc 100644
    a b  
    5050#include "monitor.h"
    5151#include "roaming.h"
    5252
     53#ifdef GSSAPI
     54#include "ssh-gss.h"
     55#endif
     56
    5357#if OPENSSL_VERSION_NUMBER >= 0x00907000L
    5458# if defined(HAVE_EVP_SHA256)
    5559# define evp_ssh_sha256 EVP_sha256
    choose_kex(Kex *k, char *client, char *server) 
    358362                k->kex_type = KEX_ECDH_SHA2;
    359363                k->evp_md = kex_ecdh_name_to_evpmd(k->name);
    360364#endif
     365#ifdef GSSAPI
     366        } else if (strncmp(k->name, KEX_GSS_GEX_SHA1_ID,
     367            sizeof(KEX_GSS_GEX_SHA1_ID) - 1) == 0) {
     368                k->kex_type = KEX_GSS_GEX_SHA1;
     369                k->evp_md = EVP_sha1();
     370        } else if (strncmp(k->name, KEX_GSS_GRP1_SHA1_ID,
     371            sizeof(KEX_GSS_GRP1_SHA1_ID) - 1) == 0) {
     372                k->kex_type = KEX_GSS_GRP1_SHA1;
     373                k->evp_md = EVP_sha1();
     374        } else if (strncmp(k->name, KEX_GSS_GRP14_SHA1_ID,
     375            sizeof(KEX_GSS_GRP14_SHA1_ID) - 1) == 0) {
     376                k->kex_type = KEX_GSS_GRP14_SHA1;
     377                k->evp_md = EVP_sha1();
     378#endif
    361379        } else
    362380                fatal("bad kex alg %s", k->name);
    363381}
  • kex.h

    diff --git a/kex.h b/kex.h
    index 7373d3c..fa50b2c 100644
    a b enum kex_exchange { 
    7373        KEX_DH_GEX_SHA1,
    7474        KEX_DH_GEX_SHA256,
    7575        KEX_ECDH_SHA2,
     76        KEX_GSS_GRP1_SHA1,
     77        KEX_GSS_GRP14_SHA1,
     78        KEX_GSS_GEX_SHA1,
    7679        KEX_MAX
    7780};
    7881
    struct Kex { 
    129132        sig_atomic_t done;
    130133        int     flags;
    131134        const EVP_MD *evp_md;
     135#ifdef GSSAPI
     136        int     gss_deleg_creds;
     137        int     gss_trust_dns;
     138        char    *gss_host;
     139        char    *gss_client;
     140#endif
    132141        char    *client_version_string;
    133142        char    *server_version_string;
    134143        int     (*verify_host_key)(Key *);
    void kexgex_server(Kex *); 
    156165void     kexecdh_client(Kex *);
    157166void     kexecdh_server(Kex *);
    158167
     168#ifdef GSSAPI
     169void    kexgss_client(Kex *);
     170void    kexgss_server(Kex *);
     171#endif
     172
    159173void
    160174kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
    161175    BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *);
  • new file kexgssc.c

    diff --git a/kexgssc.c b/kexgssc.c
    new file mode 100644
    index 0000000..39be405
    - +  
     1/*
     2 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
     3 *
     4 * Redistribution and use in source and binary forms, with or without
     5 * modification, are permitted provided that the following conditions
     6 * are met:
     7 * 1. Redistributions of source code must retain the above copyright
     8 *    notice, this list of conditions and the following disclaimer.
     9 * 2. Redistributions in binary form must reproduce the above copyright
     10 *    notice, this list of conditions and the following disclaimer in the
     11 *    documentation and/or other materials provided with the distribution.
     12 *
     13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
     14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23 */
     24
     25#include "includes.h"
     26
     27#ifdef GSSAPI
     28
     29#include "includes.h"
     30
     31#include <openssl/crypto.h>
     32#include <openssl/bn.h>
     33
     34#include <string.h>
     35
     36#include "xmalloc.h"
     37#include "buffer.h"
     38#include "ssh2.h"
     39#include "key.h"
     40#include "cipher.h"
     41#include "kex.h"
     42#include "log.h"
     43#include "packet.h"
     44#include "dh.h"
     45
     46#include "ssh-gss.h"
     47
     48void
     49kexgss_client(Kex *kex) {
     50        gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
     51        gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr;
     52        Gssctxt *ctxt;
     53        OM_uint32 maj_status, min_status, ret_flags;
     54        u_int klen, kout, slen = 0, hashlen, strlen;
     55        DH *dh;
     56        BIGNUM *dh_server_pub = NULL;
     57        BIGNUM *shared_secret = NULL;
     58        BIGNUM *p = NULL;
     59        BIGNUM *g = NULL;       
     60        u_char *kbuf, *hash;
     61        u_char *serverhostkey = NULL;
     62        u_char *empty = "";
     63        char *msg;
     64        char *lang;
     65        int type = 0;
     66        int first = 1;
     67        int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
     68
     69        /* Initialise our GSSAPI world */       
     70        ssh_gssapi_build_ctx(&ctxt);
     71        if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type)
     72            == GSS_C_NO_OID)
     73                fatal("Couldn't identify host exchange");
     74
     75        if (ssh_gssapi_import_name(ctxt, kex->gss_host))
     76                fatal("Couldn't import hostname");
     77
     78        if (kex->gss_client &&
     79            ssh_gssapi_client_identity(ctxt, kex->gss_client))
     80                fatal("Couldn't acquire client credentials");
     81
     82        switch (kex->kex_type) {
     83        case KEX_GSS_GRP1_SHA1:
     84                dh = dh_new_group1();
     85                break;
     86        case KEX_GSS_GRP14_SHA1:
     87                dh = dh_new_group14();
     88                break;
     89        case KEX_GSS_GEX_SHA1:
     90                debug("Doing group exchange\n");
     91                nbits = dh_estimate(kex->we_need * 8);
     92                packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
     93                packet_put_int(min);
     94                packet_put_int(nbits);
     95                packet_put_int(max);
     96
     97                packet_send();
     98
     99                packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
     100
     101                if ((p = BN_new()) == NULL)
     102                        fatal("BN_new() failed");
     103                packet_get_bignum2(p);
     104                if ((g = BN_new()) == NULL)
     105                        fatal("BN_new() failed");
     106                packet_get_bignum2(g);
     107                packet_check_eom();
     108
     109                if (BN_num_bits(p) < min || BN_num_bits(p) > max)
     110                        fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
     111                            min, BN_num_bits(p), max);
     112
     113                dh = dh_new_group(g, p);
     114                break;
     115        default:
     116                fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
     117        }
     118       
     119        /* Step 1 - e is dh->pub_key */
     120        dh_gen_key(dh, kex->we_need * 8);
     121
     122        /* This is f, we initialise it now to make life easier */
     123        dh_server_pub = BN_new();
     124        if (dh_server_pub == NULL)
     125                fatal("dh_server_pub == NULL");
     126
     127        token_ptr = GSS_C_NO_BUFFER;
     128                         
     129        do {
     130                debug("Calling gss_init_sec_context");
     131               
     132                maj_status = ssh_gssapi_init_ctx(ctxt,
     133                    kex->gss_deleg_creds, token_ptr, &send_tok,
     134                    &ret_flags);
     135
     136                if (GSS_ERROR(maj_status)) {
     137                        if (send_tok.length != 0) {
     138                                packet_start(SSH2_MSG_KEXGSS_CONTINUE);
     139                                packet_put_string(send_tok.value,
     140                                    send_tok.length);
     141                        }
     142                        fatal("gss_init_context failed");
     143                }
     144
     145                /* If we've got an old receive buffer get rid of it */
     146                if (token_ptr != GSS_C_NO_BUFFER)
     147                        xfree(recv_tok.value);
     148
     149                if (maj_status == GSS_S_COMPLETE) {
     150                        /* If mutual state flag is not true, kex fails */
     151                        if (!(ret_flags & GSS_C_MUTUAL_FLAG))
     152                                fatal("Mutual authentication failed");
     153
     154                        /* If integ avail flag is not true kex fails */
     155                        if (!(ret_flags & GSS_C_INTEG_FLAG))
     156                                fatal("Integrity check failed");
     157                }
     158
     159                /*
     160                 * If we have data to send, then the last message that we
     161                 * received cannot have been a 'complete'.
     162                 */
     163                if (send_tok.length != 0) {
     164                        if (first) {
     165                                packet_start(SSH2_MSG_KEXGSS_INIT);
     166                                packet_put_string(send_tok.value,
     167                                    send_tok.length);
     168                                packet_put_bignum2(dh->pub_key);
     169                                first = 0;
     170                        } else {
     171                                packet_start(SSH2_MSG_KEXGSS_CONTINUE);
     172                                packet_put_string(send_tok.value,
     173                                    send_tok.length);
     174                        }
     175                        packet_send();
     176                        gss_release_buffer(&min_status, &send_tok);
     177
     178                        /* If we've sent them data, they should reply */
     179                        do {   
     180                                type = packet_read();
     181                                if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
     182                                        debug("Received KEXGSS_HOSTKEY");
     183                                        if (serverhostkey)
     184                                                fatal("Server host key received more than once");
     185                                        serverhostkey =
     186                                            packet_get_string(&slen);
     187                                }
     188                        } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
     189
     190                        switch (type) {
     191                        case SSH2_MSG_KEXGSS_CONTINUE:
     192                                debug("Received GSSAPI_CONTINUE");
     193                                if (maj_status == GSS_S_COMPLETE)
     194                                        fatal("GSSAPI Continue received from server when complete");
     195                                recv_tok.value = packet_get_string(&strlen);
     196                                recv_tok.length = strlen;
     197                                break;
     198                        case SSH2_MSG_KEXGSS_COMPLETE:
     199                                debug("Received GSSAPI_COMPLETE");
     200                                packet_get_bignum2(dh_server_pub);
     201                                msg_tok.value =  packet_get_string(&strlen);
     202                                msg_tok.length = strlen;
     203
     204                                /* Is there a token included? */
     205                                if (packet_get_char()) {
     206                                        recv_tok.value=
     207                                            packet_get_string(&strlen);
     208                                        recv_tok.length = strlen;
     209                                        /* If we're already complete - protocol error */
     210                                        if (maj_status == GSS_S_COMPLETE)
     211                                                packet_disconnect("Protocol error: received token when complete");
     212                                        } else {
     213                                                /* No token included */
     214                                                if (maj_status != GSS_S_COMPLETE)
     215                                                        packet_disconnect("Protocol error: did not receive final token");
     216                                }
     217                                break;
     218                        case SSH2_MSG_KEXGSS_ERROR:
     219                                debug("Received Error");
     220                                maj_status = packet_get_int();
     221                                min_status = packet_get_int();
     222                                msg = packet_get_string(NULL);
     223                                lang = packet_get_string(NULL);
     224                                fatal("GSSAPI Error: \n%.400s",msg);
     225                        default:
     226                                packet_disconnect("Protocol error: didn't expect packet type %d",
     227                                type);
     228                        }
     229                        token_ptr = &recv_tok;
     230                } else {
     231                        /* No data, and not complete */
     232                        if (maj_status != GSS_S_COMPLETE)
     233                                fatal("Not complete, and no token output");
     234                }
     235        } while (maj_status & GSS_S_CONTINUE_NEEDED);
     236
     237        /*
     238         * We _must_ have received a COMPLETE message in reply from the
     239         * server, which will have set dh_server_pub and msg_tok
     240         */
     241
     242        if (type != SSH2_MSG_KEXGSS_COMPLETE)
     243                fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
     244
     245        /* Check f in range [1, p-1] */
     246        if (!dh_pub_is_valid(dh, dh_server_pub))
     247                packet_disconnect("bad server public DH value");
     248
     249        /* compute K=f^x mod p */
     250        klen = DH_size(dh);
     251        kbuf = xmalloc(klen);
     252        kout = DH_compute_key(kbuf, dh_server_pub, dh);
     253        if (kout < 0)
     254                fatal("DH_compute_key: failed");
     255
     256        shared_secret = BN_new();
     257        if (shared_secret == NULL)
     258                fatal("kexgss_client: BN_new failed");
     259
     260        if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
     261                fatal("kexdh_client: BN_bin2bn failed");
     262
     263        memset(kbuf, 0, klen);
     264        xfree(kbuf);
     265
     266        switch (kex->kex_type) {
     267        case KEX_GSS_GRP1_SHA1:
     268        case KEX_GSS_GRP14_SHA1:
     269                kex_dh_hash( kex->client_version_string,
     270                    kex->server_version_string,
     271                    buffer_ptr(&kex->my), buffer_len(&kex->my),
     272                    buffer_ptr(&kex->peer), buffer_len(&kex->peer),
     273                    (serverhostkey ? serverhostkey : empty), slen,
     274                    dh->pub_key,        /* e */
     275                    dh_server_pub,      /* f */
     276                    shared_secret,      /* K */
     277                    &hash, &hashlen
     278                );
     279                break;
     280        case KEX_GSS_GEX_SHA1:
     281                kexgex_hash(
     282                    kex->evp_md,
     283                    kex->client_version_string,
     284                    kex->server_version_string,
     285                    buffer_ptr(&kex->my), buffer_len(&kex->my),
     286                    buffer_ptr(&kex->peer), buffer_len(&kex->peer),
     287                    (serverhostkey ? serverhostkey : empty), slen,
     288                    min, nbits, max,
     289                    dh->p, dh->g,
     290                    dh->pub_key,
     291                    dh_server_pub,
     292                    shared_secret,
     293                    &hash, &hashlen
     294                );
     295                break;
     296        default:
     297                fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
     298        }
     299
     300        gssbuf.value = hash;
     301        gssbuf.length = hashlen;
     302
     303        /* Verify that the hash matches the MIC we just got. */
     304        if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
     305                packet_disconnect("Hash's MIC didn't verify");
     306
     307        xfree(msg_tok.value);
     308
     309        DH_free(dh);
     310        if (serverhostkey)
     311                xfree(serverhostkey);
     312        BN_clear_free(dh_server_pub);
     313
     314        /* save session id */
     315        if (kex->session_id == NULL) {
     316                kex->session_id_len = hashlen;
     317                kex->session_id = xmalloc(kex->session_id_len);
     318                memcpy(kex->session_id, hash, kex->session_id_len);
     319        }
     320
     321        if (kex->gss_deleg_creds)
     322                ssh_gssapi_credentials_updated(ctxt);
     323
     324        if (gss_kex_context == NULL)
     325                gss_kex_context = ctxt;
     326        else
     327                ssh_gssapi_delete_ctx(&ctxt);
     328
     329        kex_derive_keys(kex, hash, hashlen, shared_secret);
     330        BN_clear_free(shared_secret);
     331        kex_finish(kex);
     332}
     333
     334#endif /* GSSAPI */
  • new file kexgsss.c

    diff --git a/kexgsss.c b/kexgsss.c
    new file mode 100644
    index 0000000..0c3eeaa
    - +  
     1/*
     2 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
     3 *
     4 * Redistribution and use in source and binary forms, with or without
     5 * modification, are permitted provided that the following conditions
     6 * are met:
     7 * 1. Redistributions of source code must retain the above copyright
     8 *    notice, this list of conditions and the following disclaimer.
     9 * 2. Redistributions in binary form must reproduce the above copyright
     10 *    notice, this list of conditions and the following disclaimer in the
     11 *    documentation and/or other materials provided with the distribution.
     12 *
     13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
     14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23 */
     24
     25#include "includes.h"
     26
     27#ifdef GSSAPI
     28
     29#include <string.h>
     30
     31#include <openssl/crypto.h>
     32#include <openssl/bn.h>
     33
     34#include "xmalloc.h"
     35#include "buffer.h"
     36#include "ssh2.h"
     37#include "key.h"
     38#include "cipher.h"
     39#include "kex.h"
     40#include "log.h"
     41#include "packet.h"
     42#include "dh.h"
     43#include "ssh-gss.h"
     44#include "monitor_wrap.h"
     45#include "servconf.h"
     46
     47extern ServerOptions options;
     48
     49void
     50kexgss_server(Kex *kex)
     51{
     52        OM_uint32 maj_status, min_status;
     53       
     54        /*
     55         * Some GSSAPI implementations use the input value of ret_flags (an
     56         * output variable) as a means of triggering mechanism specific
     57         * features. Initializing it to zero avoids inadvertently
     58         * activating this non-standard behaviour.
     59         */
     60
     61        OM_uint32 ret_flags = 0;
     62        gss_buffer_desc gssbuf, recv_tok, msg_tok;
     63        gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
     64        Gssctxt *ctxt = NULL;
     65        u_int slen, klen, kout, hashlen;
     66        u_char *kbuf, *hash;
     67        DH *dh;
     68        int min = -1, max = -1, nbits = -1;
     69        BIGNUM *shared_secret = NULL;
     70        BIGNUM *dh_client_pub = NULL;
     71        int type = 0;
     72        gss_OID oid;
     73        char *mechs;
     74
     75        /* Initialise GSSAPI */
     76
     77        /* If we're rekeying, privsep means that some of the private structures
     78         * in the GSSAPI code are no longer available. This kludges them back
     79         * into life
     80         */
     81        if (!ssh_gssapi_oid_table_ok())
     82                if ((mechs = ssh_gssapi_server_mechanisms()))
     83                        xfree(mechs);
     84
     85        debug2("%s: Identifying %s", __func__, kex->name);
     86        oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type);
     87        if (oid == GSS_C_NO_OID)
     88           fatal("Unknown gssapi mechanism");
     89
     90        debug2("%s: Acquiring credentials", __func__);
     91
     92        if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
     93                fatal("Unable to acquire credentials for the server");
     94
     95        switch (kex->kex_type) {
     96        case KEX_GSS_GRP1_SHA1:
     97                dh = dh_new_group1();
     98                break;
     99        case KEX_GSS_GRP14_SHA1:
     100                dh = dh_new_group14();
     101                break;
     102        case KEX_GSS_GEX_SHA1:
     103                debug("Doing group exchange");
     104                packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ);
     105                min = packet_get_int();
     106                nbits = packet_get_int();
     107                max = packet_get_int();
     108                min = MAX(DH_GRP_MIN, min);
     109                max = MIN(DH_GRP_MAX, max);
     110                packet_check_eom();
     111                if (max < min || nbits < min || max < nbits)
     112                        fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
     113                            min, nbits, max);
     114                dh = PRIVSEP(choose_dh(min, nbits, max));
     115                if (dh == NULL)
     116                        packet_disconnect("Protocol error: no matching group found");
     117
     118                packet_start(SSH2_MSG_KEXGSS_GROUP);
     119                packet_put_bignum2(dh->p);
     120                packet_put_bignum2(dh->g);
     121                packet_send();
     122
     123                packet_write_wait();
     124                break;
     125        default:
     126                fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
     127        }
     128
     129        dh_gen_key(dh, kex->we_need * 8);
     130
     131        do {
     132                debug("Wait SSH2_MSG_GSSAPI_INIT");
     133                type = packet_read();
     134                switch(type) {
     135                case SSH2_MSG_KEXGSS_INIT:
     136                        if (dh_client_pub != NULL)
     137                                fatal("Received KEXGSS_INIT after initialising");
     138                        recv_tok.value = packet_get_string(&slen);
     139                        recv_tok.length = slen;
     140
     141                        if ((dh_client_pub = BN_new()) == NULL)
     142                                fatal("dh_client_pub == NULL");
     143
     144                        packet_get_bignum2(dh_client_pub);
     145
     146                        /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
     147                        break;
     148                case SSH2_MSG_KEXGSS_CONTINUE:
     149                        recv_tok.value = packet_get_string(&slen);
     150                        recv_tok.length = slen;
     151                        break;
     152                default:
     153                        packet_disconnect(
     154                            "Protocol error: didn't expect packet type %d",
     155                            type);
     156                }
     157
     158                maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
     159                    &send_tok, &ret_flags));
     160
     161                xfree(recv_tok.value);
     162
     163                if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
     164                        fatal("Zero length token output when incomplete");
     165
     166                if (dh_client_pub == NULL)
     167                        fatal("No client public key");
     168               
     169                if (maj_status & GSS_S_CONTINUE_NEEDED) {
     170                        debug("Sending GSSAPI_CONTINUE");
     171                        packet_start(SSH2_MSG_KEXGSS_CONTINUE);
     172                        packet_put_string(send_tok.value, send_tok.length);
     173                        packet_send();
     174                        gss_release_buffer(&min_status, &send_tok);
     175                }
     176        } while (maj_status & GSS_S_CONTINUE_NEEDED);
     177
     178        if (GSS_ERROR(maj_status)) {
     179                if (send_tok.length > 0) {
     180                        packet_start(SSH2_MSG_KEXGSS_CONTINUE);
     181                        packet_put_string(send_tok.value, send_tok.length);
     182                        packet_send();
     183                }
     184                fatal("accept_ctx died");
     185        }
     186
     187        if (!(ret_flags & GSS_C_MUTUAL_FLAG))
     188                fatal("Mutual Authentication flag wasn't set");
     189
     190        if (!(ret_flags & GSS_C_INTEG_FLAG))
     191                fatal("Integrity flag wasn't set");
     192       
     193        if (!dh_pub_is_valid(dh, dh_client_pub))
     194                packet_disconnect("bad client public DH value");
     195
     196        klen = DH_size(dh);
     197        kbuf = xmalloc(klen);
     198        kout = DH_compute_key(kbuf, dh_client_pub, dh);
     199        if (kout < 0)
     200                fatal("DH_compute_key: failed");
     201
     202        shared_secret = BN_new();
     203        if (shared_secret == NULL)
     204                fatal("kexgss_server: BN_new failed");
     205
     206        if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
     207                fatal("kexgss_server: BN_bin2bn failed");
     208
     209        memset(kbuf, 0, klen);
     210        xfree(kbuf);
     211
     212        switch (kex->kex_type) {
     213        case KEX_GSS_GRP1_SHA1:
     214        case KEX_GSS_GRP14_SHA1:
     215                kex_dh_hash(
     216                    kex->client_version_string, kex->server_version_string,
     217                    buffer_ptr(&kex->peer), buffer_len(&kex->peer),
     218                    buffer_ptr(&kex->my), buffer_len(&kex->my),
     219                    NULL, 0, /* Change this if we start sending host keys */
     220                    dh_client_pub, dh->pub_key, shared_secret,
     221                    &hash, &hashlen
     222                );
     223                break;
     224        case KEX_GSS_GEX_SHA1:
     225                kexgex_hash(
     226                    kex->evp_md,
     227                    kex->client_version_string, kex->server_version_string,
     228                    buffer_ptr(&kex->peer), buffer_len(&kex->peer),
     229                    buffer_ptr(&kex->my), buffer_len(&kex->my),
     230                    NULL, 0,
     231                    min, nbits, max,
     232                    dh->p, dh->g,
     233                    dh_client_pub,
     234                    dh->pub_key,
     235                    shared_secret,
     236                    &hash, &hashlen
     237                );
     238                break;
     239        default:
     240                fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
     241        }
     242
     243        BN_clear_free(dh_client_pub);
     244
     245        if (kex->session_id == NULL) {
     246                kex->session_id_len = hashlen;
     247                kex->session_id = xmalloc(kex->session_id_len);
     248                memcpy(kex->session_id, hash, kex->session_id_len);
     249        }
     250
     251        gssbuf.value = hash;
     252        gssbuf.length = hashlen;
     253
     254        if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok))))
     255                fatal("Couldn't get MIC");
     256
     257        packet_start(SSH2_MSG_KEXGSS_COMPLETE);
     258        packet_put_bignum2(dh->pub_key);
     259        packet_put_string(msg_tok.value,msg_tok.length);
     260
     261        if (send_tok.length != 0) {
     262                packet_put_char(1); /* true */
     263                packet_put_string(send_tok.value, send_tok.length);
     264        } else {
     265                packet_put_char(0); /* false */
     266        }
     267        packet_send();
     268
     269        gss_release_buffer(&min_status, &send_tok);
     270        gss_release_buffer(&min_status, &msg_tok);
     271
     272        if (gss_kex_context == NULL)
     273                gss_kex_context = ctxt;
     274        else
     275                ssh_gssapi_delete_ctx(&ctxt);
     276
     277        DH_free(dh);
     278
     279        kex_derive_keys(kex, hash, hashlen, shared_secret);
     280        BN_clear_free(shared_secret);
     281        kex_finish(kex);
     282
     283        /* If this was a rekey, then save out any delegated credentials we
     284         * just exchanged.  */
     285        if (options.gss_store_rekey)
     286                ssh_gssapi_rekey_creds();
     287}
     288#endif /* GSSAPI */
  • key.c

    diff --git a/key.c b/key.c
    index 1defb11..6ccfd8d 100644
    a b key_ssh_name_from_type_nid(int type, int nid) 
    971971                }
    972972                break;
    973973#endif /* OPENSSL_HAS_ECC */
     974        case KEY_NULL:
     975                return "null";
    974976        }
    975977        return "ssh-unknown";
    976978}
    key_type_from_name(char *name) 
    12761278            strcmp(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com") == 0) {
    12771279                return KEY_ECDSA_CERT;
    12781280#endif
     1281        } else if (strcmp(name, "null") == 0) {
     1282                return KEY_NULL;
    12791283        }
    12801284
    12811285        debug2("key_type_from_name: unknown key type '%s'", name);
  • key.h

    diff --git a/key.h b/key.h
    index ec5ac5e..8b5c565 100644
    a b enum types { 
    4444        KEY_ECDSA_CERT,
    4545        KEY_RSA_CERT_V00,
    4646        KEY_DSA_CERT_V00,
     47        KEY_NULL,
    4748        KEY_UNSPEC
    4849};
    4950enum fp_type {
  • monitor.c

    diff --git a/monitor.c b/monitor.c
    index 29d987c..73702d1 100644
    a b int mm_answer_gss_setup_ctx(int, Buffer *); 
    172172int mm_answer_gss_accept_ctx(int, Buffer *);
    173173int mm_answer_gss_userok(int, Buffer *);
    174174int mm_answer_gss_checkmic(int, Buffer *);
     175int mm_answer_gss_sign(int, Buffer *);
     176int mm_answer_gss_updatecreds(int, Buffer *);
    175177#endif
    176178
    177179#ifdef SSH_AUDIT_EVENTS
    struct mon_table mon_dispatch_proto20[] = { 
    241243    {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
    242244    {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
    243245    {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
     246    {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
    244247#endif
    245248#ifdef JPAKE
    246249    {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata},
    struct mon_table mon_dispatch_proto20[] = { 
    253256};
    254257
    255258struct mon_table mon_dispatch_postauth20[] = {
     259#ifdef GSSAPI
     260    {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
     261    {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
     262    {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
     263    {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
     264#endif
    256265    {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
    257266    {MONITOR_REQ_SIGN, 0, mm_answer_sign},
    258267    {MONITOR_REQ_PTY, 0, mm_answer_pty},
    monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) 
    357366                /* Permit requests for moduli and signatures */
    358367                monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
    359368                monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
     369#ifdef GSSAPI
     370                /* and for the GSSAPI key exchange */
     371                monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
     372#endif
    360373        } else {
    361374                mon_dispatch = mon_dispatch_proto15;
    362375
    monitor_child_postauth(struct monitor *pmonitor) 
    443456                monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
    444457                monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
    445458                monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
     459#ifdef GSSAPI
     460                /* and for the GSSAPI key exchange */
     461                monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
     462#endif         
    446463        } else {
    447464                mon_dispatch = mon_dispatch_postauth15;
    448465                monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
    mm_get_kex(Buffer *m) 
    16921709        kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
    16931710        kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
    16941711        kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
     1712#ifdef GSSAPI
     1713        if (options.gss_keyex) {
     1714                kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
     1715                kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
     1716                kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
     1717        }
     1718#endif
    16951719        kex->server = 1;
    16961720        kex->hostkey_type = buffer_get_int(m);
    16971721        kex->kex_type = buffer_get_int(m);
    mm_answer_gss_setup_ctx(int sock, Buffer *m) 
    18981922        OM_uint32 major;
    18991923        u_int len;
    19001924
     1925        if (!options.gss_authentication && !options.gss_keyex)
     1926                fatal("In GSSAPI monitor when GSSAPI is disabled");
     1927
    19011928        goid.elements = buffer_get_string(m, &len);
    19021929        goid.length = len;
    19031930
    mm_answer_gss_accept_ctx(int sock, Buffer *m) 
    19251952        OM_uint32 flags = 0; /* GSI needs this */
    19261953        u_int len;
    19271954
     1955        if (!options.gss_authentication && !options.gss_keyex)
     1956                fatal("In GSSAPI monitor when GSSAPI is disabled");
     1957
    19281958        in.value = buffer_get_string(m, &len);
    19291959        in.length = len;
    19301960        major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
    mm_answer_gss_accept_ctx(int sock, Buffer *m) 
    19421972                monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
    19431973                monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
    19441974                monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
     1975                monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
    19451976        }
    19461977        return (0);
    19471978}
    mm_answer_gss_checkmic(int sock, Buffer *m) 
    19531984        OM_uint32 ret;
    19541985        u_int len;
    19551986
     1987        if (!options.gss_authentication && !options.gss_keyex)
     1988                fatal("In GSSAPI monitor when GSSAPI is disabled");
     1989
    19561990        gssbuf.value = buffer_get_string(m, &len);
    19571991        gssbuf.length = len;
    19581992        mic.value = buffer_get_string(m, &len);
    mm_answer_gss_userok(int sock, Buffer *m) 
    19792013{
    19802014        int authenticated;
    19812015
    1982         authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
     2016        if (!options.gss_authentication && !options.gss_keyex)
     2017                fatal("In GSSAPI monitor when GSSAPI is disabled");
     2018
     2019        authenticated = authctxt->valid &&
     2020            ssh_gssapi_userok(authctxt->user, authctxt->pw);
    19832021
    19842022        buffer_clear(m);
    19852023        buffer_put_int(m, authenticated);
    mm_answer_gss_userok(int sock, Buffer *m) 
    19922030        /* Monitor loop will terminate if authenticated */
    19932031        return (authenticated);
    19942032}
     2033
     2034int
     2035mm_answer_gss_sign(int socket, Buffer *m)
     2036{
     2037        gss_buffer_desc data;
     2038        gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
     2039        OM_uint32 major, minor;
     2040        u_int len;
     2041
     2042        if (!options.gss_authentication && !options.gss_keyex)
     2043                fatal("In GSSAPI monitor when GSSAPI is disabled");
     2044
     2045        data.value = buffer_get_string(m, &len);
     2046        data.length = len;
     2047        if (data.length != 20)
     2048                fatal("%s: data length incorrect: %d", __func__,
     2049                    (int) data.length);
     2050
     2051        /* Save the session ID on the first time around */
     2052        if (session_id2_len == 0) {
     2053                session_id2_len = data.length;
     2054                session_id2 = xmalloc(session_id2_len);
     2055                memcpy(session_id2, data.value, session_id2_len);
     2056        }
     2057        major = ssh_gssapi_sign(gsscontext, &data, &hash);
     2058
     2059        xfree(data.value);
     2060
     2061        buffer_clear(m);
     2062        buffer_put_int(m, major);
     2063        buffer_put_string(m, hash.value, hash.length);
     2064
     2065        mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
     2066
     2067        gss_release_buffer(&minor, &hash);
     2068
     2069        /* Turn on getpwnam permissions */
     2070        monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
     2071       
     2072        /* And credential updating, for when rekeying */
     2073        monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1);
     2074
     2075        return (0);
     2076}
     2077
     2078int
     2079mm_answer_gss_updatecreds(int socket, Buffer *m) {
     2080        ssh_gssapi_ccache store;
     2081        int ok;
     2082
     2083        store.filename = buffer_get_string(m, NULL);
     2084        store.envvar   = buffer_get_string(m, NULL);
     2085        store.envval   = buffer_get_string(m, NULL);
     2086
     2087        ok = ssh_gssapi_update_creds(&store);
     2088
     2089        xfree(store.filename);
     2090        xfree(store.envvar);
     2091        xfree(store.envval);
     2092
     2093        buffer_clear(m);
     2094        buffer_put_int(m, ok);
     2095
     2096        mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m);
     2097
     2098        return(0);
     2099}
     2100
    19952101#endif /* GSSAPI */
    19962102
    19972103#ifdef JPAKE
  • monitor.h

    diff --git a/monitor.h b/monitor.h
    index a8a2c0c..aa38b16 100644
    a b enum monitor_reqtype { 
    5353        MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP,
    5454        MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK,
    5555        MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC,
     56        MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN,
     57        MONITOR_REQ_GSSUPCREDS, MONITOR_ANS_GSSUPCREDS,
    5658        MONITOR_REQ_PAM_START,
    5759        MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT,
    5860        MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX,
  • monitor_wrap.c

    diff --git a/monitor_wrap.c b/monitor_wrap.c
    index 1a5dda5..20c37eb 100644
    a b mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) 
    12321232}
    12331233
    12341234int
    1235 mm_ssh_gssapi_userok(char *user)
     1235mm_ssh_gssapi_userok(char *user, struct passwd *pw)
    12361236{
    12371237        Buffer m;
    12381238        int authenticated = 0;
    mm_ssh_gssapi_userok(char *user) 
    12491249        debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
    12501250        return (authenticated);
    12511251}
     1252
     1253OM_uint32
     1254mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
     1255{
     1256        Buffer m;
     1257        OM_uint32 major;
     1258        u_int len;
     1259
     1260        buffer_init(&m);
     1261        buffer_put_string(&m, data->value, data->length);
     1262
     1263        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
     1264        mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
     1265
     1266        major = buffer_get_int(&m);
     1267        hash->value = buffer_get_string(&m, &len);
     1268        hash->length = len;
     1269
     1270        buffer_free(&m);
     1271
     1272        return(major);
     1273}
     1274
     1275int
     1276mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store)
     1277{
     1278        Buffer m;
     1279        int ok;
     1280
     1281        buffer_init(&m);
     1282
     1283        buffer_put_cstring(&m, store->filename ? store->filename : "");
     1284        buffer_put_cstring(&m, store->envvar ? store->envvar : "");
     1285        buffer_put_cstring(&m, store->envval ? store->envval : "");
     1286       
     1287        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, &m);
     1288        mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, &m);
     1289
     1290        ok = buffer_get_int(&m);
     1291
     1292        buffer_free(&m);
     1293       
     1294        return (ok);
     1295}
     1296
    12521297#endif /* GSSAPI */
    12531298
    12541299#ifdef JPAKE
  • monitor_wrap.h

    diff --git a/monitor_wrap.h b/monitor_wrap.h
    index de2d16f..432953f 100644
    a b BIGNUM *mm_auth_rsa_generate_challenge(Key *); 
    5757OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
    5858OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
    5959   gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
    60 int mm_ssh_gssapi_userok(char *user);
     60int mm_ssh_gssapi_userok(char *user, struct passwd *);
    6161OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
     62OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
     63int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
    6264#endif
    6365
    6466#ifdef USE_PAM
  • readconf.c

    diff --git a/readconf.c b/readconf.c
    index eb4a8b9..091029a 100644
    a b typedef enum { 
    129129        oClearAllForwardings, oNoHostAuthenticationForLocalhost,
    130130        oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
    131131        oAddressFamily, oGssAuthentication, oGssDelegateCreds,
     132        oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey,
     133        oGssServerIdentity,
    132134        oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
    133135        oSendEnv, oControlPath, oControlMaster, oControlPersist,
    134136        oHashKnownHosts,
    static struct { 
    169171        { "afstokenpassing", oUnsupported },
    170172#if defined(GSSAPI)
    171173        { "gssapiauthentication", oGssAuthentication },
     174        { "gssapikeyexchange", oGssKeyEx },
    172175        { "gssapidelegatecredentials", oGssDelegateCreds },
     176        { "gssapitrustdns", oGssTrustDns },
     177        { "gssapiclientidentity", oGssClientIdentity },
     178        { "gssapiserveridentity", oGssServerIdentity },
     179        { "gssapirenewalforcesrekey", oGssRenewalRekey },
    173180#else
    174181        { "gssapiauthentication", oUnsupported },
     182        { "gssapikeyexchange", oUnsupported },
    175183        { "gssapidelegatecredentials", oUnsupported },
     184        { "gssapitrustdns", oUnsupported },
     185        { "gssapiclientidentity", oUnsupported },
     186        { "gssapirenewalforcesrekey", oUnsupported },
    176187#endif
    177188        { "fallbacktorsh", oDeprecated },
    178189        { "usersh", oDeprecated },
    parse_flag: 
    479490                intptr = &options->gss_authentication;
    480491                goto parse_flag;
    481492
     493        case oGssKeyEx:
     494                intptr = &options->gss_keyex;
     495                goto parse_flag;
     496
    482497        case oGssDelegateCreds:
    483498                intptr = &options->gss_deleg_creds;
    484499                goto parse_flag;
    485500
     501        case oGssTrustDns:
     502                intptr = &options->gss_trust_dns;
     503                goto parse_flag;
     504
     505        case oGssClientIdentity:
     506                charptr = &options->gss_client_identity;
     507                goto parse_string;
     508
     509        case oGssServerIdentity:
     510                charptr = &options->gss_server_identity;
     511                goto parse_string;
     512
     513        case oGssRenewalRekey:
     514                intptr = &options->gss_renewal_rekey;
     515                goto parse_flag;
     516
    486517        case oBatchMode:
    487518                intptr = &options->batch_mode;
    488519                goto parse_flag;
    initialize_options(Options * options) 
    10921123        options->pubkey_authentication = -1;
    10931124        options->challenge_response_authentication = -1;
    10941125        options->gss_authentication = -1;
     1126        options->gss_keyex = -1;
    10951127        options->gss_deleg_creds = -1;
     1128        options->gss_trust_dns = -1;
     1129        options->gss_renewal_rekey = -1;
     1130        options->gss_client_identity = NULL;
     1131        options->gss_server_identity = NULL;
    10961132        options->password_authentication = -1;
    10971133        options->kbd_interactive_authentication = -1;
    10981134        options->kbd_interactive_devices = NULL;
    fill_default_options(Options * options) 
    11931229                options->challenge_response_authentication = 1;
    11941230        if (options->gss_authentication == -1)
    11951231                options->gss_authentication = 0;
     1232        if (options->gss_keyex == -1)
     1233                options->gss_keyex = 0;
    11961234        if (options->gss_deleg_creds == -1)
    11971235                options->gss_deleg_creds = 0;
     1236        if (options->gss_trust_dns == -1)
     1237                options->gss_trust_dns = 0;
     1238        if (options->gss_renewal_rekey == -1)
     1239                options->gss_renewal_rekey = 0;
    11981240        if (options->password_authentication == -1)
    11991241                options->password_authentication = 1;
    12001242        if (options->kbd_interactive_authentication == -1)
  • readconf.h

    diff --git a/readconf.h b/readconf.h
    index ee160df..3e54355 100644
    a b typedef struct { 
    4646        int     challenge_response_authentication;
    4747                                        /* Try S/Key or TIS, authentication. */
    4848        int     gss_authentication;     /* Try GSS authentication */
     49        int     gss_keyex;              /* Try GSS key exchange */
    4950        int     gss_deleg_creds;        /* Delegate GSS credentials */
     51        int     gss_trust_dns;          /* Trust DNS for GSS canonicalization */
     52        int     gss_renewal_rekey;      /* Credential renewal forces rekey */
     53        char    *gss_client_identity;   /* Principal to initiate GSSAPI with */
     54        char    *gss_server_identity;   /* GSSAPI target principal */
    5055        int     password_authentication;        /* Try password
    5156                                                 * authentication. */
    5257        int     kbd_interactive_authentication; /* Try keyboard-interactive auth. */
  • servconf.c

    diff --git a/servconf.c b/servconf.c
    index e2f20a3..b087726 100644
    a b initialize_server_options(ServerOptions *options) 
    9797        options->kerberos_ticket_cleanup = -1;
    9898        options->kerberos_get_afs_token = -1;
    9999        options->gss_authentication=-1;
     100        options->gss_keyex = -1;
    100101        options->gss_cleanup_creds = -1;
     102        options->gss_strict_acceptor = -1;
     103        options->gss_store_rekey = -1;
    101104        options->password_authentication = -1;
    102105        options->kbd_interactive_authentication = -1;
    103106        options->challenge_response_authentication = -1;
    fill_default_server_options(ServerOptions *options) 
    226229                options->kerberos_get_afs_token = 0;
    227230        if (options->gss_authentication == -1)
    228231                options->gss_authentication = 0;
     232        if (options->gss_keyex == -1)
     233                options->gss_keyex = 0;
    229234        if (options->gss_cleanup_creds == -1)
    230235                options->gss_cleanup_creds = 1;
     236        if (options->gss_strict_acceptor == -1)
     237                options->gss_strict_acceptor = 1;
     238        if (options->gss_store_rekey == -1)
     239                options->gss_store_rekey = 0;
    231240        if (options->password_authentication == -1)
    232241                options->password_authentication = 1;
    233242        if (options->kbd_interactive_authentication == -1)
     
    318327        sBanner, sUseDNS, sHostbasedAuthentication,
    319328        sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
    320329        sClientAliveCountMax, sAuthorizedKeysFile,
    321         sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
     330        sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
     331        sGssKeyEx, sGssStoreRekey,
     332        sAcceptEnv, sPermitTunnel,
    322333        sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
    323334        sUsePrivilegeSeparation, sAllowAgentForwarding,
    324335        sZeroKnowledgePasswordAuthentication, sHostCertificate,
    static struct { 
    386397#ifdef GSSAPI
    387398        { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
    388399        { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
     400        { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
     401        { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
     402        { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
     403        { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
    389404#else
    390405        { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
    391406        { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
     407        { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL },
     408        { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
     409        { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
     410        { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
    392411#endif
     412        { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL },
     413        { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL },
    393414        { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
    394415        { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
    395416        { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
    process_server_config_line(ServerOptions *options, char *line, 
    944965                intptr = &options->gss_authentication;
    945966                goto parse_flag;
    946967
     968        case sGssKeyEx:
     969                intptr = &options->gss_keyex;
     970                goto parse_flag;
     971
    947972        case sGssCleanupCreds:
    948973                intptr = &options->gss_cleanup_creds;
    949974                goto parse_flag;
    950975
     976        case sGssStrictAcceptor:
     977                intptr = &options->gss_strict_acceptor;
     978                goto parse_flag;
     979
     980        case sGssStoreRekey:
     981                intptr = &options->gss_store_rekey;
     982                goto parse_flag;
     983
    951984        case sPasswordAuthentication:
    952985                intptr = &options->password_authentication;
    953986                goto parse_flag;
    dump_config(ServerOptions *o) 
    17041737#endif
    17051738#ifdef GSSAPI
    17061739        dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
     1740        dump_cfg_fmtint(sGssKeyEx, o->gss_keyex);
    17071741        dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
     1742        dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor);
     1743        dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey);
    17081744#endif
    17091745#ifdef JPAKE
    17101746        dump_cfg_fmtint(sZeroKnowledgePasswordAuthentication,
  • servconf.h

    diff --git a/servconf.h b/servconf.h
    index 5a058a4..38de135 100644
    a b typedef struct { 
    9797        int     kerberos_get_afs_token;         /* If true, try to get AFS token if
    9898                                                 * authenticated with Kerberos. */
    9999        int     gss_authentication;     /* If true, permit GSSAPI authentication */
     100        int     gss_keyex;              /* If true, permit GSSAPI key exchange */
    100101        int     gss_cleanup_creds;      /* If true, destroy cred cache on logout */
     102        int     gss_strict_acceptor;    /* If true, restrict the GSSAPI acceptor name */
     103        int     gss_store_rekey;
    101104        int     password_authentication;        /* If true, permit password
    102105                                                 * authentication. */
    103106        int     kbd_interactive_authentication; /* If true, permit */
  • ssh-gss.h

    diff --git a/ssh-gss.h b/ssh-gss.h
    index c29a1b7..31d5a08 100644
    a b  
    11/* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 djm Exp $ */
    22/*
    3  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
     3 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
    44 *
    55 * Redistribution and use in source and binary forms, with or without
    66 * modification, are permitted provided that the following conditions
     
    6060
    6161#define SSH_GSS_OIDTYPE 0x06
    6262
     63#define SSH2_MSG_KEXGSS_INIT                            30
     64#define SSH2_MSG_KEXGSS_CONTINUE                        31
     65#define SSH2_MSG_KEXGSS_COMPLETE                        32
     66#define SSH2_MSG_KEXGSS_HOSTKEY                         33
     67#define SSH2_MSG_KEXGSS_ERROR                           34
     68#define SSH2_MSG_KEXGSS_GROUPREQ                        40
     69#define SSH2_MSG_KEXGSS_GROUP                           41
     70#define KEX_GSS_GRP1_SHA1_ID                            "gss-group1-sha1-"
     71#define KEX_GSS_GRP14_SHA1_ID                           "gss-group14-sha1-"
     72#define KEX_GSS_GEX_SHA1_ID                             "gss-gex-sha1-"
     73
    6374typedef struct {
    6475        char *filename;
    6576        char *envvar;
    6677        char *envval;
     78        struct passwd *owner;
    6779        void *data;
    6880} ssh_gssapi_ccache;
    6981
    typedef struct { 
    7183        gss_buffer_desc displayname;
    7284        gss_buffer_desc exportedname;
    7385        gss_cred_id_t creds;
     86        gss_name_t name;
    7487        struct ssh_gssapi_mech_struct *mech;
    7588        ssh_gssapi_ccache store;
     89        int used;
     90        int updated;
    7691} ssh_gssapi_client;
    7792
    7893typedef struct ssh_gssapi_mech_struct {
    typedef struct ssh_gssapi_mech_struct { 
    8398        int (*userok) (ssh_gssapi_client *, char *);
    8499        int (*localname) (ssh_gssapi_client *, char **);
    85100        void (*storecreds) (ssh_gssapi_client *);
     101        int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *);
    86102} ssh_gssapi_mech;
    87103
    88104typedef struct {
    typedef struct { 
    93109        gss_OID         oid; /* client */
    94110        gss_cred_id_t   creds; /* server */
    95111        gss_name_t      client; /* server */
    96         gss_cred_id_t   client_creds; /* server */
     112        gss_cred_id_t   client_creds; /* both */
    97113} Gssctxt;
    98114
    99115extern ssh_gssapi_mech *supported_mechs[];
     116extern Gssctxt *gss_kex_context;
    100117
    101118int  ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
    102119void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
    void ssh_gssapi_build_ctx(Gssctxt **); 
    116133void ssh_gssapi_delete_ctx(Gssctxt **);
    117134OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
    118135void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
    119 int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *);
     136int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *);
     137OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *);
     138int ssh_gssapi_credentials_updated(Gssctxt *);
    120139
    121140/* In the server */
     141typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *,
     142    const char *);
     143char *ssh_gssapi_client_mechanisms(const char *, const char *);
     144char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *,
     145    const char *);
     146gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int);
     147int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *,
     148    const char *);
    122149OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
    123 int ssh_gssapi_userok(char *name);
     150int ssh_gssapi_userok(char *name, struct passwd *);
    124151OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
    125152void ssh_gssapi_do_child(char ***, u_int *);
    126153void ssh_gssapi_cleanup_creds(void);
    127154void ssh_gssapi_storecreds(void);
    128155
     156char *ssh_gssapi_server_mechanisms(void);
     157int ssh_gssapi_oid_table_ok();
     158
     159int ssh_gssapi_update_creds(ssh_gssapi_ccache *store);
    129160#endif /* GSSAPI */
    130161
    131162#endif /* _SSH_GSS_H */
  • ssh_config

    diff --git a/ssh_config b/ssh_config
    index 1893674..2c06ba7 100644
    a b  
    2626#   HostbasedAuthentication no
    2727#   GSSAPIAuthentication no
    2828#   GSSAPIDelegateCredentials no
     29#   GSSAPIKeyExchange no
     30#   GSSAPITrustDNS no
    2931#   BatchMode no
    3032#   CheckHostIP yes
    3133#   AddressFamily any
  • ssh_config.5

    diff --git a/ssh_config.5 b/ssh_config.5
    index 50bcae8..269d394 100644
    a b Specifies whether user authentication based on GSSAPI is allowed. 
    508508The default is
    509509.Dq no .
    510510Note that this option applies to protocol version 2 only.
     511.It Cm GSSAPIKeyExchange
     512Specifies whether key exchange based on GSSAPI may be used. When using
     513GSSAPI key exchange the server need not have a host key.
     514The default is
     515.Dq no .
     516Note that this option applies to protocol version 2 only.
     517.It Cm GSSAPIClientIdentity
     518If set, specifies the GSSAPI client identity that ssh should use when
     519connecting to the server. The default is unset, which means that the default
     520identity will be used.
     521.It Cm GSSAPIServerIdentity
     522If set, specifies the GSSAPI server identity that ssh should expect when
     523connecting to the server. The default is unset, which means that the
     524expected GSSAPI server identity will be determined from the target
     525hostname.
    511526.It Cm GSSAPIDelegateCredentials
    512527Forward (delegate) credentials to the server.
    513528The default is
    514529.Dq no .
    515 Note that this option applies to protocol version 2 only.
     530Note that this option applies to protocol version 2 connections using GSSAPI.
     531.It Cm GSSAPIRenewalForcesRekey
     532If set to
     533.Dq yes
     534then renewal of the client's GSSAPI credentials will force the rekeying of the
     535ssh connection. With a compatible server, this can delegate the renewed
     536credentials to a session on the server.
     537The default is
     538.Dq no .
     539.It Cm GSSAPITrustDns
     540Set to
     541.Dq yes to indicate that the DNS is trusted to securely canonicalize
     542the name of the host being connected to. If
     543.Dq no, the hostname entered on the
     544command line will be passed untouched to the GSSAPI library.
     545The default is
     546.Dq no .
     547This option only applies to protocol version 2 connections using GSSAPI.
    516548.It Cm HashKnownHosts
    517549Indicates that
    518550.Xr ssh 1
  • sshconnect2.c

    diff --git a/sshconnect2.c b/sshconnect2.c
    index 3cb9b10..aaf02ec 100644
    a b ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) 
    159159{
    160160        Kex *kex;
    161161
     162#ifdef GSSAPI
     163        char *orig = NULL, *gss = NULL;
     164        char *gss_host = NULL;
     165#endif
     166
    162167        xxx_host = host;
    163168        xxx_hostaddr = hostaddr;
    164169
     170#ifdef GSSAPI
     171        if (options.gss_keyex) {
     172                /* Add the GSSAPI mechanisms currently supported on this
     173                 * client to the key exchange algorithm proposal */
     174                orig = myproposal[PROPOSAL_KEX_ALGS];
     175
     176                if (options.gss_trust_dns)
     177                        gss_host = (char *)get_canonical_hostname(1);
     178                else
     179                        gss_host = host;
     180
     181                gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity);
     182                if (gss) {
     183                        debug("Offering GSSAPI proposal: %s", gss);
     184                        xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
     185                            "%s,%s", gss, orig);
     186                }
     187        }
     188#endif
     189
    165190        if (options.ciphers == (char *)-1) {
    166191                logit("No valid ciphers for protocol version 2 given, using defaults.");
    167192                options.ciphers = NULL;
    ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) 
    196221        if (options.kex_algorithms != NULL)
    197222                myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
    198223
     224#ifdef GSSAPI
     225        /* If we've got GSSAPI algorithms, then we also support the
     226         * 'null' hostkey, as a last resort */
     227        if (options.gss_keyex && gss) {
     228                orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
     229                xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
     230                    "%s,null", orig);
     231                xfree(gss);
     232        }
     233#endif
     234
    199235        if (options.rekey_limit)
    200236                packet_set_rekey_limit((u_int32_t)options.rekey_limit);
    201237
    ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) 
    206242        kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
    207243        kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
    208244        kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
     245#ifdef GSSAPI
     246        if (options.gss_keyex) {
     247                kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
     248                kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
     249                kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
     250        }
     251#endif
    209252        kex->client_version_string=client_version_string;
    210253        kex->server_version_string=server_version_string;
    211254        kex->verify_host_key=&verify_host_key_callback;
    212255
     256#ifdef GSSAPI
     257        if (options.gss_keyex) {
     258                kex->gss_deleg_creds = options.gss_deleg_creds;
     259                kex->gss_trust_dns = options.gss_trust_dns;
     260                kex->gss_client = options.gss_client_identity;
     261                if (options.gss_server_identity) {
     262                        kex->gss_host = options.gss_server_identity;
     263                } else {
     264                        kex->gss_host = gss_host;
     265        }
     266        }
     267#endif
     268
    213269        xxx_kex = kex;
    214270
    215271        dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
    void input_gssapi_token(int type, u_int32_t, void *); 
    304360void    input_gssapi_hash(int type, u_int32_t, void *);
    305361void    input_gssapi_error(int, u_int32_t, void *);
    306362void    input_gssapi_errtok(int, u_int32_t, void *);
     363int     userauth_gsskeyex(Authctxt *authctxt);
    307364#endif
    308365
    309366void    userauth(Authctxt *, char *);
    static char *authmethods_get(void); 
    319376
    320377Authmethod authmethods[] = {
    321378#ifdef GSSAPI
     379        {"gssapi-keyex",
     380                userauth_gsskeyex,
     381                NULL,
     382                &options.gss_authentication,
     383                NULL},
    322384        {"gssapi-with-mic",
    323385                userauth_gssapi,
    324386                NULL,
    userauth_gssapi(Authctxt *authctxt) 
    625687        static u_int mech = 0;
    626688        OM_uint32 min;
    627689        int ok = 0;
     690        const char *gss_host;
     691
     692        if (options.gss_server_identity)
     693                gss_host = options.gss_server_identity;
     694        else if (options.gss_trust_dns)
     695                gss_host = get_canonical_hostname(1);
     696        else
     697                gss_host = authctxt->host;
    628698
    629699        /* Try one GSSAPI method at a time, rather than sending them all at
    630700         * once. */
    631701
    632702        if (gss_supported == NULL)
    633                 gss_indicate_mechs(&min, &gss_supported);
     703                if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
     704                        gss_supported = NULL;
     705                        return 0;
     706                }
    634707
    635708        /* Check to see if the mechanism is usable before we offer it */
    636709        while (mech < gss_supported->count && !ok) {
    637710                /* My DER encoding requires length<128 */
    638711                if (gss_supported->elements[mech].length < 128 &&
    639712                    ssh_gssapi_check_mechanism(&gssctxt,
    640                     &gss_supported->elements[mech], authctxt->host)) {
     713                    &gss_supported->elements[mech], gss_host,
     714                    options.gss_client_identity)) {
    641715                        ok = 1; /* Mechanism works */
    642716                } else {
    643717                        mech++;
    input_gssapi_response(int type, u_int32_t plen, void *ctxt) 
    734808{
    735809        Authctxt *authctxt = ctxt;
    736810        Gssctxt *gssctxt;
    737         int oidlen;
    738         char *oidv;
     811        u_int oidlen;
     812        u_char *oidv;
    739813
    740814        if (authctxt == NULL)
    741815                fatal("input_gssapi_response: no authentication context");
    input_gssapi_error(int type, u_int32_t plen, void *ctxt) 
    845919        xfree(msg);
    846920        xfree(lang);
    847921}
     922
     923int
     924userauth_gsskeyex(Authctxt *authctxt)
     925{
     926        Buffer b;
     927        gss_buffer_desc gssbuf;
     928        gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
     929        OM_uint32 ms;
     930
     931        static int attempt = 0;
     932        if (attempt++ >= 1)
     933                return (0);
     934
     935        if (gss_kex_context == NULL) {
     936                debug("No valid Key exchange context");
     937                return (0);
     938        }
     939
     940        ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
     941            "gssapi-keyex");
     942
     943        gssbuf.value = buffer_ptr(&b);
     944        gssbuf.length = buffer_len(&b);
     945
     946        if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
     947                buffer_free(&b);
     948                return (0);
     949        }
     950
     951        packet_start(SSH2_MSG_USERAUTH_REQUEST);
     952        packet_put_cstring(authctxt->server_user);
     953        packet_put_cstring(authctxt->service);
     954        packet_put_cstring(authctxt->method->name);
     955        packet_put_string(mic.value, mic.length);
     956        packet_send();
     957
     958        buffer_free(&b);
     959        gss_release_buffer(&ms, &mic);
     960
     961        return (1);
     962}
     963
    848964#endif /* GSSAPI */
    849965
    850966int
  • sshd.c

    diff --git a/sshd.c b/sshd.c
    index cb45cec..1136c63 100644
    a b  
    120120#include "roaming.h"
    121121#include "version.h"
    122122
     123#ifdef USE_SECURITY_SESSION_API
     124#include <Security/AuthSession.h>
     125#endif
     126
    123127#ifdef LIBWRAP
    124128#include <tcpd.h>
    125129#include <syslog.h>
    main(int ac, char **av) 
    15901594                logit("Disabling protocol version 1. Could not load host key");
    15911595                options.protocol &= ~SSH_PROTO_1;
    15921596        }
     1597#ifndef GSSAPI
     1598        /* The GSSAPI key exchange can run without a host key */
    15931599        if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
    15941600                logit("Disabling protocol version 2. Could not load host key");
    15951601                options.protocol &= ~SSH_PROTO_2;
    15961602        }
     1603#endif
    15971604        if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
    15981605                logit("sshd: no hostkeys available -- exiting.");
    15991606                exit(1);
    main(int ac, char **av) 
    19221929        /* Log the connection. */
    19231930        verbose("Connection from %.500s port %d", remote_ip, remote_port);
    19241931
     1932#ifdef USE_SECURITY_SESSION_API
     1933        /*
     1934         * Create a new security session for use by the new user login if
     1935         * the current session is the root session or we are not launched
     1936         * by inetd (eg: debugging mode or server mode).  We do not
     1937         * necessarily need to create a session if we are launched from
     1938         * inetd because Panther xinetd will create a session for us.
     1939         *
     1940         * The only case where this logic will fail is if there is an
     1941         * inetd running in a non-root session which is not creating
     1942         * new sessions for us.  Then all the users will end up in the
     1943         * same session (bad).
     1944         *
     1945         * When the client exits, the session will be destroyed for us
     1946         * automatically.
     1947         *
     1948         * We must create the session before any credentials are stored
     1949         * (including AFS pags, which happens a few lines below).
     1950         */
     1951        {
     1952                OSStatus err = 0;
     1953                SecuritySessionId sid = 0;
     1954                SessionAttributeBits sattrs = 0;
     1955
     1956                err = SessionGetInfo(callerSecuritySession, &sid, &sattrs);
     1957                if (err)
     1958                        error("SessionGetInfo() failed with error %.8X",
     1959                            (unsigned) err);
     1960                else
     1961                        debug("Current Session ID is %.8X / Session Attributes are %.8X",
     1962                            (unsigned) sid, (unsigned) sattrs);
     1963
     1964                if (inetd_flag && !(sattrs & sessionIsRoot))
     1965                        debug("Running in inetd mode in a non-root session... "
     1966                            "assuming inetd created the session for us.");
     1967                else {
     1968                        debug("Creating new security session...");
     1969                        err = SessionCreate(0, sessionHasTTY | sessionIsRemote);
     1970                        if (err)
     1971                                error("SessionCreate() failed with error %.8X",
     1972                                    (unsigned) err);
     1973
     1974                        err = SessionGetInfo(callerSecuritySession, &sid,
     1975                            &sattrs);
     1976                        if (err)
     1977                                error("SessionGetInfo() failed with error %.8X",
     1978                                    (unsigned) err);
     1979                        else
     1980                                debug("New Session ID is %.8X / Session Attributes are %.8X",
     1981                                    (unsigned) sid, (unsigned) sattrs);
     1982                }
     1983        }
     1984#endif
     1985
    19251986        /*
    19261987         * We don't want to listen forever unless the other side
    19271988         * successfully authenticates itself.  So we set up an alarm which is
    do_ssh2_kex(void) 
    23032364
    23042365        myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
    23052366
     2367#ifdef GSSAPI
     2368        {
     2369        char *orig;
     2370        char *gss = NULL;
     2371        char *newstr = NULL;
     2372        orig = myproposal[PROPOSAL_KEX_ALGS];
     2373
     2374        /*
     2375         * If we don't have a host key, then there's no point advertising
     2376         * the other key exchange algorithms
     2377         */
     2378
     2379        if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
     2380                orig = NULL;
     2381
     2382        if (options.gss_keyex)
     2383                gss = ssh_gssapi_server_mechanisms();
     2384        else
     2385                gss = NULL;
     2386
     2387        if (gss && orig)
     2388                xasprintf(&newstr, "%s,%s", gss, orig);
     2389        else if (gss)
     2390                newstr = gss;
     2391        else if (orig)
     2392                newstr = orig;
     2393
     2394        /*
     2395         * If we've got GSSAPI mechanisms, then we've got the 'null' host
     2396         * key alg, but we can't tell people about it unless its the only
     2397         * host key algorithm we support
     2398         */
     2399        if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
     2400                myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
     2401
     2402        if (newstr)
     2403                myproposal[PROPOSAL_KEX_ALGS] = newstr;
     2404        else
     2405                fatal("No supported key exchange algorithms");
     2406        }
     2407#endif
     2408
    23062409        /* start key exchange */
    23072410        kex = kex_setup(myproposal);
    23082411        kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
    do_ssh2_kex(void) 
    23102413        kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
    23112414        kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
    23122415        kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
     2416#ifdef GSSAPI
     2417        if (options.gss_keyex) {
     2418                kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
     2419                kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
     2420                kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
     2421        }
     2422#endif
    23132423        kex->server = 1;
    23142424        kex->client_version_string=client_version_string;
    23152425        kex->server_version_string=server_version_string;
  • sshd_config

    diff --git a/sshd_config b/sshd_config
    index 4534841..3576260 100644
    a b  
    7272# GSSAPI options
    7373#GSSAPIAuthentication no
    7474#GSSAPICleanupCredentials yes
     75#GSSAPIStrictAcceptorCheck yes
     76#GSSAPIKeyExchange no
    7577
    7678# Set this to 'yes' to enable PAM authentication, account processing,
    7779# and session processing. If this is enabled, PAM authentication will
  • sshd_config.5

    diff --git a/sshd_config.5 b/sshd_config.5
    index c3d6df3..449afb3 100644
    a b Specifies whether user authentication based on GSSAPI is allowed. 
    423423The default is
    424424.Dq no .
    425425Note that this option applies to protocol version 2 only.
     426.It Cm GSSAPIKeyExchange
     427Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
     428doesn't rely on ssh keys to verify host identity.
     429The default is
     430.Dq no .
     431Note that this option applies to protocol version 2 only.
    426432.It Cm GSSAPICleanupCredentials
    427433Specifies whether to automatically destroy the user's credentials cache
    428434on logout.
    429435The default is
    430436.Dq yes .
    431437Note that this option applies to protocol version 2 only.
     438.It Cm GSSAPIStrictAcceptorCheck
     439Determines whether to be strict about the identity of the GSSAPI acceptor
     440a client authenticates against. If
     441.Dq yes
     442then the client must authenticate against the
     443.Pa host
     444service on the current hostname. If
     445.Dq no
     446then the client may authenticate against any service key stored in the
     447machine's default store. This facility is provided to assist with operation
     448on multi homed machines.
     449The default is
     450.Dq yes .
     451Note that this option applies only to protocol version 2 GSSAPI connections,
     452and setting it to
     453.Dq no
     454may only work with recent Kerberos GSSAPI libraries.
     455.It Cm GSSAPIStoreCredentialsOnRekey
     456Controls whether the user's GSSAPI credentials should be updated following a
     457successful connection rekeying. This option can be used to accepted renewed
     458or updated credentials from a compatible client. The default is
     459.Dq no .
    432460.It Cm HostbasedAuthentication
    433461Specifies whether rhosts or /etc/hosts.equiv authentication together
    434462with successful public key client host authentication is allowed