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