bool_t xdr_rpc_gss_wrap_data(struct mbuf **argsp, gss_ctx_id_t ctx, gss_qop_t qop, rpc_gss_service_t svc, u_int seq) { struct mbuf *args, *mic; OM_uint32 maj_stat, min_stat; int conf_state; u_int len; static char zpad[4]; args = *argsp; /* * Prepend the sequence number before calling gss_get_mic or gss_wrap. */ put_uint32(&args, seq); len = m_length(args, NULL); if (svc == rpc_gss_svc_integrity) { /* Checksum rpc_gss_data_t. */ maj_stat = gss_get_mic_mbuf(&min_stat, ctx, qop, args, &mic); if (maj_stat != GSS_S_COMPLETE) { rpc_gss_log_debug("gss_get_mic failed"); m_freem(args); return (FALSE); } /* * Marshal databody_integ. Note that since args is * already RPC encoded, there will be no padding. */ put_uint32(&args, len); /* * Marshal checksum. This is likely to need padding. */ len = m_length(mic, NULL); put_uint32(&mic, len); if (len != RNDUP(len)) { m_append(mic, RNDUP(len) - len, zpad); } /* * Concatenate databody_integ with checksum. */ m_cat(args, mic); } else if (svc == rpc_gss_svc_privacy) { /* Encrypt rpc_gss_data_t. */ maj_stat = gss_wrap_mbuf(&min_stat, ctx, TRUE, qop, &args, &conf_state); if (maj_stat != GSS_S_COMPLETE) { rpc_gss_log_status("gss_wrap", NULL, maj_stat, min_stat); return (FALSE); } /* * Marshal databody_priv and deal with RPC padding. */ len = m_length(args, NULL); put_uint32(&args, len); if (len != RNDUP(len)) { m_append(args, RNDUP(len) - len, zpad); } } *argsp = args; return (TRUE); }
bool_t xdr_rpc_gss_unwrap_data(struct mbuf **resultsp, gss_ctx_id_t ctx, gss_qop_t qop, rpc_gss_service_t svc, u_int seq) { struct mbuf *results, *message, *mic; uint32_t len, cklen; OM_uint32 maj_stat, min_stat; u_int seq_num, conf_state, qop_state; results = *resultsp; *resultsp = NULL; message = NULL; if (svc == rpc_gss_svc_integrity) { /* * Extract the seq+message part. Remember that there * may be extra RPC padding in the checksum. The * message part is RPC encoded already so no * padding. */ len = get_uint32(&results); message = results; results = m_split(results, len, M_WAIT); if (!results) { m_freem(message); return (FALSE); } /* * Extract the MIC and make it contiguous. */ cklen = get_uint32(&results); KASSERT(cklen <= MHLEN, ("unexpected large GSS-API checksum")); mic = results; if (cklen > mic->m_len) mic = m_pullup(mic, cklen); if (cklen != RNDUP(cklen)) m_trim(mic, cklen); /* Verify checksum and QOP. */ maj_stat = gss_verify_mic_mbuf(&min_stat, ctx, message, mic, &qop_state); m_freem(mic); if (maj_stat != GSS_S_COMPLETE || qop_state != qop) { m_freem(message); rpc_gss_log_status("gss_verify_mic", NULL, maj_stat, min_stat); return (FALSE); } } else if (svc == rpc_gss_svc_privacy) { /* Decode databody_priv. */ len = get_uint32(&results); /* Decrypt databody. */ message = results; if (len != RNDUP(len)) m_trim(message, len); maj_stat = gss_unwrap_mbuf(&min_stat, ctx, &message, &conf_state, &qop_state); /* Verify encryption and QOP. */ if (maj_stat != GSS_S_COMPLETE) { rpc_gss_log_status("gss_unwrap", NULL, maj_stat, min_stat); return (FALSE); } if (qop_state != qop || conf_state != TRUE) { m_freem(results); return (FALSE); } } /* Decode rpc_gss_data_t (sequence number + arguments). */ seq_num = get_uint32(&message); /* Verify sequence number. */ if (seq_num != seq) { rpc_gss_log_debug("wrong sequence number in databody"); m_freem(message); return (FALSE); } *resultsp = message; return (TRUE); }