xref: /freebsd/lib/librpcsec_gss/rpcsec_gss_prot.c (revision 8f55a568f69c5b2fadaa020a452c2043a7dcf65f)
18f55a568SDoug Rabson /*
28f55a568SDoug Rabson   rpcsec_gss_prot.c
38f55a568SDoug Rabson 
48f55a568SDoug Rabson   Copyright (c) 2000 The Regents of the University of Michigan.
58f55a568SDoug Rabson   All rights reserved.
68f55a568SDoug Rabson 
78f55a568SDoug Rabson   Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
88f55a568SDoug Rabson   All rights reserved, all wrongs reversed.
98f55a568SDoug Rabson 
108f55a568SDoug Rabson   Redistribution and use in source and binary forms, with or without
118f55a568SDoug Rabson   modification, are permitted provided that the following conditions
128f55a568SDoug Rabson   are met:
138f55a568SDoug Rabson 
148f55a568SDoug Rabson   1. Redistributions of source code must retain the above copyright
158f55a568SDoug Rabson      notice, this list of conditions and the following disclaimer.
168f55a568SDoug Rabson   2. Redistributions in binary form must reproduce the above copyright
178f55a568SDoug Rabson      notice, this list of conditions and the following disclaimer in the
188f55a568SDoug Rabson      documentation and/or other materials provided with the distribution.
198f55a568SDoug Rabson   3. Neither the name of the University nor the names of its
208f55a568SDoug Rabson      contributors may be used to endorse or promote products derived
218f55a568SDoug Rabson      from this software without specific prior written permission.
228f55a568SDoug Rabson 
238f55a568SDoug Rabson   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
248f55a568SDoug Rabson   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
258f55a568SDoug Rabson   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
268f55a568SDoug Rabson   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
278f55a568SDoug Rabson   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
288f55a568SDoug Rabson   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
298f55a568SDoug Rabson   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
308f55a568SDoug Rabson   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
318f55a568SDoug Rabson   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
328f55a568SDoug Rabson   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
338f55a568SDoug Rabson   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
348f55a568SDoug Rabson 
358f55a568SDoug Rabson   $Id: authgss_prot.c,v 1.18 2000/09/01 04:14:03 dugsong Exp $
368f55a568SDoug Rabson */
378f55a568SDoug Rabson /* $FreeBSD$ */
388f55a568SDoug Rabson 
398f55a568SDoug Rabson #include <stdio.h>
408f55a568SDoug Rabson #include <stdlib.h>
418f55a568SDoug Rabson #include <stdarg.h>
428f55a568SDoug Rabson #include <string.h>
438f55a568SDoug Rabson #include <rpc/rpc.h>
448f55a568SDoug Rabson #include <rpc/rpcsec_gss.h>
458f55a568SDoug Rabson #include "rpcsec_gss_int.h"
468f55a568SDoug Rabson 
478f55a568SDoug Rabson #define MAX_GSS_SIZE	10240	/* XXX */
488f55a568SDoug Rabson 
498f55a568SDoug Rabson bool_t
508f55a568SDoug Rabson xdr_gss_buffer_desc(XDR *xdrs, gss_buffer_desc *p)
518f55a568SDoug Rabson {
528f55a568SDoug Rabson 	char *val;
538f55a568SDoug Rabson 	u_int len;
548f55a568SDoug Rabson 	bool_t ret;
558f55a568SDoug Rabson 
568f55a568SDoug Rabson 	val = p->value;
578f55a568SDoug Rabson 	len = p->length;
588f55a568SDoug Rabson 	ret = xdr_bytes(xdrs, &val, &len, MAX_GSS_SIZE);
598f55a568SDoug Rabson 	p->value = val;
608f55a568SDoug Rabson 	p->length = len;
618f55a568SDoug Rabson 
628f55a568SDoug Rabson 	return (ret);
638f55a568SDoug Rabson }
648f55a568SDoug Rabson 
658f55a568SDoug Rabson bool_t
668f55a568SDoug Rabson xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p)
678f55a568SDoug Rabson {
688f55a568SDoug Rabson 	enum_t proc, svc;
698f55a568SDoug Rabson 	bool_t ret;
708f55a568SDoug Rabson 
718f55a568SDoug Rabson 	proc = p->gc_proc;
728f55a568SDoug Rabson 	svc = p->gc_svc;
738f55a568SDoug Rabson 	ret = (xdr_u_int(xdrs, &p->gc_version) &&
748f55a568SDoug Rabson 	    xdr_enum(xdrs, &proc) &&
758f55a568SDoug Rabson 	    xdr_u_int(xdrs, &p->gc_seq) &&
768f55a568SDoug Rabson 	    xdr_enum(xdrs, &svc) &&
778f55a568SDoug Rabson 	    xdr_gss_buffer_desc(xdrs, &p->gc_handle));
788f55a568SDoug Rabson 	p->gc_proc = proc;
798f55a568SDoug Rabson 	p->gc_svc = svc;
808f55a568SDoug Rabson 
818f55a568SDoug Rabson 	return (ret);
828f55a568SDoug Rabson }
838f55a568SDoug Rabson 
848f55a568SDoug Rabson bool_t
858f55a568SDoug Rabson xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p)
868f55a568SDoug Rabson {
878f55a568SDoug Rabson 
888f55a568SDoug Rabson 	return (xdr_gss_buffer_desc(xdrs, &p->gr_handle) &&
898f55a568SDoug Rabson 	    xdr_u_int(xdrs, &p->gr_major) &&
908f55a568SDoug Rabson 	    xdr_u_int(xdrs, &p->gr_minor) &&
918f55a568SDoug Rabson 	    xdr_u_int(xdrs, &p->gr_win) &&
928f55a568SDoug Rabson 	    xdr_gss_buffer_desc(xdrs, &p->gr_token));
938f55a568SDoug Rabson }
948f55a568SDoug Rabson 
958f55a568SDoug Rabson bool_t
968f55a568SDoug Rabson xdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
978f55a568SDoug Rabson 		      gss_ctx_id_t ctx, gss_qop_t qop,
988f55a568SDoug Rabson 		      rpc_gss_service_t svc, u_int seq)
998f55a568SDoug Rabson {
1008f55a568SDoug Rabson 	gss_buffer_desc	databuf, wrapbuf;
1018f55a568SDoug Rabson 	OM_uint32	maj_stat, min_stat;
1028f55a568SDoug Rabson 	int		start, end, conf_state;
1038f55a568SDoug Rabson 	bool_t		xdr_stat;
1048f55a568SDoug Rabson 
1058f55a568SDoug Rabson 	/* Skip databody length. */
1068f55a568SDoug Rabson 	start = XDR_GETPOS(xdrs);
1078f55a568SDoug Rabson 	XDR_SETPOS(xdrs, start + 4);
1088f55a568SDoug Rabson 
1098f55a568SDoug Rabson 	/* Marshal rpc_gss_data_t (sequence number + arguments). */
1108f55a568SDoug Rabson 	if (!xdr_u_int(xdrs, &seq) || !xdr_func(xdrs, xdr_ptr))
1118f55a568SDoug Rabson 		return (FALSE);
1128f55a568SDoug Rabson 	end = XDR_GETPOS(xdrs);
1138f55a568SDoug Rabson 
1148f55a568SDoug Rabson 	/* Set databuf to marshalled rpc_gss_data_t. */
1158f55a568SDoug Rabson 	databuf.length = end - start - 4;
1168f55a568SDoug Rabson 	XDR_SETPOS(xdrs, start + 4);
1178f55a568SDoug Rabson 	databuf.value = XDR_INLINE(xdrs, databuf.length);
1188f55a568SDoug Rabson 
1198f55a568SDoug Rabson 	xdr_stat = FALSE;
1208f55a568SDoug Rabson 
1218f55a568SDoug Rabson 	if (svc == rpc_gss_svc_integrity) {
1228f55a568SDoug Rabson 		/* Marshal databody_integ length. */
1238f55a568SDoug Rabson 		XDR_SETPOS(xdrs, start);
1248f55a568SDoug Rabson 		if (!xdr_u_int(xdrs, &databuf.length))
1258f55a568SDoug Rabson 			return (FALSE);
1268f55a568SDoug Rabson 
1278f55a568SDoug Rabson 		/* Checksum rpc_gss_data_t. */
1288f55a568SDoug Rabson 		maj_stat = gss_get_mic(&min_stat, ctx, qop,
1298f55a568SDoug Rabson 				       &databuf, &wrapbuf);
1308f55a568SDoug Rabson 		if (maj_stat != GSS_S_COMPLETE) {
1318f55a568SDoug Rabson 			log_debug("gss_get_mic failed");
1328f55a568SDoug Rabson 			return (FALSE);
1338f55a568SDoug Rabson 		}
1348f55a568SDoug Rabson 		/* Marshal checksum. */
1358f55a568SDoug Rabson 		XDR_SETPOS(xdrs, end);
1368f55a568SDoug Rabson 		xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf);
1378f55a568SDoug Rabson 		gss_release_buffer(&min_stat, &wrapbuf);
1388f55a568SDoug Rabson 	}
1398f55a568SDoug Rabson 	else if (svc == rpc_gss_svc_privacy) {
1408f55a568SDoug Rabson 		/* Encrypt rpc_gss_data_t. */
1418f55a568SDoug Rabson 		maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf,
1428f55a568SDoug Rabson 				    &conf_state, &wrapbuf);
1438f55a568SDoug Rabson 		if (maj_stat != GSS_S_COMPLETE) {
1448f55a568SDoug Rabson 			log_status("gss_wrap", NULL, maj_stat, min_stat);
1458f55a568SDoug Rabson 			return (FALSE);
1468f55a568SDoug Rabson 		}
1478f55a568SDoug Rabson 		/* Marshal databody_priv. */
1488f55a568SDoug Rabson 		XDR_SETPOS(xdrs, start);
1498f55a568SDoug Rabson 		xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf);
1508f55a568SDoug Rabson 		gss_release_buffer(&min_stat, &wrapbuf);
1518f55a568SDoug Rabson 	}
1528f55a568SDoug Rabson 	return (xdr_stat);
1538f55a568SDoug Rabson }
1548f55a568SDoug Rabson 
1558f55a568SDoug Rabson bool_t
1568f55a568SDoug Rabson xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
1578f55a568SDoug Rabson 			gss_ctx_id_t ctx, gss_qop_t qop,
1588f55a568SDoug Rabson 			rpc_gss_service_t svc, u_int seq)
1598f55a568SDoug Rabson {
1608f55a568SDoug Rabson 	XDR		tmpxdrs;
1618f55a568SDoug Rabson 	gss_buffer_desc	databuf, wrapbuf;
1628f55a568SDoug Rabson 	OM_uint32	maj_stat, min_stat;
1638f55a568SDoug Rabson 	u_int		seq_num, conf_state, qop_state;
1648f55a568SDoug Rabson 	bool_t		xdr_stat;
1658f55a568SDoug Rabson 
1668f55a568SDoug Rabson 	if (xdr_func == (xdrproc_t) xdr_void || xdr_ptr == NULL)
1678f55a568SDoug Rabson 		return (TRUE);
1688f55a568SDoug Rabson 
1698f55a568SDoug Rabson 	memset(&databuf, 0, sizeof(databuf));
1708f55a568SDoug Rabson 	memset(&wrapbuf, 0, sizeof(wrapbuf));
1718f55a568SDoug Rabson 
1728f55a568SDoug Rabson 	if (svc == rpc_gss_svc_integrity) {
1738f55a568SDoug Rabson 		/* Decode databody_integ. */
1748f55a568SDoug Rabson 		if (!xdr_gss_buffer_desc(xdrs, &databuf)) {
1758f55a568SDoug Rabson 			log_debug("xdr decode databody_integ failed");
1768f55a568SDoug Rabson 			return (FALSE);
1778f55a568SDoug Rabson 		}
1788f55a568SDoug Rabson 		/* Decode checksum. */
1798f55a568SDoug Rabson 		if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) {
1808f55a568SDoug Rabson 			mem_free(databuf.value, databuf.length);
1818f55a568SDoug Rabson 			log_debug("xdr decode checksum failed");
1828f55a568SDoug Rabson 			return (FALSE);
1838f55a568SDoug Rabson 		}
1848f55a568SDoug Rabson 		/* Verify checksum and QOP. */
1858f55a568SDoug Rabson 		maj_stat = gss_verify_mic(&min_stat, ctx, &databuf,
1868f55a568SDoug Rabson 					  &wrapbuf, &qop_state);
1878f55a568SDoug Rabson 		mem_free(wrapbuf.value, wrapbuf.length);
1888f55a568SDoug Rabson 
1898f55a568SDoug Rabson 		if (maj_stat != GSS_S_COMPLETE || qop_state != qop) {
1908f55a568SDoug Rabson 			mem_free(databuf.value, databuf.length);
1918f55a568SDoug Rabson 			log_status("gss_verify_mic", NULL, maj_stat, min_stat);
1928f55a568SDoug Rabson 			return (FALSE);
1938f55a568SDoug Rabson 		}
1948f55a568SDoug Rabson 	} else if (svc == rpc_gss_svc_privacy) {
1958f55a568SDoug Rabson 		/* Decode databody_priv. */
1968f55a568SDoug Rabson 		if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) {
1978f55a568SDoug Rabson 			log_debug("xdr decode databody_priv failed");
1988f55a568SDoug Rabson 			return (FALSE);
1998f55a568SDoug Rabson 		}
2008f55a568SDoug Rabson 		/* Decrypt databody. */
2018f55a568SDoug Rabson 		maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf,
2028f55a568SDoug Rabson 				      &conf_state, &qop_state);
2038f55a568SDoug Rabson 
2048f55a568SDoug Rabson 		mem_free(wrapbuf.value, wrapbuf.length);
2058f55a568SDoug Rabson 
2068f55a568SDoug Rabson 		/* Verify encryption and QOP. */
2078f55a568SDoug Rabson 		if (maj_stat != GSS_S_COMPLETE || qop_state != qop ||
2088f55a568SDoug Rabson 			conf_state != TRUE) {
2098f55a568SDoug Rabson 			gss_release_buffer(&min_stat, &databuf);
2108f55a568SDoug Rabson 			log_status("gss_unwrap", NULL, maj_stat, min_stat);
2118f55a568SDoug Rabson 			return (FALSE);
2128f55a568SDoug Rabson 		}
2138f55a568SDoug Rabson 	}
2148f55a568SDoug Rabson 	/* Decode rpc_gss_data_t (sequence number + arguments). */
2158f55a568SDoug Rabson 	xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE);
2168f55a568SDoug Rabson 	xdr_stat = (xdr_u_int(&tmpxdrs, &seq_num) &&
2178f55a568SDoug Rabson 	    xdr_func(&tmpxdrs, xdr_ptr));
2188f55a568SDoug Rabson 	XDR_DESTROY(&tmpxdrs);
2198f55a568SDoug Rabson 
2208f55a568SDoug Rabson 	/*
2218f55a568SDoug Rabson 	 * Integrity service allocates databuf via XDR so free it the
2228f55a568SDoug Rabson 	 * same way.
2238f55a568SDoug Rabson 	 */
2248f55a568SDoug Rabson 	if (svc == rpc_gss_svc_integrity) {
2258f55a568SDoug Rabson 		xdr_free((xdrproc_t) xdr_gss_buffer_desc, (char *) &databuf);
2268f55a568SDoug Rabson 	} else {
2278f55a568SDoug Rabson 		gss_release_buffer(&min_stat, &databuf);
2288f55a568SDoug Rabson 	}
2298f55a568SDoug Rabson 
2308f55a568SDoug Rabson 	/* Verify sequence number. */
2318f55a568SDoug Rabson 	if (xdr_stat == TRUE && seq_num != seq) {
2328f55a568SDoug Rabson 		log_debug("wrong sequence number in databody");
2338f55a568SDoug Rabson 		return (FALSE);
2348f55a568SDoug Rabson 	}
2358f55a568SDoug Rabson 	return (xdr_stat);
2368f55a568SDoug Rabson }
2378f55a568SDoug Rabson 
2388f55a568SDoug Rabson #ifdef DEBUG
2398f55a568SDoug Rabson #include <ctype.h>
2408f55a568SDoug Rabson 
2418f55a568SDoug Rabson void
2428f55a568SDoug Rabson log_debug(const char *fmt, ...)
2438f55a568SDoug Rabson {
2448f55a568SDoug Rabson 	va_list ap;
2458f55a568SDoug Rabson 
2468f55a568SDoug Rabson 	va_start(ap, fmt);
2478f55a568SDoug Rabson 	fprintf(stderr, "rpcsec_gss: ");
2488f55a568SDoug Rabson 	vfprintf(stderr, fmt, ap);
2498f55a568SDoug Rabson 	fprintf(stderr, "\n");
2508f55a568SDoug Rabson 	va_end(ap);
2518f55a568SDoug Rabson }
2528f55a568SDoug Rabson 
2538f55a568SDoug Rabson void
2548f55a568SDoug Rabson log_status(const char *m, gss_OID mech, OM_uint32 maj_stat, OM_uint32 min_stat)
2558f55a568SDoug Rabson {
2568f55a568SDoug Rabson 	OM_uint32 min;
2578f55a568SDoug Rabson 	gss_buffer_desc msg;
2588f55a568SDoug Rabson 	int msg_ctx = 0;
2598f55a568SDoug Rabson 
2608f55a568SDoug Rabson 	fprintf(stderr, "rpcsec_gss: %s: ", m);
2618f55a568SDoug Rabson 
2628f55a568SDoug Rabson 	gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID,
2638f55a568SDoug Rabson 			   &msg_ctx, &msg);
2648f55a568SDoug Rabson 	fprintf(stderr, "%s - ", (char *)msg.value);
2658f55a568SDoug Rabson 	gss_release_buffer(&min, &msg);
2668f55a568SDoug Rabson 
2678f55a568SDoug Rabson 	gss_display_status(&min, min_stat, GSS_C_MECH_CODE, mech,
2688f55a568SDoug Rabson 			   &msg_ctx, &msg);
2698f55a568SDoug Rabson 	fprintf(stderr, "%s\n", (char *)msg.value);
2708f55a568SDoug Rabson 	gss_release_buffer(&min, &msg);
2718f55a568SDoug Rabson }
2728f55a568SDoug Rabson 
2738f55a568SDoug Rabson #else
2748f55a568SDoug Rabson 
2758f55a568SDoug Rabson void
2768f55a568SDoug Rabson log_debug(__unused const char *fmt, ...)
2778f55a568SDoug Rabson {
2788f55a568SDoug Rabson }
2798f55a568SDoug Rabson 
2808f55a568SDoug Rabson void
2818f55a568SDoug Rabson log_status(__unused const char *m, __unused gss_OID mech,
2828f55a568SDoug Rabson     __unused OM_uint32 maj_stat, __unused OM_uint32 min_stat)
2838f55a568SDoug Rabson {
2848f55a568SDoug Rabson }
2858f55a568SDoug Rabson 
2868f55a568SDoug Rabson #endif
2878f55a568SDoug Rabson 
2888f55a568SDoug Rabson 
289