xref: /openssh-portable/gss-genr.c (revision 39be3dc2)
1*39be3dc2Sdjm@openbsd.org /* $OpenBSD: gss-genr.c,v 1.28 2021/01/27 10:05:28 djm Exp $ */
20efd155cSDarren Tucker 
30efd155cSDarren Tucker /*
4b1e128f7SDarren Tucker  * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
50efd155cSDarren Tucker  *
60efd155cSDarren Tucker  * Redistribution and use in source and binary forms, with or without
70efd155cSDarren Tucker  * modification, are permitted provided that the following conditions
80efd155cSDarren Tucker  * are met:
90efd155cSDarren Tucker  * 1. Redistributions of source code must retain the above copyright
100efd155cSDarren Tucker  *    notice, this list of conditions and the following disclaimer.
110efd155cSDarren Tucker  * 2. Redistributions in binary form must reproduce the above copyright
120efd155cSDarren Tucker  *    notice, this list of conditions and the following disclaimer in the
130efd155cSDarren Tucker  *    documentation and/or other materials provided with the distribution.
140efd155cSDarren Tucker  *
150efd155cSDarren Tucker  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
160efd155cSDarren Tucker  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
170efd155cSDarren Tucker  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
180efd155cSDarren Tucker  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
190efd155cSDarren Tucker  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
200efd155cSDarren Tucker  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
210efd155cSDarren Tucker  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
220efd155cSDarren Tucker  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
230efd155cSDarren Tucker  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
240efd155cSDarren Tucker  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
250efd155cSDarren Tucker  */
260efd155cSDarren Tucker 
270efd155cSDarren Tucker #include "includes.h"
280efd155cSDarren Tucker 
290efd155cSDarren Tucker #ifdef GSSAPI
300efd155cSDarren Tucker 
31d7834353SDamien Miller #include <sys/types.h>
328dbffe79SDamien Miller 
33087266ecSderaadt@openbsd.org #include <limits.h>
34d7834353SDamien Miller #include <stdarg.h>
35e3476ed0SDamien Miller #include <string.h>
36aa72196aSDarren Tucker #include <signal.h>
37b8fe89c4SDamien Miller #include <unistd.h>
38e3476ed0SDamien Miller 
390efd155cSDarren Tucker #include "xmalloc.h"
40b8d9214dSmarkus@openbsd.org #include "ssherr.h"
41b8d9214dSmarkus@openbsd.org #include "sshbuf.h"
420efd155cSDarren Tucker #include "log.h"
430425d401SDamien Miller #include "ssh2.h"
440efd155cSDarren Tucker 
450efd155cSDarren Tucker #include "ssh-gss.h"
460efd155cSDarren Tucker 
470f3958c1Sdjm@openbsd.org /* sshbuf_get for gss_buffer_desc */
480f3958c1Sdjm@openbsd.org int
ssh_gssapi_get_buffer_desc(struct sshbuf * b,gss_buffer_desc * g)490f3958c1Sdjm@openbsd.org ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g)
500f3958c1Sdjm@openbsd.org {
510f3958c1Sdjm@openbsd.org 	int r;
520f3958c1Sdjm@openbsd.org 	u_char *p;
530f3958c1Sdjm@openbsd.org 	size_t len;
540f3958c1Sdjm@openbsd.org 
550f3958c1Sdjm@openbsd.org 	if ((r = sshbuf_get_string(b, &p, &len)) != 0)
560f3958c1Sdjm@openbsd.org 		return r;
570f3958c1Sdjm@openbsd.org 	g->value = p;
580f3958c1Sdjm@openbsd.org 	g->length = len;
590f3958c1Sdjm@openbsd.org 	return 0;
600f3958c1Sdjm@openbsd.org }
610f3958c1Sdjm@openbsd.org 
620efd155cSDarren Tucker /* Check that the OID in a data stream matches that in the context */
630efd155cSDarren Tucker int
ssh_gssapi_check_oid(Gssctxt * ctx,void * data,size_t len)640efd155cSDarren Tucker ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
650efd155cSDarren Tucker {
660efd155cSDarren Tucker 	return (ctx != NULL && ctx->oid != GSS_C_NO_OID &&
670efd155cSDarren Tucker 	    ctx->oid->length == len &&
680efd155cSDarren Tucker 	    memcmp(ctx->oid->elements, data, len) == 0);
690efd155cSDarren Tucker }
700efd155cSDarren Tucker 
710efd155cSDarren Tucker /* Set the contexts OID from a data stream */
720efd155cSDarren Tucker void
ssh_gssapi_set_oid_data(Gssctxt * ctx,void * data,size_t len)730efd155cSDarren Tucker ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len)
740efd155cSDarren Tucker {
750efd155cSDarren Tucker 	if (ctx->oid != GSS_C_NO_OID) {
76a627d42eSDarren Tucker 		free(ctx->oid->elements);
77a627d42eSDarren Tucker 		free(ctx->oid);
780efd155cSDarren Tucker 	}
796c81fee6SDamien Miller 	ctx->oid = xcalloc(1, sizeof(gss_OID_desc));
800efd155cSDarren Tucker 	ctx->oid->length = len;
810efd155cSDarren Tucker 	ctx->oid->elements = xmalloc(len);
820efd155cSDarren Tucker 	memcpy(ctx->oid->elements, data, len);
830efd155cSDarren Tucker }
840efd155cSDarren Tucker 
850efd155cSDarren Tucker /* Set the contexts OID */
860efd155cSDarren Tucker void
ssh_gssapi_set_oid(Gssctxt * ctx,gss_OID oid)870efd155cSDarren Tucker ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid)
880efd155cSDarren Tucker {
890efd155cSDarren Tucker 	ssh_gssapi_set_oid_data(ctx, oid->elements, oid->length);
900efd155cSDarren Tucker }
910efd155cSDarren Tucker 
920efd155cSDarren Tucker /* All this effort to report an error ... */
930efd155cSDarren Tucker void
ssh_gssapi_error(Gssctxt * ctxt)940efd155cSDarren Tucker ssh_gssapi_error(Gssctxt *ctxt)
950efd155cSDarren Tucker {
96a66cf68dSDamien Miller 	char *s;
97a66cf68dSDamien Miller 
98a66cf68dSDamien Miller 	s = ssh_gssapi_last_error(ctxt, NULL, NULL);
99a66cf68dSDamien Miller 	debug("%s", s);
100a627d42eSDarren Tucker 	free(s);
1010efd155cSDarren Tucker }
1020efd155cSDarren Tucker 
1030efd155cSDarren Tucker char *
ssh_gssapi_last_error(Gssctxt * ctxt,OM_uint32 * major_status,OM_uint32 * minor_status)1040dc1bef1SDamien Miller ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *major_status,
1050dc1bef1SDamien Miller     OM_uint32 *minor_status)
1060efd155cSDarren Tucker {
1070efd155cSDarren Tucker 	OM_uint32 lmin;
1080efd155cSDarren Tucker 	gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
1090efd155cSDarren Tucker 	OM_uint32 ctx;
110b8d9214dSmarkus@openbsd.org 	struct sshbuf *b;
1110efd155cSDarren Tucker 	char *ret;
112b8d9214dSmarkus@openbsd.org 	int r;
1130efd155cSDarren Tucker 
114b8d9214dSmarkus@openbsd.org 	if ((b = sshbuf_new()) == NULL)
115816036f1Sdjm@openbsd.org 		fatal_f("sshbuf_new failed");
1160efd155cSDarren Tucker 
1170efd155cSDarren Tucker 	if (major_status != NULL)
1180efd155cSDarren Tucker 		*major_status = ctxt->major;
1190efd155cSDarren Tucker 	if (minor_status != NULL)
1200efd155cSDarren Tucker 		*minor_status = ctxt->minor;
1210efd155cSDarren Tucker 
1220efd155cSDarren Tucker 	ctx = 0;
1230efd155cSDarren Tucker 	/* The GSSAPI error */
1240efd155cSDarren Tucker 	do {
1250efd155cSDarren Tucker 		gss_display_status(&lmin, ctxt->major,
126b1e128f7SDarren Tucker 		    GSS_C_GSS_CODE, ctxt->oid, &ctx, &msg);
1270efd155cSDarren Tucker 
128b8d9214dSmarkus@openbsd.org 		if ((r = sshbuf_put(b, msg.value, msg.length)) != 0 ||
129b8d9214dSmarkus@openbsd.org 		    (r = sshbuf_put_u8(b, '\n')) != 0)
130816036f1Sdjm@openbsd.org 			fatal_fr(r, "assemble GSS_CODE");
1310efd155cSDarren Tucker 
1320efd155cSDarren Tucker 		gss_release_buffer(&lmin, &msg);
1330efd155cSDarren Tucker 	} while (ctx != 0);
1340efd155cSDarren Tucker 
1350efd155cSDarren Tucker 	/* The mechanism specific error */
1360efd155cSDarren Tucker 	do {
1370efd155cSDarren Tucker 		gss_display_status(&lmin, ctxt->minor,
138b1e128f7SDarren Tucker 		    GSS_C_MECH_CODE, ctxt->oid, &ctx, &msg);
1390efd155cSDarren Tucker 
140b8d9214dSmarkus@openbsd.org 		if ((r = sshbuf_put(b, msg.value, msg.length)) != 0 ||
141b8d9214dSmarkus@openbsd.org 		    (r = sshbuf_put_u8(b, '\n')) != 0)
142816036f1Sdjm@openbsd.org 			fatal_fr(r, "assemble MECH_CODE");
1430efd155cSDarren Tucker 
1440efd155cSDarren Tucker 		gss_release_buffer(&lmin, &msg);
1450efd155cSDarren Tucker 	} while (ctx != 0);
1460efd155cSDarren Tucker 
147b8d9214dSmarkus@openbsd.org 	if ((r = sshbuf_put_u8(b, '\n')) != 0)
148816036f1Sdjm@openbsd.org 		fatal_fr(r, "assemble newline");
149b8d9214dSmarkus@openbsd.org 	ret = xstrdup((const char *)sshbuf_ptr(b));
150b8d9214dSmarkus@openbsd.org 	sshbuf_free(b);
1510efd155cSDarren Tucker 	return (ret);
1520efd155cSDarren Tucker }
1530efd155cSDarren Tucker 
1540efd155cSDarren Tucker /*
1550efd155cSDarren Tucker  * Initialise our GSSAPI context. We use this opaque structure to contain all
1560efd155cSDarren Tucker  * of the data which both the client and server need to persist across
1570efd155cSDarren Tucker  * {accept,init}_sec_context calls, so that when we do it from the userauth
1580efd155cSDarren Tucker  * stuff life is a little easier
1590efd155cSDarren Tucker  */
1600efd155cSDarren Tucker void
ssh_gssapi_build_ctx(Gssctxt ** ctx)1610efd155cSDarren Tucker ssh_gssapi_build_ctx(Gssctxt **ctx)
1620efd155cSDarren Tucker {
16307d86becSDamien Miller 	*ctx = xcalloc(1, sizeof (Gssctxt));
1640efd155cSDarren Tucker 	(*ctx)->context = GSS_C_NO_CONTEXT;
1650efd155cSDarren Tucker 	(*ctx)->name = GSS_C_NO_NAME;
1660efd155cSDarren Tucker 	(*ctx)->oid = GSS_C_NO_OID;
1670efd155cSDarren Tucker 	(*ctx)->creds = GSS_C_NO_CREDENTIAL;
1680efd155cSDarren Tucker 	(*ctx)->client = GSS_C_NO_NAME;
1690efd155cSDarren Tucker 	(*ctx)->client_creds = GSS_C_NO_CREDENTIAL;
1700efd155cSDarren Tucker }
1710efd155cSDarren Tucker 
1720efd155cSDarren Tucker /* Delete our context, providing it has been built correctly */
1730efd155cSDarren Tucker void
ssh_gssapi_delete_ctx(Gssctxt ** ctx)1740efd155cSDarren Tucker ssh_gssapi_delete_ctx(Gssctxt **ctx)
1750efd155cSDarren Tucker {
1760efd155cSDarren Tucker 	OM_uint32 ms;
1770efd155cSDarren Tucker 
1780efd155cSDarren Tucker 	if ((*ctx) == NULL)
1790efd155cSDarren Tucker 		return;
1800efd155cSDarren Tucker 	if ((*ctx)->context != GSS_C_NO_CONTEXT)
1810efd155cSDarren Tucker 		gss_delete_sec_context(&ms, &(*ctx)->context, GSS_C_NO_BUFFER);
1820efd155cSDarren Tucker 	if ((*ctx)->name != GSS_C_NO_NAME)
1830efd155cSDarren Tucker 		gss_release_name(&ms, &(*ctx)->name);
1840efd155cSDarren Tucker 	if ((*ctx)->oid != GSS_C_NO_OID) {
185a627d42eSDarren Tucker 		free((*ctx)->oid->elements);
186a627d42eSDarren Tucker 		free((*ctx)->oid);
1870efd155cSDarren Tucker 		(*ctx)->oid = GSS_C_NO_OID;
1880efd155cSDarren Tucker 	}
1890efd155cSDarren Tucker 	if ((*ctx)->creds != GSS_C_NO_CREDENTIAL)
1900efd155cSDarren Tucker 		gss_release_cred(&ms, &(*ctx)->creds);
1910efd155cSDarren Tucker 	if ((*ctx)->client != GSS_C_NO_NAME)
1920efd155cSDarren Tucker 		gss_release_name(&ms, &(*ctx)->client);
1930efd155cSDarren Tucker 	if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL)
1940efd155cSDarren Tucker 		gss_release_cred(&ms, &(*ctx)->client_creds);
1950efd155cSDarren Tucker 
196a627d42eSDarren Tucker 	free(*ctx);
1970efd155cSDarren Tucker 	*ctx = NULL;
1980efd155cSDarren Tucker }
1990efd155cSDarren Tucker 
2000efd155cSDarren Tucker /*
2010efd155cSDarren Tucker  * Wrapper to init_sec_context
2020efd155cSDarren Tucker  * Requires that the context contains:
2030efd155cSDarren Tucker  *	oid
2040efd155cSDarren Tucker  *	server name (from ssh_gssapi_import_name)
2050efd155cSDarren Tucker  */
2060efd155cSDarren Tucker OM_uint32
ssh_gssapi_init_ctx(Gssctxt * ctx,int deleg_creds,gss_buffer_desc * recv_tok,gss_buffer_desc * send_tok,OM_uint32 * flags)2070efd155cSDarren Tucker ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
2080efd155cSDarren Tucker     gss_buffer_desc* send_tok, OM_uint32 *flags)
2090efd155cSDarren Tucker {
2100efd155cSDarren Tucker 	int deleg_flag = 0;
2110efd155cSDarren Tucker 
2120efd155cSDarren Tucker 	if (deleg_creds) {
2130efd155cSDarren Tucker 		deleg_flag = GSS_C_DELEG_FLAG;
2140efd155cSDarren Tucker 		debug("Delegating credentials");
2150efd155cSDarren Tucker 	}
2160efd155cSDarren Tucker 
2170efd155cSDarren Tucker 	ctx->major = gss_init_sec_context(&ctx->minor,
2180efd155cSDarren Tucker 	    GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid,
2190efd155cSDarren Tucker 	    GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
2200efd155cSDarren Tucker 	    0, NULL, recv_tok, NULL, send_tok, flags, NULL);
2210efd155cSDarren Tucker 
2220efd155cSDarren Tucker 	if (GSS_ERROR(ctx->major))
2230efd155cSDarren Tucker 		ssh_gssapi_error(ctx);
2240efd155cSDarren Tucker 
2250efd155cSDarren Tucker 	return (ctx->major);
2260efd155cSDarren Tucker }
2270efd155cSDarren Tucker 
2280efd155cSDarren Tucker /* Create a service name for the given host */
2290efd155cSDarren Tucker OM_uint32
ssh_gssapi_import_name(Gssctxt * ctx,const char * host)2300efd155cSDarren Tucker ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
2310efd155cSDarren Tucker {
2320efd155cSDarren Tucker 	gss_buffer_desc gssbuf;
23363e437f0SDamien Miller 	char *val;
2340efd155cSDarren Tucker 
23563e437f0SDamien Miller 	xasprintf(&val, "host@%s", host);
23663e437f0SDamien Miller 	gssbuf.value = val;
23763e437f0SDamien Miller 	gssbuf.length = strlen(gssbuf.value);
2380efd155cSDarren Tucker 
2390efd155cSDarren Tucker 	if ((ctx->major = gss_import_name(&ctx->minor,
2400efd155cSDarren Tucker 	    &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name)))
2410efd155cSDarren Tucker 		ssh_gssapi_error(ctx);
2420efd155cSDarren Tucker 
243a627d42eSDarren Tucker 	free(gssbuf.value);
2440efd155cSDarren Tucker 	return (ctx->major);
2450efd155cSDarren Tucker }
2460efd155cSDarren Tucker 
2470efd155cSDarren Tucker OM_uint32
ssh_gssapi_sign(Gssctxt * ctx,gss_buffer_t buffer,gss_buffer_t hash)2480425d401SDamien Miller ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
2490425d401SDamien Miller {
2500425d401SDamien Miller 	if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
2510425d401SDamien Miller 	    GSS_C_QOP_DEFAULT, buffer, hash)))
2520425d401SDamien Miller 		ssh_gssapi_error(ctx);
2530425d401SDamien Miller 
2540425d401SDamien Miller 	return (ctx->major);
2550425d401SDamien Miller }
2560425d401SDamien Miller 
2570425d401SDamien Miller void
ssh_gssapi_buildmic(struct sshbuf * b,const char * user,const char * service,const char * context,const struct sshbuf * session_id)258b8d9214dSmarkus@openbsd.org ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service,
259*39be3dc2Sdjm@openbsd.org     const char *context, const struct sshbuf *session_id)
2600425d401SDamien Miller {
261b8d9214dSmarkus@openbsd.org 	int r;
262b8d9214dSmarkus@openbsd.org 
263b8d9214dSmarkus@openbsd.org 	sshbuf_reset(b);
264*39be3dc2Sdjm@openbsd.org 	if ((r = sshbuf_put_stringb(b, session_id)) != 0 ||
265b8d9214dSmarkus@openbsd.org 	    (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
266b8d9214dSmarkus@openbsd.org 	    (r = sshbuf_put_cstring(b, user)) != 0 ||
267b8d9214dSmarkus@openbsd.org 	    (r = sshbuf_put_cstring(b, service)) != 0 ||
268b8d9214dSmarkus@openbsd.org 	    (r = sshbuf_put_cstring(b, context)) != 0)
269816036f1Sdjm@openbsd.org 		fatal_fr(r, "assemble buildmic");
2700425d401SDamien Miller }
2710425d401SDamien Miller 
272a1cb9f33SDamien Miller int
ssh_gssapi_check_mechanism(Gssctxt ** ctx,gss_OID oid,const char * host)2733d2d6e90SDamien Miller ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
274a1cb9f33SDamien Miller {
275a1cb9f33SDamien Miller 	gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
276a1cb9f33SDamien Miller 	OM_uint32 major, minor;
277a1cb9f33SDamien Miller 	gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
278a1cb9f33SDamien Miller 
279a1cb9f33SDamien Miller 	/* RFC 4462 says we MUST NOT do SPNEGO */
280a1cb9f33SDamien Miller 	if (oid->length == spnego_oid.length &&
281a1cb9f33SDamien Miller 	    (memcmp(oid->elements, spnego_oid.elements, oid->length) == 0))
282deccaa7dSDamien Miller 		return 0; /* false */
283a1cb9f33SDamien Miller 
284a1cb9f33SDamien Miller 	ssh_gssapi_build_ctx(ctx);
285a1cb9f33SDamien Miller 	ssh_gssapi_set_oid(*ctx, oid);
286a1cb9f33SDamien Miller 	major = ssh_gssapi_import_name(*ctx, host);
287a1cb9f33SDamien Miller 	if (!GSS_ERROR(major)) {
288a1cb9f33SDamien Miller 		major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token,
289a1cb9f33SDamien Miller 		    NULL);
290a1cb9f33SDamien Miller 		gss_release_buffer(&minor, &token);
29176758b64SDamien Miller 		if ((*ctx)->context != GSS_C_NO_CONTEXT)
292a1cb9f33SDamien Miller 			gss_delete_sec_context(&minor, &(*ctx)->context,
293a1cb9f33SDamien Miller 			    GSS_C_NO_BUFFER);
294a1cb9f33SDamien Miller 	}
295a1cb9f33SDamien Miller 
296a1cb9f33SDamien Miller 	if (GSS_ERROR(major))
297a1cb9f33SDamien Miller 		ssh_gssapi_delete_ctx(ctx);
298a1cb9f33SDamien Miller 
299a1cb9f33SDamien Miller 	return (!GSS_ERROR(major));
300a1cb9f33SDamien Miller }
301a1cb9f33SDamien Miller 
3020efd155cSDarren Tucker #endif /* GSSAPI */
303