xref: /freebsd/sys/rpc/rpcsec_gss/rpcsec_gss_prot.c (revision a9148abd9da5db2f1c682fb17bed791845fc41c9)
1a9148abdSDoug Rabson /*
2a9148abdSDoug Rabson   rpcsec_gss_prot.c
3a9148abdSDoug Rabson 
4a9148abdSDoug Rabson   Copyright (c) 2000 The Regents of the University of Michigan.
5a9148abdSDoug Rabson   All rights reserved.
6a9148abdSDoug Rabson 
7a9148abdSDoug Rabson   Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
8a9148abdSDoug Rabson   All rights reserved, all wrongs reversed.
9a9148abdSDoug Rabson 
10a9148abdSDoug Rabson   Redistribution and use in source and binary forms, with or without
11a9148abdSDoug Rabson   modification, are permitted provided that the following conditions
12a9148abdSDoug Rabson   are met:
13a9148abdSDoug Rabson 
14a9148abdSDoug Rabson   1. Redistributions of source code must retain the above copyright
15a9148abdSDoug Rabson      notice, this list of conditions and the following disclaimer.
16a9148abdSDoug Rabson   2. Redistributions in binary form must reproduce the above copyright
17a9148abdSDoug Rabson      notice, this list of conditions and the following disclaimer in the
18a9148abdSDoug Rabson      documentation and/or other materials provided with the distribution.
19a9148abdSDoug Rabson   3. Neither the name of the University nor the names of its
20a9148abdSDoug Rabson      contributors may be used to endorse or promote products derived
21a9148abdSDoug Rabson      from this software without specific prior written permission.
22a9148abdSDoug Rabson 
23a9148abdSDoug Rabson   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
24a9148abdSDoug Rabson   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25a9148abdSDoug Rabson   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26a9148abdSDoug Rabson   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27a9148abdSDoug Rabson   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28a9148abdSDoug Rabson   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29a9148abdSDoug Rabson   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30a9148abdSDoug Rabson   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31a9148abdSDoug Rabson   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32a9148abdSDoug Rabson   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33a9148abdSDoug Rabson   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34a9148abdSDoug Rabson 
35a9148abdSDoug Rabson   $Id: authgss_prot.c,v 1.18 2000/09/01 04:14:03 dugsong Exp $
36a9148abdSDoug Rabson */
37a9148abdSDoug Rabson 
38a9148abdSDoug Rabson #include <sys/cdefs.h>
39a9148abdSDoug Rabson __FBSDID("$FreeBSD$");
40a9148abdSDoug Rabson 
41a9148abdSDoug Rabson #include <sys/param.h>
42a9148abdSDoug Rabson #include <sys/systm.h>
43a9148abdSDoug Rabson #include <sys/kobj.h>
44a9148abdSDoug Rabson #include <sys/lock.h>
45a9148abdSDoug Rabson #include <sys/malloc.h>
46a9148abdSDoug Rabson #include <sys/mbuf.h>
47a9148abdSDoug Rabson #include <sys/mutex.h>
48a9148abdSDoug Rabson 
49a9148abdSDoug Rabson #include <rpc/rpc.h>
50a9148abdSDoug Rabson #include <rpc/rpcsec_gss.h>
51a9148abdSDoug Rabson 
52a9148abdSDoug Rabson #include "rpcsec_gss_int.h"
53a9148abdSDoug Rabson 
54a9148abdSDoug Rabson #define MAX_GSS_SIZE	10240	/* XXX */
55a9148abdSDoug Rabson 
56a9148abdSDoug Rabson #if 0				/* use the one from kgssapi */
57a9148abdSDoug Rabson bool_t
58a9148abdSDoug Rabson xdr_gss_buffer_desc(XDR *xdrs, gss_buffer_desc *p)
59a9148abdSDoug Rabson {
60a9148abdSDoug Rabson 	char *val;
61a9148abdSDoug Rabson 	u_int len;
62a9148abdSDoug Rabson 	bool_t ret;
63a9148abdSDoug Rabson 
64a9148abdSDoug Rabson 	val = p->value;
65a9148abdSDoug Rabson 	len = p->length;
66a9148abdSDoug Rabson 	ret = xdr_bytes(xdrs, &val, &len, MAX_GSS_SIZE);
67a9148abdSDoug Rabson 	p->value = val;
68a9148abdSDoug Rabson 	p->length = len;
69a9148abdSDoug Rabson 
70a9148abdSDoug Rabson 	return (ret);
71a9148abdSDoug Rabson }
72a9148abdSDoug Rabson #endif
73a9148abdSDoug Rabson 
74a9148abdSDoug Rabson bool_t
75a9148abdSDoug Rabson xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p)
76a9148abdSDoug Rabson {
77a9148abdSDoug Rabson 	enum_t proc, svc;
78a9148abdSDoug Rabson 	bool_t ret;
79a9148abdSDoug Rabson 
80a9148abdSDoug Rabson 	proc = p->gc_proc;
81a9148abdSDoug Rabson 	svc = p->gc_svc;
82a9148abdSDoug Rabson 	ret = (xdr_u_int(xdrs, &p->gc_version) &&
83a9148abdSDoug Rabson 	    xdr_enum(xdrs, &proc) &&
84a9148abdSDoug Rabson 	    xdr_u_int(xdrs, &p->gc_seq) &&
85a9148abdSDoug Rabson 	    xdr_enum(xdrs, &svc) &&
86a9148abdSDoug Rabson 	    xdr_gss_buffer_desc(xdrs, &p->gc_handle));
87a9148abdSDoug Rabson 	p->gc_proc = proc;
88a9148abdSDoug Rabson 	p->gc_svc = svc;
89a9148abdSDoug Rabson 
90a9148abdSDoug Rabson 	return (ret);
91a9148abdSDoug Rabson }
92a9148abdSDoug Rabson 
93a9148abdSDoug Rabson bool_t
94a9148abdSDoug Rabson xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p)
95a9148abdSDoug Rabson {
96a9148abdSDoug Rabson 
97a9148abdSDoug Rabson 	return (xdr_gss_buffer_desc(xdrs, &p->gr_handle) &&
98a9148abdSDoug Rabson 	    xdr_u_int(xdrs, &p->gr_major) &&
99a9148abdSDoug Rabson 	    xdr_u_int(xdrs, &p->gr_minor) &&
100a9148abdSDoug Rabson 	    xdr_u_int(xdrs, &p->gr_win) &&
101a9148abdSDoug Rabson 	    xdr_gss_buffer_desc(xdrs, &p->gr_token));
102a9148abdSDoug Rabson }
103a9148abdSDoug Rabson 
104a9148abdSDoug Rabson static void
105a9148abdSDoug Rabson put_uint32(struct mbuf **mp, uint32_t v)
106a9148abdSDoug Rabson {
107a9148abdSDoug Rabson 	struct mbuf *m = *mp;
108a9148abdSDoug Rabson 	uint32_t n;
109a9148abdSDoug Rabson 
110a9148abdSDoug Rabson 	M_PREPEND(m, sizeof(uint32_t), M_WAIT);
111a9148abdSDoug Rabson 	n = htonl(v);
112a9148abdSDoug Rabson 	bcopy(&n, mtod(m, uint32_t *), sizeof(uint32_t));
113a9148abdSDoug Rabson 	*mp = m;
114a9148abdSDoug Rabson }
115a9148abdSDoug Rabson 
116a9148abdSDoug Rabson bool_t
117a9148abdSDoug Rabson xdr_rpc_gss_wrap_data(struct mbuf **argsp,
118a9148abdSDoug Rabson 		      gss_ctx_id_t ctx, gss_qop_t qop,
119a9148abdSDoug Rabson 		      rpc_gss_service_t svc, u_int seq)
120a9148abdSDoug Rabson {
121a9148abdSDoug Rabson 	struct mbuf	*args, *mic;
122a9148abdSDoug Rabson 	OM_uint32	maj_stat, min_stat;
123a9148abdSDoug Rabson 	int		conf_state;
124a9148abdSDoug Rabson 	u_int		len;
125a9148abdSDoug Rabson 	static char	zpad[4];
126a9148abdSDoug Rabson 
127a9148abdSDoug Rabson 	args = *argsp;
128a9148abdSDoug Rabson 
129a9148abdSDoug Rabson 	/*
130a9148abdSDoug Rabson 	 * Prepend the sequence number before calling gss_get_mic or gss_wrap.
131a9148abdSDoug Rabson 	 */
132a9148abdSDoug Rabson 	put_uint32(&args, seq);
133a9148abdSDoug Rabson 	len = m_length(args, NULL);
134a9148abdSDoug Rabson 
135a9148abdSDoug Rabson 	if (svc == rpc_gss_svc_integrity) {
136a9148abdSDoug Rabson 		/* Checksum rpc_gss_data_t. */
137a9148abdSDoug Rabson 		maj_stat = gss_get_mic_mbuf(&min_stat, ctx, qop, args, &mic);
138a9148abdSDoug Rabson 		if (maj_stat != GSS_S_COMPLETE) {
139a9148abdSDoug Rabson 			rpc_gss_log_debug("gss_get_mic failed");
140a9148abdSDoug Rabson 			m_freem(args);
141a9148abdSDoug Rabson 			return (FALSE);
142a9148abdSDoug Rabson 		}
143a9148abdSDoug Rabson 
144a9148abdSDoug Rabson 		/*
145a9148abdSDoug Rabson 		 * Marshal databody_integ. Note that since args is
146a9148abdSDoug Rabson 		 * already RPC encoded, there will be no padding.
147a9148abdSDoug Rabson 		 */
148a9148abdSDoug Rabson 		put_uint32(&args, len);
149a9148abdSDoug Rabson 
150a9148abdSDoug Rabson 		/*
151a9148abdSDoug Rabson 		 * Marshal checksum. This is likely to need padding.
152a9148abdSDoug Rabson 		 */
153a9148abdSDoug Rabson 		len = m_length(mic, NULL);
154a9148abdSDoug Rabson 		put_uint32(&mic, len);
155a9148abdSDoug Rabson 		if (len != RNDUP(len)) {
156a9148abdSDoug Rabson 			m_append(mic, RNDUP(len) - len, zpad);
157a9148abdSDoug Rabson 		}
158a9148abdSDoug Rabson 
159a9148abdSDoug Rabson 		/*
160a9148abdSDoug Rabson 		 * Concatenate databody_integ with checksum.
161a9148abdSDoug Rabson 		 */
162a9148abdSDoug Rabson 		m_cat(args, mic);
163a9148abdSDoug Rabson 	} else if (svc == rpc_gss_svc_privacy) {
164a9148abdSDoug Rabson 		/* Encrypt rpc_gss_data_t. */
165a9148abdSDoug Rabson 		maj_stat = gss_wrap_mbuf(&min_stat, ctx, TRUE, qop,
166a9148abdSDoug Rabson 		    &args, &conf_state);
167a9148abdSDoug Rabson 		if (maj_stat != GSS_S_COMPLETE) {
168a9148abdSDoug Rabson 			rpc_gss_log_status("gss_wrap", NULL,
169a9148abdSDoug Rabson 			    maj_stat, min_stat);
170a9148abdSDoug Rabson 			return (FALSE);
171a9148abdSDoug Rabson 		}
172a9148abdSDoug Rabson 
173a9148abdSDoug Rabson 		/*
174a9148abdSDoug Rabson 		 *  Marshal databody_priv and deal with RPC padding.
175a9148abdSDoug Rabson 		 */
176a9148abdSDoug Rabson 		len = m_length(args, NULL);
177a9148abdSDoug Rabson 		put_uint32(&args, len);
178a9148abdSDoug Rabson 		if (len != RNDUP(len)) {
179a9148abdSDoug Rabson 			m_append(args, RNDUP(len) - len, zpad);
180a9148abdSDoug Rabson 		}
181a9148abdSDoug Rabson 	}
182a9148abdSDoug Rabson 	*argsp = args;
183a9148abdSDoug Rabson 	return (TRUE);
184a9148abdSDoug Rabson }
185a9148abdSDoug Rabson 
186a9148abdSDoug Rabson static uint32_t
187a9148abdSDoug Rabson get_uint32(struct mbuf **mp)
188a9148abdSDoug Rabson {
189a9148abdSDoug Rabson 	struct mbuf *m = *mp;
190a9148abdSDoug Rabson 	uint32_t n;
191a9148abdSDoug Rabson 
192a9148abdSDoug Rabson 	if (m->m_len < sizeof(uint32_t)) {
193a9148abdSDoug Rabson 		m = m_pullup(m, sizeof(uint32_t));
194a9148abdSDoug Rabson 		if (!m) {
195a9148abdSDoug Rabson 			*mp = NULL;
196a9148abdSDoug Rabson 			return (0);
197a9148abdSDoug Rabson 		}
198a9148abdSDoug Rabson 	}
199a9148abdSDoug Rabson 	bcopy(mtod(m, uint32_t *), &n, sizeof(uint32_t));
200a9148abdSDoug Rabson 	m_adj(m, sizeof(uint32_t));
201a9148abdSDoug Rabson 	*mp = m;
202a9148abdSDoug Rabson 	return (ntohl(n));
203a9148abdSDoug Rabson }
204a9148abdSDoug Rabson 
205a9148abdSDoug Rabson static void
206a9148abdSDoug Rabson m_trim(struct mbuf *m, int len)
207a9148abdSDoug Rabson {
208a9148abdSDoug Rabson 	struct mbuf *n;
209a9148abdSDoug Rabson 	int off;
210a9148abdSDoug Rabson 
211a9148abdSDoug Rabson 	n = m_getptr(m, len, &off);
212a9148abdSDoug Rabson 	if (n) {
213a9148abdSDoug Rabson 		n->m_len = off;
214a9148abdSDoug Rabson 		if (n->m_next) {
215a9148abdSDoug Rabson 			m_freem(n->m_next);
216a9148abdSDoug Rabson 			n->m_next = NULL;
217a9148abdSDoug Rabson 		}
218a9148abdSDoug Rabson 	}
219a9148abdSDoug Rabson }
220a9148abdSDoug Rabson 
221a9148abdSDoug Rabson bool_t
222a9148abdSDoug Rabson xdr_rpc_gss_unwrap_data(struct mbuf **resultsp,
223a9148abdSDoug Rabson 			gss_ctx_id_t ctx, gss_qop_t qop,
224a9148abdSDoug Rabson 			rpc_gss_service_t svc, u_int seq)
225a9148abdSDoug Rabson {
226a9148abdSDoug Rabson 	struct mbuf	*results, *message, *mic;
227a9148abdSDoug Rabson 	uint32_t	len, cklen;
228a9148abdSDoug Rabson 	OM_uint32	maj_stat, min_stat;
229a9148abdSDoug Rabson 	u_int		seq_num, conf_state, qop_state;
230a9148abdSDoug Rabson 
231a9148abdSDoug Rabson 	results = *resultsp;
232a9148abdSDoug Rabson 	*resultsp = NULL;
233a9148abdSDoug Rabson 
234a9148abdSDoug Rabson 	message = NULL;
235a9148abdSDoug Rabson 	if (svc == rpc_gss_svc_integrity) {
236a9148abdSDoug Rabson 		/*
237a9148abdSDoug Rabson 		 * Extract the seq+message part. Remember that there
238a9148abdSDoug Rabson 		 * may be extra RPC padding in the checksum. The
239a9148abdSDoug Rabson 		 * message part is RPC encoded already so no
240a9148abdSDoug Rabson 		 * padding.
241a9148abdSDoug Rabson 		 */
242a9148abdSDoug Rabson 		len = get_uint32(&results);
243a9148abdSDoug Rabson 		message = results;
244a9148abdSDoug Rabson 		results = m_split(results, len, M_WAIT);
245a9148abdSDoug Rabson 		if (!results) {
246a9148abdSDoug Rabson 			m_freem(message);
247a9148abdSDoug Rabson 			return (FALSE);
248a9148abdSDoug Rabson 		}
249a9148abdSDoug Rabson 
250a9148abdSDoug Rabson 		/*
251a9148abdSDoug Rabson 		 * Extract the MIC and make it contiguous.
252a9148abdSDoug Rabson 		 */
253a9148abdSDoug Rabson 		cklen = get_uint32(&results);
254a9148abdSDoug Rabson 		KASSERT(cklen <= MHLEN, ("unexpected large GSS-API checksum"));
255a9148abdSDoug Rabson 		mic = results;
256a9148abdSDoug Rabson 		if (cklen > mic->m_len)
257a9148abdSDoug Rabson 			mic = m_pullup(mic, cklen);
258a9148abdSDoug Rabson 		if (cklen != RNDUP(cklen))
259a9148abdSDoug Rabson 			m_trim(mic, cklen);
260a9148abdSDoug Rabson 
261a9148abdSDoug Rabson 		/* Verify checksum and QOP. */
262a9148abdSDoug Rabson 		maj_stat = gss_verify_mic_mbuf(&min_stat, ctx,
263a9148abdSDoug Rabson 		    message, mic, &qop_state);
264a9148abdSDoug Rabson 		m_freem(mic);
265a9148abdSDoug Rabson 
266a9148abdSDoug Rabson 		if (maj_stat != GSS_S_COMPLETE || qop_state != qop) {
267a9148abdSDoug Rabson 			m_freem(message);
268a9148abdSDoug Rabson 			rpc_gss_log_status("gss_verify_mic", NULL,
269a9148abdSDoug Rabson 			    maj_stat, min_stat);
270a9148abdSDoug Rabson 			return (FALSE);
271a9148abdSDoug Rabson 		}
272a9148abdSDoug Rabson 	} else if (svc == rpc_gss_svc_privacy) {
273a9148abdSDoug Rabson 		/* Decode databody_priv. */
274a9148abdSDoug Rabson 		len = get_uint32(&results);
275a9148abdSDoug Rabson 
276a9148abdSDoug Rabson 		/* Decrypt databody. */
277a9148abdSDoug Rabson 		message = results;
278a9148abdSDoug Rabson 		if (len != RNDUP(len))
279a9148abdSDoug Rabson 			m_trim(message, len);
280a9148abdSDoug Rabson 		maj_stat = gss_unwrap_mbuf(&min_stat, ctx, &message,
281a9148abdSDoug Rabson 		    &conf_state, &qop_state);
282a9148abdSDoug Rabson 
283a9148abdSDoug Rabson 		/* Verify encryption and QOP. */
284a9148abdSDoug Rabson 		if (maj_stat != GSS_S_COMPLETE) {
285a9148abdSDoug Rabson 			rpc_gss_log_status("gss_unwrap", NULL,
286a9148abdSDoug Rabson 			    maj_stat, min_stat);
287a9148abdSDoug Rabson 			return (FALSE);
288a9148abdSDoug Rabson 		}
289a9148abdSDoug Rabson 		if (qop_state != qop || conf_state != TRUE) {
290a9148abdSDoug Rabson 			m_freem(results);
291a9148abdSDoug Rabson 			return (FALSE);
292a9148abdSDoug Rabson 		}
293a9148abdSDoug Rabson 	}
294a9148abdSDoug Rabson 
295a9148abdSDoug Rabson 	/* Decode rpc_gss_data_t (sequence number + arguments). */
296a9148abdSDoug Rabson 	seq_num = get_uint32(&message);
297a9148abdSDoug Rabson 
298a9148abdSDoug Rabson 	/* Verify sequence number. */
299a9148abdSDoug Rabson 	if (seq_num != seq) {
300a9148abdSDoug Rabson 		rpc_gss_log_debug("wrong sequence number in databody");
301a9148abdSDoug Rabson 		m_freem(message);
302a9148abdSDoug Rabson 		return (FALSE);
303a9148abdSDoug Rabson 	}
304a9148abdSDoug Rabson 
305a9148abdSDoug Rabson 	*resultsp = message;
306a9148abdSDoug Rabson 	return (TRUE);
307a9148abdSDoug Rabson }
308a9148abdSDoug Rabson 
309a9148abdSDoug Rabson #ifdef DEBUG
310a9148abdSDoug Rabson #include <ctype.h>
311a9148abdSDoug Rabson 
312a9148abdSDoug Rabson void
313a9148abdSDoug Rabson rpc_gss_log_debug(const char *fmt, ...)
314a9148abdSDoug Rabson {
315a9148abdSDoug Rabson 	va_list ap;
316a9148abdSDoug Rabson 
317a9148abdSDoug Rabson 	va_start(ap, fmt);
318a9148abdSDoug Rabson 	fprintf(stderr, "rpcsec_gss: ");
319a9148abdSDoug Rabson 	vfprintf(stderr, fmt, ap);
320a9148abdSDoug Rabson 	fprintf(stderr, "\n");
321a9148abdSDoug Rabson 	va_end(ap);
322a9148abdSDoug Rabson }
323a9148abdSDoug Rabson 
324a9148abdSDoug Rabson void
325a9148abdSDoug Rabson rpc_gss_log_status(const char *m, gss_OID mech, OM_uint32 maj_stat, OM_uint32 min_stat)
326a9148abdSDoug Rabson {
327a9148abdSDoug Rabson 	OM_uint32 min;
328a9148abdSDoug Rabson 	gss_buffer_desc msg;
329a9148abdSDoug Rabson 	int msg_ctx = 0;
330a9148abdSDoug Rabson 
331a9148abdSDoug Rabson 	fprintf(stderr, "rpcsec_gss: %s: ", m);
332a9148abdSDoug Rabson 
333a9148abdSDoug Rabson 	gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID,
334a9148abdSDoug Rabson 			   &msg_ctx, &msg);
335a9148abdSDoug Rabson 	printf("%s - ", (char *)msg.value);
336a9148abdSDoug Rabson 	gss_release_buffer(&min, &msg);
337a9148abdSDoug Rabson 
338a9148abdSDoug Rabson 	gss_display_status(&min, min_stat, GSS_C_MECH_CODE, mech,
339a9148abdSDoug Rabson 			   &msg_ctx, &msg);
340a9148abdSDoug Rabson 	printf("%s\n", (char *)msg.value);
341a9148abdSDoug Rabson 	gss_release_buffer(&min, &msg);
342a9148abdSDoug Rabson }
343a9148abdSDoug Rabson 
344a9148abdSDoug Rabson #else
345a9148abdSDoug Rabson 
346a9148abdSDoug Rabson void
347a9148abdSDoug Rabson rpc_gss_log_debug(__unused const char *fmt, ...)
348a9148abdSDoug Rabson {
349a9148abdSDoug Rabson }
350a9148abdSDoug Rabson 
351a9148abdSDoug Rabson void
352a9148abdSDoug Rabson rpc_gss_log_status(__unused const char *m, __unused gss_OID mech,
353a9148abdSDoug Rabson     __unused OM_uint32 maj_stat, __unused OM_uint32 min_stat)
354a9148abdSDoug Rabson {
355a9148abdSDoug Rabson }
356a9148abdSDoug Rabson 
357a9148abdSDoug Rabson #endif
358a9148abdSDoug Rabson 
359a9148abdSDoug Rabson 
360