17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. *
37c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
47c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions
57c478bd9Sstevel@tonic-gate * are met:
67c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
77c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer.
87c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
97c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the
107c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution.
117c478bd9Sstevel@tonic-gate *
127c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
137c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
147c478bd9Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
157c478bd9Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
167c478bd9Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
177c478bd9Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
187c478bd9Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
197c478bd9Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
207c478bd9Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
217c478bd9Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
227c478bd9Sstevel@tonic-gate */
237c478bd9Sstevel@tonic-gate /*
24*c15e4e4bSjp161948 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
257c478bd9Sstevel@tonic-gate * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate #include "includes.h"
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate #ifdef GSSAPI
317c478bd9Sstevel@tonic-gate
327c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
337c478bd9Sstevel@tonic-gate
347c478bd9Sstevel@tonic-gate #include "ssh.h"
357c478bd9Sstevel@tonic-gate #include "ssh2.h"
367c478bd9Sstevel@tonic-gate #include "xmalloc.h"
377c478bd9Sstevel@tonic-gate #include "buffer.h"
387c478bd9Sstevel@tonic-gate #include "bufaux.h"
397c478bd9Sstevel@tonic-gate #include "packet.h"
407c478bd9Sstevel@tonic-gate #include "compat.h"
417c478bd9Sstevel@tonic-gate #include <openssl/evp.h>
427c478bd9Sstevel@tonic-gate #include "cipher.h"
437c478bd9Sstevel@tonic-gate #include "kex.h"
447c478bd9Sstevel@tonic-gate #include "log.h"
457c478bd9Sstevel@tonic-gate #include "compat.h"
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate #include <netdb.h>
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate #include "ssh-gss.h"
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate void
ssh_gssapi_client_kex_hook(Kex * kex,char ** proposal)527c478bd9Sstevel@tonic-gate ssh_gssapi_client_kex_hook(Kex *kex, char **proposal)
537c478bd9Sstevel@tonic-gate {
547c478bd9Sstevel@tonic-gate gss_OID_set mechs = GSS_C_NULL_OID_SET;
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate if (kex == NULL || kex->serverhost == NULL)
577c478bd9Sstevel@tonic-gate fatal("INTERNAL ERROR (%s)", __func__);
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate ssh_gssapi_client_mechs(kex->serverhost, &mechs);
607c478bd9Sstevel@tonic-gate ssh_gssapi_modify_kex(kex, mechs, proposal);
617c478bd9Sstevel@tonic-gate }
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate void
ssh_gssapi_client_mechs(const char * server_host,gss_OID_set * mechs)647c478bd9Sstevel@tonic-gate ssh_gssapi_client_mechs(const char *server_host, gss_OID_set *mechs)
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate gss_OID_set indicated = GSS_C_NULL_OID_SET;
677c478bd9Sstevel@tonic-gate gss_OID_set acquired, supported;
687c478bd9Sstevel@tonic-gate gss_OID mech;
697c478bd9Sstevel@tonic-gate gss_cred_id_t creds;
707c478bd9Sstevel@tonic-gate Gssctxt *ctxt = NULL;
717c478bd9Sstevel@tonic-gate gss_buffer_desc tok;
727c478bd9Sstevel@tonic-gate OM_uint32 maj, min;
737c478bd9Sstevel@tonic-gate int i;
749a8058b5Sjp161948 char *errmsg;
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate if (!mechs)
777c478bd9Sstevel@tonic-gate return;
787c478bd9Sstevel@tonic-gate *mechs = GSS_C_NULL_OID_SET;
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate maj = gss_indicate_mechs(&min, &indicated);
817c478bd9Sstevel@tonic-gate if (GSS_ERROR(maj)) {
827c478bd9Sstevel@tonic-gate debug("No GSS-API mechanisms are installed");
837c478bd9Sstevel@tonic-gate return;
847c478bd9Sstevel@tonic-gate }
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate maj = gss_create_empty_oid_set(&min, &supported);
877c478bd9Sstevel@tonic-gate if (GSS_ERROR(maj)) {
889a8058b5Sjp161948 errmsg = ssh_gssapi_last_error(NULL, &maj, &min);
899a8058b5Sjp161948 debug("Failed to allocate resources (%s) for GSS-API", errmsg);
909a8058b5Sjp161948 xfree(errmsg);
917c478bd9Sstevel@tonic-gate (void) gss_release_oid_set(&min, &indicated);
927c478bd9Sstevel@tonic-gate return;
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate maj = gss_acquire_cred(&min, GSS_C_NO_NAME, 0, indicated,
957c478bd9Sstevel@tonic-gate GSS_C_INITIATE, &creds, &acquired, NULL);
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate if (GSS_ERROR(maj)) {
989a8058b5Sjp161948 errmsg = ssh_gssapi_last_error(NULL, &maj, &min);
997c478bd9Sstevel@tonic-gate debug("Failed to acquire GSS-API credentials for any "
1009a8058b5Sjp161948 "mechanisms (%s)", errmsg);
1019a8058b5Sjp161948 xfree(errmsg);
1027c478bd9Sstevel@tonic-gate (void) gss_release_oid_set(&min, &indicated);
1037c478bd9Sstevel@tonic-gate (void) gss_release_oid_set(&min, &supported);
1047c478bd9Sstevel@tonic-gate return;
1057c478bd9Sstevel@tonic-gate }
1067c478bd9Sstevel@tonic-gate (void) gss_release_cred(&min, &creds);
1077c478bd9Sstevel@tonic-gate
1087c478bd9Sstevel@tonic-gate for (i = 0; i < acquired->count; i++) {
1097c478bd9Sstevel@tonic-gate mech = &acquired->elements[i];
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate if (ssh_gssapi_is_spnego(mech))
1127c478bd9Sstevel@tonic-gate continue;
1137c478bd9Sstevel@tonic-gate
1147c478bd9Sstevel@tonic-gate ssh_gssapi_build_ctx(&ctxt, 1, mech);
1157c478bd9Sstevel@tonic-gate if (!ctxt)
1167c478bd9Sstevel@tonic-gate continue;
1177c478bd9Sstevel@tonic-gate
1187c478bd9Sstevel@tonic-gate /*
1197c478bd9Sstevel@tonic-gate * This is useful for mechs like Kerberos, which can
1207c478bd9Sstevel@tonic-gate * detect unknown target princs here, but not for
1217c478bd9Sstevel@tonic-gate * mechs like SPKM, which cannot detect unknown princs
1227c478bd9Sstevel@tonic-gate * until context tokens are actually exchanged.
1237c478bd9Sstevel@tonic-gate *
1247c478bd9Sstevel@tonic-gate * 'Twould be useful to have a test that could save us
1257c478bd9Sstevel@tonic-gate * the bother of trying this for SPKM and the such...
1267c478bd9Sstevel@tonic-gate */
127*c15e4e4bSjp161948 maj = ssh_gssapi_init_ctx(ctxt, server_host, 0, NULL, &tok);
1287c478bd9Sstevel@tonic-gate if (GSS_ERROR(maj)) {
1299a8058b5Sjp161948 errmsg = ssh_gssapi_last_error(ctxt, NULL, NULL);
1307c478bd9Sstevel@tonic-gate debug("Skipping GSS-API mechanism %s (%s)",
1319a8058b5Sjp161948 ssh_gssapi_oid_to_name(mech), errmsg);
1329a8058b5Sjp161948 xfree(errmsg);
1337c478bd9Sstevel@tonic-gate continue;
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate (void) gss_release_buffer(&min, &tok);
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate maj = gss_add_oid_set_member(&min, mech, &supported);
1399a8058b5Sjp161948 if (GSS_ERROR(maj)) {
1409a8058b5Sjp161948 errmsg = ssh_gssapi_last_error(NULL, &maj, &min);
1417c478bd9Sstevel@tonic-gate debug("Failed to allocate resources (%s) for GSS-API",
1429a8058b5Sjp161948 errmsg);
1439a8058b5Sjp161948 xfree(errmsg);
1449a8058b5Sjp161948 }
1457c478bd9Sstevel@tonic-gate }
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate *mechs = supported;
1487c478bd9Sstevel@tonic-gate }
1497c478bd9Sstevel@tonic-gate
1507c478bd9Sstevel@tonic-gate
151*c15e4e4bSjp161948 /*
152*c15e4e4bSjp161948 * Wrapper to init_sec_context. Requires that the context contains:
153*c15e4e4bSjp161948 *
1547c478bd9Sstevel@tonic-gate * oid
1557c478bd9Sstevel@tonic-gate * server name (from ssh_gssapi_import_name)
1567c478bd9Sstevel@tonic-gate */
1577c478bd9Sstevel@tonic-gate OM_uint32
ssh_gssapi_init_ctx(Gssctxt * ctx,const char * server_host,int deleg_creds,gss_buffer_t recv_tok,gss_buffer_t send_tok)1587c478bd9Sstevel@tonic-gate ssh_gssapi_init_ctx(Gssctxt *ctx, const char *server_host, int deleg_creds,
1597c478bd9Sstevel@tonic-gate gss_buffer_t recv_tok, gss_buffer_t send_tok)
1607c478bd9Sstevel@tonic-gate {
1617c478bd9Sstevel@tonic-gate int flags = GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG;
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate debug("%s(%p, %s, %d, %p, %p)", __func__, ctx, server_host,
1647c478bd9Sstevel@tonic-gate deleg_creds, recv_tok, send_tok);
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate if (deleg_creds) {
1677c478bd9Sstevel@tonic-gate flags |= GSS_C_DELEG_FLAG;
1687c478bd9Sstevel@tonic-gate debug("Delegating GSS-API credentials");
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate
1717c478bd9Sstevel@tonic-gate /* Build target principal */
1727c478bd9Sstevel@tonic-gate if (ctx->desired_name == GSS_C_NO_NAME &&
173*c15e4e4bSjp161948 !ssh_gssapi_import_name(ctx, server_host)) {
174*c15e4e4bSjp161948 return (ctx->major);
175*c15e4e4bSjp161948 }
1767c478bd9Sstevel@tonic-gate
177*c15e4e4bSjp161948 ctx->major = gss_init_sec_context(&ctx->minor, GSS_C_NO_CREDENTIAL,
178*c15e4e4bSjp161948 &ctx->context, ctx->desired_name, ctx->desired_mech, flags,
1797c478bd9Sstevel@tonic-gate 0, /* default lifetime */
1807c478bd9Sstevel@tonic-gate NULL, /* no channel bindings */
1817c478bd9Sstevel@tonic-gate recv_tok,
1827c478bd9Sstevel@tonic-gate NULL, /* actual mech type */
183*c15e4e4bSjp161948 send_tok, &ctx->flags,
1847c478bd9Sstevel@tonic-gate NULL); /* actual lifetime */
1857c478bd9Sstevel@tonic-gate
1867c478bd9Sstevel@tonic-gate if (GSS_ERROR(ctx->major))
1877c478bd9Sstevel@tonic-gate ssh_gssapi_error(ctx, "calling GSS_Init_sec_context()");
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate return (ctx->major);
1907c478bd9Sstevel@tonic-gate }
1917c478bd9Sstevel@tonic-gate #endif /* GSSAPI */
192