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