1184588Sdfr/*- 2184588Sdfr * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 3184588Sdfr * Authors: Doug Rabson <dfr@rabson.org> 4184588Sdfr * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 5184588Sdfr * 6184588Sdfr * Redistribution and use in source and binary forms, with or without 7184588Sdfr * modification, are permitted provided that the following conditions 8184588Sdfr * are met: 9184588Sdfr * 1. Redistributions of source code must retain the above copyright 10184588Sdfr * notice, this list of conditions and the following disclaimer. 11184588Sdfr * 2. Redistributions in binary form must reproduce the above copyright 12184588Sdfr * notice, this list of conditions and the following disclaimer in the 13184588Sdfr * documentation and/or other materials provided with the distribution. 14184588Sdfr * 15184588Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16184588Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17184588Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18184588Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19184588Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20184588Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21184588Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22184588Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23184588Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24184588Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25184588Sdfr * SUCH DAMAGE. 26184588Sdfr */ 27184588Sdfr 28184588Sdfr#include <sys/cdefs.h> 29184588Sdfr__FBSDID("$FreeBSD: releng/10.3/sys/kgssapi/krb5/krb5_mech.c 250157 2013-05-01 22:07:55Z rmacklem $"); 30184588Sdfr 31184588Sdfr#include "opt_inet6.h" 32184588Sdfr 33184588Sdfr#include <sys/param.h> 34184588Sdfr#include <sys/kernel.h> 35184588Sdfr#include <sys/kobj.h> 36184588Sdfr#include <sys/lock.h> 37184588Sdfr#include <sys/malloc.h> 38184588Sdfr#include <sys/mbuf.h> 39184588Sdfr#include <sys/module.h> 40184588Sdfr#include <sys/mutex.h> 41184588Sdfr#include <kgssapi/gssapi.h> 42184588Sdfr#include <kgssapi/gssapi_impl.h> 43184588Sdfr 44184588Sdfr#include "kgss_if.h" 45184588Sdfr#include "kcrypto.h" 46184588Sdfr 47184588Sdfr#define GSS_TOKEN_SENT_BY_ACCEPTOR 1 48184588Sdfr#define GSS_TOKEN_SEALED 2 49184588Sdfr#define GSS_TOKEN_ACCEPTOR_SUBKEY 4 50184588Sdfr 51184588Sdfrstatic gss_OID_desc krb5_mech_oid = 52184588Sdfr{9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }; 53184588Sdfr 54184588Sdfrstruct krb5_data { 55184588Sdfr size_t kd_length; 56184588Sdfr void *kd_data; 57184588Sdfr}; 58184588Sdfr 59184588Sdfrstruct krb5_keyblock { 60184588Sdfr uint16_t kk_type; /* encryption type */ 61184588Sdfr struct krb5_data kk_key; /* key data */ 62184588Sdfr}; 63184588Sdfr 64184588Sdfrstruct krb5_address { 65184588Sdfr uint16_t ka_type; 66184588Sdfr struct krb5_data ka_addr; 67184588Sdfr}; 68184588Sdfr 69184588Sdfr/* 70184588Sdfr * The km_elem array is ordered so that the highest received sequence 71184588Sdfr * number is listed first. 72184588Sdfr */ 73184588Sdfrstruct krb5_msg_order { 74184588Sdfr uint32_t km_flags; 75184588Sdfr uint32_t km_start; 76184588Sdfr uint32_t km_length; 77184588Sdfr uint32_t km_jitter_window; 78184588Sdfr uint32_t km_first_seq; 79184588Sdfr uint32_t *km_elem; 80184588Sdfr}; 81184588Sdfr 82184588Sdfrstruct krb5_context { 83184588Sdfr struct _gss_ctx_id_t kc_common; 84184588Sdfr struct mtx kc_lock; 85184588Sdfr uint32_t kc_ac_flags; 86184588Sdfr uint32_t kc_ctx_flags; 87184588Sdfr uint32_t kc_more_flags; 88184588Sdfr#define LOCAL 1 89184588Sdfr#define OPEN 2 90184588Sdfr#define COMPAT_OLD_DES3 4 91184588Sdfr#define COMPAT_OLD_DES3_SELECTED 8 92184588Sdfr#define ACCEPTOR_SUBKEY 16 93184588Sdfr struct krb5_address kc_local_address; 94184588Sdfr struct krb5_address kc_remote_address; 95184588Sdfr uint16_t kc_local_port; 96184588Sdfr uint16_t kc_remote_port; 97184588Sdfr struct krb5_keyblock kc_keyblock; 98184588Sdfr struct krb5_keyblock kc_local_subkey; 99184588Sdfr struct krb5_keyblock kc_remote_subkey; 100184588Sdfr volatile uint32_t kc_local_seqnumber; 101184588Sdfr uint32_t kc_remote_seqnumber; 102184588Sdfr uint32_t kc_keytype; 103184588Sdfr uint32_t kc_cksumtype; 104184588Sdfr struct krb5_data kc_source_name; 105184588Sdfr struct krb5_data kc_target_name; 106184588Sdfr uint32_t kc_lifetime; 107184588Sdfr struct krb5_msg_order kc_msg_order; 108184588Sdfr struct krb5_key_state *kc_tokenkey; 109184588Sdfr struct krb5_key_state *kc_encryptkey; 110184588Sdfr struct krb5_key_state *kc_checksumkey; 111184588Sdfr 112184588Sdfr struct krb5_key_state *kc_send_seal_Ke; 113184588Sdfr struct krb5_key_state *kc_send_seal_Ki; 114184588Sdfr struct krb5_key_state *kc_send_seal_Kc; 115184588Sdfr struct krb5_key_state *kc_send_sign_Kc; 116184588Sdfr 117184588Sdfr struct krb5_key_state *kc_recv_seal_Ke; 118184588Sdfr struct krb5_key_state *kc_recv_seal_Ki; 119184588Sdfr struct krb5_key_state *kc_recv_seal_Kc; 120184588Sdfr struct krb5_key_state *kc_recv_sign_Kc; 121184588Sdfr}; 122184588Sdfr 123184588Sdfrstatic uint16_t 124184588Sdfrget_uint16(const uint8_t **pp, size_t *lenp) 125184588Sdfr{ 126184588Sdfr const uint8_t *p = *pp; 127184588Sdfr uint16_t v; 128184588Sdfr 129184588Sdfr if (*lenp < 2) 130184588Sdfr return (0); 131184588Sdfr 132184588Sdfr v = (p[0] << 8) | p[1]; 133184588Sdfr *pp = p + 2; 134184588Sdfr *lenp = *lenp - 2; 135184588Sdfr 136184588Sdfr return (v); 137184588Sdfr} 138184588Sdfr 139184588Sdfrstatic uint32_t 140184588Sdfrget_uint32(const uint8_t **pp, size_t *lenp) 141184588Sdfr{ 142184588Sdfr const uint8_t *p = *pp; 143184588Sdfr uint32_t v; 144184588Sdfr 145184588Sdfr if (*lenp < 4) 146184588Sdfr return (0); 147184588Sdfr 148184588Sdfr v = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; 149184588Sdfr *pp = p + 4; 150184588Sdfr *lenp = *lenp - 4; 151184588Sdfr 152184588Sdfr return (v); 153184588Sdfr} 154184588Sdfr 155184588Sdfrstatic void 156184588Sdfrget_data(const uint8_t **pp, size_t *lenp, struct krb5_data *dp) 157184588Sdfr{ 158184588Sdfr size_t sz = get_uint32(pp, lenp); 159184588Sdfr 160184588Sdfr dp->kd_length = sz; 161184588Sdfr dp->kd_data = malloc(sz, M_GSSAPI, M_WAITOK); 162184588Sdfr 163184588Sdfr if (*lenp < sz) 164184588Sdfr sz = *lenp; 165184588Sdfr bcopy(*pp, dp->kd_data, sz); 166184588Sdfr (*pp) += sz; 167184588Sdfr (*lenp) -= sz; 168184588Sdfr} 169184588Sdfr 170184588Sdfrstatic void 171184588Sdfrdelete_data(struct krb5_data *dp) 172184588Sdfr{ 173184588Sdfr if (dp->kd_data) { 174184588Sdfr free(dp->kd_data, M_GSSAPI); 175184588Sdfr dp->kd_length = 0; 176184588Sdfr dp->kd_data = NULL; 177184588Sdfr } 178184588Sdfr} 179184588Sdfr 180184588Sdfrstatic void 181184588Sdfrget_address(const uint8_t **pp, size_t *lenp, struct krb5_address *ka) 182184588Sdfr{ 183184588Sdfr 184184588Sdfr ka->ka_type = get_uint16(pp, lenp); 185184588Sdfr get_data(pp, lenp, &ka->ka_addr); 186184588Sdfr} 187184588Sdfr 188184588Sdfrstatic void 189184588Sdfrdelete_address(struct krb5_address *ka) 190184588Sdfr{ 191184588Sdfr delete_data(&ka->ka_addr); 192184588Sdfr} 193184588Sdfr 194184588Sdfrstatic void 195184588Sdfrget_keyblock(const uint8_t **pp, size_t *lenp, struct krb5_keyblock *kk) 196184588Sdfr{ 197184588Sdfr 198184588Sdfr kk->kk_type = get_uint16(pp, lenp); 199184588Sdfr get_data(pp, lenp, &kk->kk_key); 200184588Sdfr} 201184588Sdfr 202184588Sdfrstatic void 203184588Sdfrdelete_keyblock(struct krb5_keyblock *kk) 204184588Sdfr{ 205184588Sdfr if (kk->kk_key.kd_data) 206184588Sdfr bzero(kk->kk_key.kd_data, kk->kk_key.kd_length); 207184588Sdfr delete_data(&kk->kk_key); 208184588Sdfr} 209184588Sdfr 210184588Sdfrstatic void 211184588Sdfrcopy_key(struct krb5_keyblock *from, struct krb5_keyblock **to) 212184588Sdfr{ 213184588Sdfr 214184588Sdfr if (from->kk_key.kd_length) 215184588Sdfr *to = from; 216184588Sdfr else 217184588Sdfr *to = NULL; 218184588Sdfr} 219184588Sdfr 220184588Sdfr/* 221184588Sdfr * Return non-zero if we are initiator. 222184588Sdfr */ 223184588Sdfrstatic __inline int 224184588Sdfris_initiator(struct krb5_context *kc) 225184588Sdfr{ 226184588Sdfr return (kc->kc_more_flags & LOCAL); 227184588Sdfr} 228184588Sdfr 229184588Sdfr/* 230184588Sdfr * Return non-zero if we are acceptor. 231184588Sdfr */ 232184588Sdfrstatic __inline int 233184588Sdfris_acceptor(struct krb5_context *kc) 234184588Sdfr{ 235184588Sdfr return !(kc->kc_more_flags & LOCAL); 236184588Sdfr} 237184588Sdfr 238184588Sdfrstatic void 239184588Sdfrget_initiator_subkey(struct krb5_context *kc, struct krb5_keyblock **kdp) 240184588Sdfr{ 241184588Sdfr 242184588Sdfr if (is_initiator(kc)) 243184588Sdfr copy_key(&kc->kc_local_subkey, kdp); 244184588Sdfr else 245184588Sdfr copy_key(&kc->kc_remote_subkey, kdp); 246184588Sdfr if (!*kdp) 247184588Sdfr copy_key(&kc->kc_keyblock, kdp); 248184588Sdfr} 249184588Sdfr 250184588Sdfrstatic void 251184588Sdfrget_acceptor_subkey(struct krb5_context *kc, struct krb5_keyblock **kdp) 252184588Sdfr{ 253184588Sdfr 254184588Sdfr if (is_initiator(kc)) 255184588Sdfr copy_key(&kc->kc_remote_subkey, kdp); 256184588Sdfr else 257184588Sdfr copy_key(&kc->kc_local_subkey, kdp); 258184588Sdfr} 259184588Sdfr 260184588Sdfrstatic OM_uint32 261184588Sdfrget_keys(struct krb5_context *kc) 262184588Sdfr{ 263184588Sdfr struct krb5_keyblock *keydata; 264184588Sdfr struct krb5_encryption_class *ec; 265184588Sdfr struct krb5_key_state *key; 266184588Sdfr int etype; 267184588Sdfr 268184588Sdfr keydata = NULL; 269184588Sdfr get_acceptor_subkey(kc, &keydata); 270184588Sdfr if (!keydata) 271184588Sdfr if ((kc->kc_more_flags & ACCEPTOR_SUBKEY) == 0) 272184588Sdfr get_initiator_subkey(kc, &keydata); 273184588Sdfr if (!keydata) 274184588Sdfr return (GSS_S_FAILURE); 275184588Sdfr 276184588Sdfr /* 277184588Sdfr * GSS-API treats all DES etypes the same and all DES3 etypes 278184588Sdfr * the same. 279184588Sdfr */ 280184588Sdfr switch (keydata->kk_type) { 281184588Sdfr case ETYPE_DES_CBC_CRC: 282184588Sdfr case ETYPE_DES_CBC_MD4: 283184588Sdfr case ETYPE_DES_CBC_MD5: 284184588Sdfr etype = ETYPE_DES_CBC_CRC; 285184588Sdfr break; 286184588Sdfr 287184588Sdfr case ETYPE_DES3_CBC_MD5: 288184588Sdfr case ETYPE_DES3_CBC_SHA1: 289184588Sdfr case ETYPE_OLD_DES3_CBC_SHA1: 290184588Sdfr etype = ETYPE_DES3_CBC_SHA1; 291226185Sbrueffer break; 292184588Sdfr 293184588Sdfr default: 294184588Sdfr etype = keydata->kk_type; 295184588Sdfr } 296184588Sdfr 297184588Sdfr ec = krb5_find_encryption_class(etype); 298184588Sdfr if (!ec) 299184588Sdfr return (GSS_S_FAILURE); 300184588Sdfr 301184588Sdfr key = krb5_create_key(ec); 302184588Sdfr krb5_set_key(key, keydata->kk_key.kd_data); 303184588Sdfr kc->kc_tokenkey = key; 304184588Sdfr 305184588Sdfr switch (etype) { 306184588Sdfr case ETYPE_DES_CBC_CRC: 307184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5: 308184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5_56: { 309184588Sdfr /* 310184588Sdfr * Single DES and ARCFOUR uses a 'derived' key (XOR 311184588Sdfr * with 0xf0) for encrypting wrap tokens. The original 312184588Sdfr * key is used for checksums and sequence numbers. 313184588Sdfr */ 314184588Sdfr struct krb5_key_state *ekey; 315184588Sdfr uint8_t *ekp, *kp; 316184588Sdfr int i; 317184588Sdfr 318184588Sdfr ekey = krb5_create_key(ec); 319184588Sdfr ekp = ekey->ks_key; 320184588Sdfr kp = key->ks_key; 321184588Sdfr for (i = 0; i < ec->ec_keylen; i++) 322184588Sdfr ekp[i] = kp[i] ^ 0xf0; 323184588Sdfr krb5_set_key(ekey, ekp); 324184588Sdfr kc->kc_encryptkey = ekey; 325184588Sdfr refcount_acquire(&key->ks_refs); 326184588Sdfr kc->kc_checksumkey = key; 327184588Sdfr break; 328184588Sdfr } 329184588Sdfr 330184588Sdfr case ETYPE_DES3_CBC_SHA1: 331184588Sdfr /* 332184588Sdfr * Triple DES uses a RFC 3961 style derived key with 333184588Sdfr * usage number KG_USAGE_SIGN for checksums. The 334184588Sdfr * original key is used for encryption and sequence 335184588Sdfr * numbers. 336184588Sdfr */ 337184588Sdfr kc->kc_checksumkey = krb5_get_checksum_key(key, KG_USAGE_SIGN); 338184588Sdfr refcount_acquire(&key->ks_refs); 339184588Sdfr kc->kc_encryptkey = key; 340184588Sdfr break; 341184588Sdfr 342184588Sdfr default: 343184588Sdfr /* 344184588Sdfr * We need eight derived keys four for sending and 345184588Sdfr * four for receiving. 346184588Sdfr */ 347184588Sdfr if (is_initiator(kc)) { 348184588Sdfr /* 349184588Sdfr * We are initiator. 350184588Sdfr */ 351184588Sdfr kc->kc_send_seal_Ke = krb5_get_encryption_key(key, 352184588Sdfr KG_USAGE_INITIATOR_SEAL); 353184588Sdfr kc->kc_send_seal_Ki = krb5_get_integrity_key(key, 354184588Sdfr KG_USAGE_INITIATOR_SEAL); 355184588Sdfr kc->kc_send_seal_Kc = krb5_get_checksum_key(key, 356184588Sdfr KG_USAGE_INITIATOR_SEAL); 357184588Sdfr kc->kc_send_sign_Kc = krb5_get_checksum_key(key, 358184588Sdfr KG_USAGE_INITIATOR_SIGN); 359184588Sdfr 360184588Sdfr kc->kc_recv_seal_Ke = krb5_get_encryption_key(key, 361184588Sdfr KG_USAGE_ACCEPTOR_SEAL); 362184588Sdfr kc->kc_recv_seal_Ki = krb5_get_integrity_key(key, 363184588Sdfr KG_USAGE_ACCEPTOR_SEAL); 364184588Sdfr kc->kc_recv_seal_Kc = krb5_get_checksum_key(key, 365184588Sdfr KG_USAGE_ACCEPTOR_SEAL); 366184588Sdfr kc->kc_recv_sign_Kc = krb5_get_checksum_key(key, 367184588Sdfr KG_USAGE_ACCEPTOR_SIGN); 368184588Sdfr } else { 369184588Sdfr /* 370184588Sdfr * We are acceptor. 371184588Sdfr */ 372184588Sdfr kc->kc_send_seal_Ke = krb5_get_encryption_key(key, 373184588Sdfr KG_USAGE_ACCEPTOR_SEAL); 374184588Sdfr kc->kc_send_seal_Ki = krb5_get_integrity_key(key, 375184588Sdfr KG_USAGE_ACCEPTOR_SEAL); 376184588Sdfr kc->kc_send_seal_Kc = krb5_get_checksum_key(key, 377184588Sdfr KG_USAGE_ACCEPTOR_SEAL); 378184588Sdfr kc->kc_send_sign_Kc = krb5_get_checksum_key(key, 379184588Sdfr KG_USAGE_ACCEPTOR_SIGN); 380184588Sdfr 381184588Sdfr kc->kc_recv_seal_Ke = krb5_get_encryption_key(key, 382184588Sdfr KG_USAGE_INITIATOR_SEAL); 383184588Sdfr kc->kc_recv_seal_Ki = krb5_get_integrity_key(key, 384184588Sdfr KG_USAGE_INITIATOR_SEAL); 385184588Sdfr kc->kc_recv_seal_Kc = krb5_get_checksum_key(key, 386184588Sdfr KG_USAGE_INITIATOR_SEAL); 387184588Sdfr kc->kc_recv_sign_Kc = krb5_get_checksum_key(key, 388184588Sdfr KG_USAGE_INITIATOR_SIGN); 389184588Sdfr } 390184588Sdfr break; 391184588Sdfr } 392184588Sdfr 393184588Sdfr return (GSS_S_COMPLETE); 394184588Sdfr} 395184588Sdfr 396184588Sdfrstatic void 397194202Srmacklemkrb5_init(gss_ctx_id_t ctx) 398184588Sdfr{ 399194202Srmacklem struct krb5_context *kc = (struct krb5_context *)ctx; 400184588Sdfr 401184588Sdfr mtx_init(&kc->kc_lock, "krb5 gss lock", NULL, MTX_DEF); 402184588Sdfr} 403184588Sdfr 404184588Sdfrstatic OM_uint32 405194202Srmacklemkrb5_import(gss_ctx_id_t ctx, 406184588Sdfr enum sec_context_format format, 407184588Sdfr const gss_buffer_t context_token) 408184588Sdfr{ 409194202Srmacklem struct krb5_context *kc = (struct krb5_context *)ctx; 410184588Sdfr OM_uint32 res; 411184588Sdfr const uint8_t *p = (const uint8_t *) context_token->value; 412184588Sdfr size_t len = context_token->length; 413184588Sdfr uint32_t flags; 414184588Sdfr int i; 415184588Sdfr 416184588Sdfr /* 417184588Sdfr * We support heimdal 0.6 and heimdal 1.1 418184588Sdfr */ 419184588Sdfr if (format != KGSS_HEIMDAL_0_6 && format != KGSS_HEIMDAL_1_1) 420184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 421184588Sdfr 422184588Sdfr#define SC_LOCAL_ADDRESS 1 423184588Sdfr#define SC_REMOTE_ADDRESS 2 424184588Sdfr#define SC_KEYBLOCK 4 425184588Sdfr#define SC_LOCAL_SUBKEY 8 426184588Sdfr#define SC_REMOTE_SUBKEY 16 427184588Sdfr 428184588Sdfr /* 429184588Sdfr * Ensure that the token starts with krb5 oid. 430184588Sdfr */ 431184588Sdfr if (p[0] != 0x00 || p[1] != krb5_mech_oid.length 432184588Sdfr || len < krb5_mech_oid.length + 2 433184588Sdfr || bcmp(krb5_mech_oid.elements, p + 2, 434184588Sdfr krb5_mech_oid.length)) 435184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 436184588Sdfr p += krb5_mech_oid.length + 2; 437184588Sdfr len -= krb5_mech_oid.length + 2; 438184588Sdfr 439184588Sdfr flags = get_uint32(&p, &len); 440184588Sdfr kc->kc_ac_flags = get_uint32(&p, &len); 441184588Sdfr if (flags & SC_LOCAL_ADDRESS) 442184588Sdfr get_address(&p, &len, &kc->kc_local_address); 443184588Sdfr if (flags & SC_REMOTE_ADDRESS) 444184588Sdfr get_address(&p, &len, &kc->kc_remote_address); 445184588Sdfr kc->kc_local_port = get_uint16(&p, &len); 446184588Sdfr kc->kc_remote_port = get_uint16(&p, &len); 447184588Sdfr if (flags & SC_KEYBLOCK) 448184588Sdfr get_keyblock(&p, &len, &kc->kc_keyblock); 449184588Sdfr if (flags & SC_LOCAL_SUBKEY) 450184588Sdfr get_keyblock(&p, &len, &kc->kc_local_subkey); 451184588Sdfr if (flags & SC_REMOTE_SUBKEY) 452184588Sdfr get_keyblock(&p, &len, &kc->kc_remote_subkey); 453184588Sdfr kc->kc_local_seqnumber = get_uint32(&p, &len); 454184588Sdfr kc->kc_remote_seqnumber = get_uint32(&p, &len); 455184588Sdfr kc->kc_keytype = get_uint32(&p, &len); 456184588Sdfr kc->kc_cksumtype = get_uint32(&p, &len); 457184588Sdfr get_data(&p, &len, &kc->kc_source_name); 458184588Sdfr get_data(&p, &len, &kc->kc_target_name); 459184588Sdfr kc->kc_ctx_flags = get_uint32(&p, &len); 460184588Sdfr kc->kc_more_flags = get_uint32(&p, &len); 461184588Sdfr kc->kc_lifetime = get_uint32(&p, &len); 462184588Sdfr /* 463184588Sdfr * Heimdal 1.1 adds the message order stuff. 464184588Sdfr */ 465184588Sdfr if (format == KGSS_HEIMDAL_1_1) { 466184588Sdfr kc->kc_msg_order.km_flags = get_uint32(&p, &len); 467184588Sdfr kc->kc_msg_order.km_start = get_uint32(&p, &len); 468184588Sdfr kc->kc_msg_order.km_length = get_uint32(&p, &len); 469184588Sdfr kc->kc_msg_order.km_jitter_window = get_uint32(&p, &len); 470184588Sdfr kc->kc_msg_order.km_first_seq = get_uint32(&p, &len); 471184588Sdfr kc->kc_msg_order.km_elem = 472184588Sdfr malloc(kc->kc_msg_order.km_jitter_window * sizeof(uint32_t), 473184588Sdfr M_GSSAPI, M_WAITOK); 474184588Sdfr for (i = 0; i < kc->kc_msg_order.km_jitter_window; i++) 475184588Sdfr kc->kc_msg_order.km_elem[i] = get_uint32(&p, &len); 476184588Sdfr } else { 477184588Sdfr kc->kc_msg_order.km_flags = 0; 478184588Sdfr } 479184588Sdfr 480184588Sdfr res = get_keys(kc); 481184588Sdfr if (GSS_ERROR(res)) 482184588Sdfr return (res); 483184588Sdfr 484184588Sdfr /* 485184588Sdfr * We don't need these anymore. 486184588Sdfr */ 487184588Sdfr delete_keyblock(&kc->kc_keyblock); 488184588Sdfr delete_keyblock(&kc->kc_local_subkey); 489184588Sdfr delete_keyblock(&kc->kc_remote_subkey); 490184588Sdfr 491184588Sdfr return (GSS_S_COMPLETE); 492184588Sdfr} 493184588Sdfr 494184588Sdfrstatic void 495194202Srmacklemkrb5_delete(gss_ctx_id_t ctx, gss_buffer_t output_token) 496184588Sdfr{ 497194202Srmacklem struct krb5_context *kc = (struct krb5_context *)ctx; 498184588Sdfr 499184588Sdfr delete_address(&kc->kc_local_address); 500184588Sdfr delete_address(&kc->kc_remote_address); 501184588Sdfr delete_keyblock(&kc->kc_keyblock); 502184588Sdfr delete_keyblock(&kc->kc_local_subkey); 503184588Sdfr delete_keyblock(&kc->kc_remote_subkey); 504184588Sdfr delete_data(&kc->kc_source_name); 505184588Sdfr delete_data(&kc->kc_target_name); 506184588Sdfr if (kc->kc_msg_order.km_elem) 507184588Sdfr free(kc->kc_msg_order.km_elem, M_GSSAPI); 508184588Sdfr if (output_token) { 509184588Sdfr output_token->length = 0; 510184588Sdfr output_token->value = NULL; 511184588Sdfr } 512184588Sdfr if (kc->kc_tokenkey) { 513184588Sdfr krb5_free_key(kc->kc_tokenkey); 514184588Sdfr if (kc->kc_encryptkey) { 515184588Sdfr krb5_free_key(kc->kc_encryptkey); 516184588Sdfr krb5_free_key(kc->kc_checksumkey); 517184588Sdfr } else { 518184588Sdfr krb5_free_key(kc->kc_send_seal_Ke); 519184588Sdfr krb5_free_key(kc->kc_send_seal_Ki); 520184588Sdfr krb5_free_key(kc->kc_send_seal_Kc); 521184588Sdfr krb5_free_key(kc->kc_send_sign_Kc); 522184588Sdfr krb5_free_key(kc->kc_recv_seal_Ke); 523184588Sdfr krb5_free_key(kc->kc_recv_seal_Ki); 524184588Sdfr krb5_free_key(kc->kc_recv_seal_Kc); 525184588Sdfr krb5_free_key(kc->kc_recv_sign_Kc); 526184588Sdfr } 527184588Sdfr } 528184588Sdfr mtx_destroy(&kc->kc_lock); 529184588Sdfr} 530184588Sdfr 531184588Sdfrstatic gss_OID 532194202Srmacklemkrb5_mech_type(gss_ctx_id_t ctx) 533184588Sdfr{ 534184588Sdfr 535184588Sdfr return (&krb5_mech_oid); 536184588Sdfr} 537184588Sdfr 538184588Sdfr/* 539184588Sdfr * Make a token with the given type and length (the length includes 540184588Sdfr * the TOK_ID), initialising the token header appropriately. Return a 541184588Sdfr * pointer to the TOK_ID of the token. A new mbuf is allocated with 542184588Sdfr * the framing header plus hlen bytes of space. 543184588Sdfr * 544184588Sdfr * Format is as follows: 545184588Sdfr * 546184588Sdfr * 0x60 [APPLICATION 0] SEQUENCE 547184588Sdfr * DER encoded length length of oid + type + inner token length 548184588Sdfr * 0x06 NN <oid data> OID of mechanism type 549184588Sdfr * TT TT TOK_ID 550184588Sdfr * <inner token> data for inner token 551184588Sdfr * 552184588Sdfr * 1: der encoded length 553184588Sdfr */ 554184588Sdfrstatic void * 555184588Sdfrkrb5_make_token(char tok_id[2], size_t hlen, size_t len, struct mbuf **mp) 556184588Sdfr{ 557184588Sdfr size_t inside_len, len_len, tlen; 558184588Sdfr gss_OID oid = &krb5_mech_oid; 559184588Sdfr struct mbuf *m; 560184588Sdfr uint8_t *p; 561184588Sdfr 562184588Sdfr inside_len = 2 + oid->length + len; 563184588Sdfr if (inside_len < 128) 564184588Sdfr len_len = 1; 565184588Sdfr else if (inside_len < 0x100) 566184588Sdfr len_len = 2; 567184588Sdfr else if (inside_len < 0x10000) 568184588Sdfr len_len = 3; 569184588Sdfr else if (inside_len < 0x1000000) 570184588Sdfr len_len = 4; 571184588Sdfr else 572184588Sdfr len_len = 5; 573184588Sdfr 574184588Sdfr tlen = 1 + len_len + 2 + oid->length + hlen; 575184588Sdfr KASSERT(tlen <= MLEN, ("token head too large")); 576184588Sdfr MGET(m, M_WAITOK, MT_DATA); 577184588Sdfr M_ALIGN(m, tlen); 578184588Sdfr m->m_len = tlen; 579184588Sdfr 580184588Sdfr p = (uint8_t *) m->m_data; 581184588Sdfr *p++ = 0x60; 582184588Sdfr switch (len_len) { 583184588Sdfr case 1: 584184588Sdfr *p++ = inside_len; 585184588Sdfr break; 586184588Sdfr case 2: 587184588Sdfr *p++ = 0x81; 588184588Sdfr *p++ = inside_len; 589184588Sdfr break; 590184588Sdfr case 3: 591184588Sdfr *p++ = 0x82; 592184588Sdfr *p++ = inside_len >> 8; 593184588Sdfr *p++ = inside_len; 594184588Sdfr break; 595184588Sdfr case 4: 596184588Sdfr *p++ = 0x83; 597184588Sdfr *p++ = inside_len >> 16; 598184588Sdfr *p++ = inside_len >> 8; 599184588Sdfr *p++ = inside_len; 600184588Sdfr break; 601184588Sdfr case 5: 602184588Sdfr *p++ = 0x84; 603184588Sdfr *p++ = inside_len >> 24; 604184588Sdfr *p++ = inside_len >> 16; 605184588Sdfr *p++ = inside_len >> 8; 606184588Sdfr *p++ = inside_len; 607184588Sdfr break; 608184588Sdfr } 609184588Sdfr 610184588Sdfr *p++ = 0x06; 611184588Sdfr *p++ = oid->length; 612184588Sdfr bcopy(oid->elements, p, oid->length); 613184588Sdfr p += oid->length; 614184588Sdfr 615184588Sdfr p[0] = tok_id[0]; 616184588Sdfr p[1] = tok_id[1]; 617184588Sdfr 618184588Sdfr *mp = m; 619184588Sdfr 620184588Sdfr return (p); 621184588Sdfr} 622184588Sdfr 623184588Sdfr/* 624184588Sdfr * Verify a token, checking the inner token length and mechanism oid. 625184588Sdfr * pointer to the first byte of the TOK_ID. The length of the 626184588Sdfr * encapsulated data is checked to be at least len bytes; the actual 627184588Sdfr * length of the encapsulated data (including TOK_ID) is returned in 628184588Sdfr * *encap_len. 629184588Sdfr * 630184588Sdfr * If can_pullup is TRUE and the token header is fragmented, we will 631184588Sdfr * rearrange it. 632184588Sdfr * 633184588Sdfr * Format is as follows: 634184588Sdfr * 635184588Sdfr * 0x60 [APPLICATION 0] SEQUENCE 636184588Sdfr * DER encoded length length of oid + type + inner token length 637184588Sdfr * 0x06 NN <oid data> OID of mechanism type 638184588Sdfr * TT TT TOK_ID 639184588Sdfr * <inner token> data for inner token 640184588Sdfr * 641184588Sdfr * 1: der encoded length 642184588Sdfr */ 643184588Sdfrstatic void * 644184588Sdfrkrb5_verify_token(char tok_id[2], size_t len, struct mbuf **mp, 645184588Sdfr size_t *encap_len, bool_t can_pullup) 646184588Sdfr{ 647184588Sdfr struct mbuf *m; 648184588Sdfr size_t tlen, hlen, len_len, inside_len; 649184588Sdfr gss_OID oid = &krb5_mech_oid; 650184588Sdfr uint8_t *p; 651184588Sdfr 652184588Sdfr m = *mp; 653184588Sdfr tlen = m_length(m, NULL); 654184588Sdfr if (tlen < 2) 655184588Sdfr return (NULL); 656184588Sdfr 657184588Sdfr /* 658184588Sdfr * Ensure that at least the framing part of the token is 659184588Sdfr * contigous. 660184588Sdfr */ 661184588Sdfr if (m->m_len < 2) { 662184588Sdfr if (can_pullup) 663184588Sdfr *mp = m = m_pullup(m, 2); 664184588Sdfr else 665184588Sdfr return (NULL); 666184588Sdfr } 667184588Sdfr 668184588Sdfr p = m->m_data; 669184588Sdfr 670184588Sdfr if (*p++ != 0x60) 671184588Sdfr return (NULL); 672184588Sdfr 673184588Sdfr if (*p < 0x80) { 674184588Sdfr inside_len = *p++; 675184588Sdfr len_len = 1; 676184588Sdfr } else { 677184588Sdfr /* 678184588Sdfr * Ensure there is enough space for the DER encoded length. 679184588Sdfr */ 680184588Sdfr len_len = (*p & 0x7f) + 1; 681184588Sdfr if (tlen < len_len + 1) 682184588Sdfr return (NULL); 683184588Sdfr if (m->m_len < len_len + 1) { 684184588Sdfr if (can_pullup) 685184588Sdfr *mp = m = m_pullup(m, len_len + 1); 686184588Sdfr else 687184588Sdfr return (NULL); 688184588Sdfr p = m->m_data + 1; 689184588Sdfr } 690184588Sdfr 691184588Sdfr switch (*p++) { 692184588Sdfr case 0x81: 693184588Sdfr inside_len = *p++; 694184588Sdfr break; 695184588Sdfr 696184588Sdfr case 0x82: 697184588Sdfr inside_len = (p[0] << 8) | p[1]; 698184588Sdfr p += 2; 699184588Sdfr break; 700184588Sdfr 701184588Sdfr case 0x83: 702184588Sdfr inside_len = (p[0] << 16) | (p[1] << 8) | p[2]; 703184588Sdfr p += 3; 704184588Sdfr break; 705184588Sdfr 706184588Sdfr case 0x84: 707184588Sdfr inside_len = (p[0] << 24) | (p[1] << 16) 708184588Sdfr | (p[2] << 8) | p[3]; 709184588Sdfr p += 4; 710184588Sdfr break; 711184588Sdfr 712184588Sdfr default: 713184588Sdfr return (NULL); 714184588Sdfr } 715184588Sdfr } 716184588Sdfr 717184588Sdfr if (tlen != inside_len + len_len + 1) 718184588Sdfr return (NULL); 719184588Sdfr if (inside_len < 2 + oid->length + len) 720184588Sdfr return (NULL); 721184588Sdfr 722184588Sdfr /* 723184588Sdfr * Now that we know the value of len_len, we can pullup the 724184588Sdfr * whole header. The header is 1 + len_len + 2 + oid->length + 725184588Sdfr * len bytes. 726184588Sdfr */ 727184588Sdfr hlen = 1 + len_len + 2 + oid->length + len; 728184588Sdfr if (m->m_len < hlen) { 729184588Sdfr if (can_pullup) 730184588Sdfr *mp = m = m_pullup(m, hlen); 731184588Sdfr else 732184588Sdfr return (NULL); 733184588Sdfr p = m->m_data + 1 + len_len; 734184588Sdfr } 735184588Sdfr 736184588Sdfr if (*p++ != 0x06) 737184588Sdfr return (NULL); 738184588Sdfr if (*p++ != oid->length) 739184588Sdfr return (NULL); 740184588Sdfr if (bcmp(oid->elements, p, oid->length)) 741184588Sdfr return (NULL); 742184588Sdfr p += oid->length; 743184588Sdfr 744184588Sdfr if (p[0] != tok_id[0]) 745184588Sdfr return (NULL); 746184588Sdfr 747184588Sdfr if (p[1] != tok_id[1]) 748184588Sdfr return (NULL); 749184588Sdfr 750184588Sdfr *encap_len = inside_len - 2 - oid->length; 751184588Sdfr 752184588Sdfr return (p); 753184588Sdfr} 754184588Sdfr 755184588Sdfrstatic void 756184588Sdfrkrb5_insert_seq(struct krb5_msg_order *mo, uint32_t seq, int index) 757184588Sdfr{ 758184588Sdfr int i; 759184588Sdfr 760184588Sdfr if (mo->km_length < mo->km_jitter_window) 761184588Sdfr mo->km_length++; 762184588Sdfr 763184588Sdfr for (i = mo->km_length - 1; i > index; i--) 764184588Sdfr mo->km_elem[i] = mo->km_elem[i - 1]; 765184588Sdfr mo->km_elem[index] = seq; 766184588Sdfr} 767184588Sdfr 768184588Sdfr/* 769184588Sdfr * Check sequence numbers according to RFC 2743 section 1.2.3. 770184588Sdfr */ 771184588Sdfrstatic OM_uint32 772184588Sdfrkrb5_sequence_check(struct krb5_context *kc, uint32_t seq) 773184588Sdfr{ 774184588Sdfr OM_uint32 res = GSS_S_FAILURE; 775184588Sdfr struct krb5_msg_order *mo = &kc->kc_msg_order; 776184588Sdfr int check_sequence = mo->km_flags & GSS_C_SEQUENCE_FLAG; 777184588Sdfr int check_replay = mo->km_flags & GSS_C_REPLAY_FLAG; 778184588Sdfr int i; 779184588Sdfr 780184588Sdfr mtx_lock(&kc->kc_lock); 781184588Sdfr 782184588Sdfr /* 783184588Sdfr * Message is in-sequence with no gap. 784184588Sdfr */ 785184588Sdfr if (mo->km_length == 0 || seq == mo->km_elem[0] + 1) { 786184588Sdfr /* 787184588Sdfr * This message is received in-sequence with no gaps. 788184588Sdfr */ 789184588Sdfr krb5_insert_seq(mo, seq, 0); 790184588Sdfr res = GSS_S_COMPLETE; 791184588Sdfr goto out; 792184588Sdfr } 793184588Sdfr 794184588Sdfr if (seq > mo->km_elem[0]) { 795184588Sdfr /* 796184588Sdfr * This message is received in-sequence with a gap. 797184588Sdfr */ 798184588Sdfr krb5_insert_seq(mo, seq, 0); 799184588Sdfr if (check_sequence) 800184588Sdfr res = GSS_S_GAP_TOKEN; 801184588Sdfr else 802184588Sdfr res = GSS_S_COMPLETE; 803184588Sdfr goto out; 804184588Sdfr } 805184588Sdfr 806184588Sdfr if (seq < mo->km_elem[mo->km_length - 1]) { 807184588Sdfr if (check_replay && !check_sequence) 808184588Sdfr res = GSS_S_OLD_TOKEN; 809184588Sdfr else 810184588Sdfr res = GSS_S_UNSEQ_TOKEN; 811184588Sdfr goto out; 812184588Sdfr } 813184588Sdfr 814184588Sdfr for (i = 0; i < mo->km_length; i++) { 815184588Sdfr if (mo->km_elem[i] == seq) { 816184588Sdfr res = GSS_S_DUPLICATE_TOKEN; 817184588Sdfr goto out; 818184588Sdfr } 819184588Sdfr if (mo->km_elem[i] < seq) { 820184588Sdfr /* 821184588Sdfr * We need to insert this seq here, 822184588Sdfr */ 823184588Sdfr krb5_insert_seq(mo, seq, i); 824184588Sdfr if (check_replay && !check_sequence) 825184588Sdfr res = GSS_S_COMPLETE; 826184588Sdfr else 827184588Sdfr res = GSS_S_UNSEQ_TOKEN; 828184588Sdfr goto out; 829184588Sdfr } 830184588Sdfr } 831184588Sdfr 832184588Sdfrout: 833184588Sdfr mtx_unlock(&kc->kc_lock); 834184588Sdfr 835184588Sdfr return (res); 836184588Sdfr} 837184588Sdfr 838184588Sdfrstatic uint8_t sgn_alg_des_md5[] = { 0x00, 0x00 }; 839184588Sdfrstatic uint8_t seal_alg_des[] = { 0x00, 0x00 }; 840184588Sdfrstatic uint8_t sgn_alg_des3_sha1[] = { 0x04, 0x00 }; 841184588Sdfrstatic uint8_t seal_alg_des3[] = { 0x02, 0x00 }; 842184588Sdfrstatic uint8_t seal_alg_rc4[] = { 0x10, 0x00 }; 843184588Sdfrstatic uint8_t sgn_alg_hmac_md5[] = { 0x11, 0x00 }; 844184588Sdfr 845184588Sdfr/* 846184588Sdfr * Return the size of the inner token given the use of the key's 847184588Sdfr * encryption class. For wrap tokens, the length of the padded 848184588Sdfr * plaintext will be added to this. 849184588Sdfr */ 850184588Sdfrstatic size_t 851184588Sdfrtoken_length(struct krb5_key_state *key) 852184588Sdfr{ 853184588Sdfr 854184588Sdfr return (16 + key->ks_class->ec_checksumlen); 855184588Sdfr} 856184588Sdfr 857184588Sdfrstatic OM_uint32 858184588Sdfrkrb5_get_mic_old(struct krb5_context *kc, struct mbuf *m, 859184588Sdfr struct mbuf **micp, uint8_t sgn_alg[2]) 860184588Sdfr{ 861184588Sdfr struct mbuf *mlast, *mic, *tm; 862184588Sdfr uint8_t *p, dir; 863184588Sdfr size_t tlen, mlen, cklen; 864184588Sdfr uint32_t seq; 865184588Sdfr char buf[8]; 866184588Sdfr 867184588Sdfr mlen = m_length(m, &mlast); 868184588Sdfr 869184588Sdfr tlen = token_length(kc->kc_tokenkey); 870184588Sdfr p = krb5_make_token("\x01\x01", tlen, tlen, &mic); 871184588Sdfr p += 2; /* TOK_ID */ 872184588Sdfr *p++ = sgn_alg[0]; /* SGN_ALG */ 873184588Sdfr *p++ = sgn_alg[1]; 874184588Sdfr 875184588Sdfr *p++ = 0xff; /* filler */ 876184588Sdfr *p++ = 0xff; 877184588Sdfr *p++ = 0xff; 878184588Sdfr *p++ = 0xff; 879184588Sdfr 880184588Sdfr /* 881184588Sdfr * SGN_CKSUM: 882184588Sdfr * 883184588Sdfr * Calculate the keyed checksum of the token header plus the 884184588Sdfr * message. 885184588Sdfr */ 886184588Sdfr cklen = kc->kc_checksumkey->ks_class->ec_checksumlen; 887184588Sdfr 888184588Sdfr mic->m_len = p - (uint8_t *) mic->m_data; 889184588Sdfr mic->m_next = m; 890184588Sdfr MGET(tm, M_WAITOK, MT_DATA); 891184588Sdfr tm->m_len = cklen; 892184588Sdfr mlast->m_next = tm; 893184588Sdfr 894184588Sdfr krb5_checksum(kc->kc_checksumkey, 15, mic, mic->m_len - 8, 895184588Sdfr 8 + mlen, cklen); 896184588Sdfr bcopy(tm->m_data, p + 8, cklen); 897184588Sdfr mic->m_next = NULL; 898184588Sdfr mlast->m_next = NULL; 899184588Sdfr m_free(tm); 900184588Sdfr 901184588Sdfr /* 902184588Sdfr * SND_SEQ: 903184588Sdfr * 904184588Sdfr * Take the four bytes of the sequence number least 905184588Sdfr * significant first followed by four bytes of direction 906184588Sdfr * marker (zero for initiator and 0xff for acceptor). Encrypt 907184588Sdfr * that data using the SGN_CKSUM as IV. Note: ARC4 wants the 908184588Sdfr * sequence number big-endian. 909184588Sdfr */ 910184588Sdfr seq = atomic_fetchadd_32(&kc->kc_local_seqnumber, 1); 911184588Sdfr if (sgn_alg[0] == 0x11) { 912184588Sdfr p[0] = (seq >> 24); 913184588Sdfr p[1] = (seq >> 16); 914184588Sdfr p[2] = (seq >> 8); 915184588Sdfr p[3] = (seq >> 0); 916184588Sdfr } else { 917184588Sdfr p[0] = (seq >> 0); 918184588Sdfr p[1] = (seq >> 8); 919184588Sdfr p[2] = (seq >> 16); 920184588Sdfr p[3] = (seq >> 24); 921184588Sdfr } 922184588Sdfr if (is_initiator(kc)) { 923184588Sdfr dir = 0; 924184588Sdfr } else { 925184588Sdfr dir = 0xff; 926184588Sdfr } 927184588Sdfr p[4] = dir; 928184588Sdfr p[5] = dir; 929184588Sdfr p[6] = dir; 930184588Sdfr p[7] = dir; 931184588Sdfr bcopy(p + 8, buf, 8); 932184588Sdfr 933184588Sdfr /* 934184588Sdfr * Set the mic buffer to its final size so that the encrypt 935184588Sdfr * can see the SND_SEQ part. 936184588Sdfr */ 937184588Sdfr mic->m_len += 8 + cklen; 938184588Sdfr krb5_encrypt(kc->kc_tokenkey, mic, mic->m_len - cklen - 8, 8, buf, 8); 939184588Sdfr 940184588Sdfr *micp = mic; 941184588Sdfr return (GSS_S_COMPLETE); 942184588Sdfr} 943184588Sdfr 944184588Sdfrstatic OM_uint32 945184588Sdfrkrb5_get_mic_new(struct krb5_context *kc, struct mbuf *m, 946184588Sdfr struct mbuf **micp) 947184588Sdfr{ 948184588Sdfr struct krb5_key_state *key = kc->kc_send_sign_Kc; 949184588Sdfr struct mbuf *mlast, *mic; 950184588Sdfr uint8_t *p; 951184588Sdfr int flags; 952184588Sdfr size_t mlen, cklen; 953184588Sdfr uint32_t seq; 954184588Sdfr 955184588Sdfr mlen = m_length(m, &mlast); 956184588Sdfr cklen = key->ks_class->ec_checksumlen; 957184588Sdfr 958184588Sdfr KASSERT(16 + cklen <= MLEN, ("checksum too large for an mbuf")); 959184588Sdfr MGET(mic, M_WAITOK, MT_DATA); 960184588Sdfr M_ALIGN(mic, 16 + cklen); 961184588Sdfr mic->m_len = 16 + cklen; 962184588Sdfr p = mic->m_data; 963184588Sdfr 964184588Sdfr /* TOK_ID */ 965184588Sdfr p[0] = 0x04; 966184588Sdfr p[1] = 0x04; 967184588Sdfr 968184588Sdfr /* Flags */ 969184588Sdfr flags = 0; 970184588Sdfr if (is_acceptor(kc)) 971184588Sdfr flags |= GSS_TOKEN_SENT_BY_ACCEPTOR; 972184588Sdfr if (kc->kc_more_flags & ACCEPTOR_SUBKEY) 973184588Sdfr flags |= GSS_TOKEN_ACCEPTOR_SUBKEY; 974184588Sdfr p[2] = flags; 975184588Sdfr 976184588Sdfr /* Filler */ 977184588Sdfr p[3] = 0xff; 978184588Sdfr p[4] = 0xff; 979184588Sdfr p[5] = 0xff; 980184588Sdfr p[6] = 0xff; 981184588Sdfr p[7] = 0xff; 982184588Sdfr 983184588Sdfr /* SND_SEQ */ 984184588Sdfr p[8] = 0; 985184588Sdfr p[9] = 0; 986184588Sdfr p[10] = 0; 987184588Sdfr p[11] = 0; 988184588Sdfr seq = atomic_fetchadd_32(&kc->kc_local_seqnumber, 1); 989184588Sdfr p[12] = (seq >> 24); 990184588Sdfr p[13] = (seq >> 16); 991184588Sdfr p[14] = (seq >> 8); 992184588Sdfr p[15] = (seq >> 0); 993184588Sdfr 994184588Sdfr /* 995184588Sdfr * SGN_CKSUM: 996184588Sdfr * 997184588Sdfr * Calculate the keyed checksum of the message plus the first 998184588Sdfr * 16 bytes of the token header. 999184588Sdfr */ 1000184588Sdfr mlast->m_next = mic; 1001184588Sdfr krb5_checksum(key, 0, m, 0, mlen + 16, cklen); 1002184588Sdfr mlast->m_next = NULL; 1003184588Sdfr 1004184588Sdfr *micp = mic; 1005184588Sdfr return (GSS_S_COMPLETE); 1006184588Sdfr} 1007184588Sdfr 1008184588Sdfrstatic OM_uint32 1009194202Srmacklemkrb5_get_mic(gss_ctx_id_t ctx, OM_uint32 *minor_status, 1010184588Sdfr gss_qop_t qop_req, struct mbuf *m, struct mbuf **micp) 1011184588Sdfr{ 1012194202Srmacklem struct krb5_context *kc = (struct krb5_context *)ctx; 1013184588Sdfr 1014184588Sdfr *minor_status = 0; 1015184588Sdfr 1016184588Sdfr if (qop_req != GSS_C_QOP_DEFAULT) 1017184588Sdfr return (GSS_S_BAD_QOP); 1018184588Sdfr 1019184588Sdfr if (time_uptime > kc->kc_lifetime) 1020184588Sdfr return (GSS_S_CONTEXT_EXPIRED); 1021184588Sdfr 1022184588Sdfr switch (kc->kc_tokenkey->ks_class->ec_type) { 1023184588Sdfr case ETYPE_DES_CBC_CRC: 1024184588Sdfr return (krb5_get_mic_old(kc, m, micp, sgn_alg_des_md5)); 1025184588Sdfr 1026184588Sdfr case ETYPE_DES3_CBC_SHA1: 1027184588Sdfr return (krb5_get_mic_old(kc, m, micp, sgn_alg_des3_sha1)); 1028184588Sdfr 1029184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5: 1030184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5_56: 1031184588Sdfr return (krb5_get_mic_old(kc, m, micp, sgn_alg_hmac_md5)); 1032184588Sdfr 1033184588Sdfr default: 1034184588Sdfr return (krb5_get_mic_new(kc, m, micp)); 1035184588Sdfr } 1036184588Sdfr 1037184588Sdfr return (GSS_S_FAILURE); 1038184588Sdfr} 1039184588Sdfr 1040184588Sdfrstatic OM_uint32 1041184588Sdfrkrb5_verify_mic_old(struct krb5_context *kc, struct mbuf *m, struct mbuf *mic, 1042184588Sdfr uint8_t sgn_alg[2]) 1043184588Sdfr{ 1044184588Sdfr struct mbuf *mlast, *tm; 1045184588Sdfr uint8_t *p, *tp, dir; 1046184588Sdfr size_t mlen, tlen, elen, miclen; 1047184588Sdfr size_t cklen; 1048184588Sdfr uint32_t seq; 1049184588Sdfr 1050184588Sdfr mlen = m_length(m, &mlast); 1051184588Sdfr 1052184588Sdfr tlen = token_length(kc->kc_tokenkey); 1053184588Sdfr p = krb5_verify_token("\x01\x01", tlen, &mic, &elen, FALSE); 1054184588Sdfr if (!p) 1055184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1056184588Sdfr#if 0 1057184588Sdfr /* 1058184588Sdfr * Disable this check - heimdal-1.1 generates DES3 MIC tokens 1059184588Sdfr * that are 2 bytes too big. 1060184588Sdfr */ 1061184588Sdfr if (elen != tlen) 1062184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1063184588Sdfr#endif 1064184588Sdfr /* TOK_ID */ 1065184588Sdfr p += 2; 1066184588Sdfr 1067184588Sdfr /* SGN_ALG */ 1068184588Sdfr if (p[0] != sgn_alg[0] || p[1] != sgn_alg[1]) 1069184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1070184588Sdfr p += 2; 1071184588Sdfr 1072184588Sdfr if (p[0] != 0xff || p[1] != 0xff || p[2] != 0xff || p[3] != 0xff) 1073184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1074184588Sdfr p += 4; 1075184588Sdfr 1076184588Sdfr /* 1077184588Sdfr * SGN_CKSUM: 1078184588Sdfr * 1079184588Sdfr * Calculate the keyed checksum of the token header plus the 1080184588Sdfr * message. 1081184588Sdfr */ 1082184588Sdfr cklen = kc->kc_checksumkey->ks_class->ec_checksumlen; 1083184588Sdfr miclen = mic->m_len; 1084184588Sdfr mic->m_len = p - (uint8_t *) mic->m_data; 1085184588Sdfr mic->m_next = m; 1086184588Sdfr MGET(tm, M_WAITOK, MT_DATA); 1087184588Sdfr tm->m_len = cklen; 1088184588Sdfr mlast->m_next = tm; 1089184588Sdfr 1090184588Sdfr krb5_checksum(kc->kc_checksumkey, 15, mic, mic->m_len - 8, 1091184588Sdfr 8 + mlen, cklen); 1092184588Sdfr mic->m_next = NULL; 1093184588Sdfr mlast->m_next = NULL; 1094184588Sdfr if (bcmp(tm->m_data, p + 8, cklen)) { 1095184588Sdfr m_free(tm); 1096184588Sdfr return (GSS_S_BAD_SIG); 1097184588Sdfr } 1098184588Sdfr 1099184588Sdfr /* 1100184588Sdfr * SND_SEQ: 1101184588Sdfr * 1102184588Sdfr * Take the four bytes of the sequence number least 1103184588Sdfr * significant first followed by four bytes of direction 1104184588Sdfr * marker (zero for initiator and 0xff for acceptor). Encrypt 1105184588Sdfr * that data using the SGN_CKSUM as IV. Note: ARC4 wants the 1106184588Sdfr * sequence number big-endian. 1107184588Sdfr */ 1108184588Sdfr bcopy(p, tm->m_data, 8); 1109184588Sdfr tm->m_len = 8; 1110184588Sdfr krb5_decrypt(kc->kc_tokenkey, tm, 0, 8, p + 8, 8); 1111184588Sdfr 1112184588Sdfr tp = tm->m_data; 1113184588Sdfr if (sgn_alg[0] == 0x11) { 1114184588Sdfr seq = tp[3] | (tp[2] << 8) | (tp[1] << 16) | (tp[0] << 24); 1115184588Sdfr } else { 1116184588Sdfr seq = tp[0] | (tp[1] << 8) | (tp[2] << 16) | (tp[3] << 24); 1117184588Sdfr } 1118184588Sdfr 1119184588Sdfr if (is_initiator(kc)) { 1120184588Sdfr dir = 0xff; 1121184588Sdfr } else { 1122184588Sdfr dir = 0; 1123184588Sdfr } 1124184588Sdfr if (tp[4] != dir || tp[5] != dir || tp[6] != dir || tp[7] != dir) { 1125184588Sdfr m_free(tm); 1126184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1127184588Sdfr } 1128184588Sdfr m_free(tm); 1129184588Sdfr 1130184588Sdfr if (kc->kc_msg_order.km_flags & 1131184588Sdfr (GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG)) { 1132184588Sdfr return (krb5_sequence_check(kc, seq)); 1133184588Sdfr } 1134184588Sdfr 1135184588Sdfr return (GSS_S_COMPLETE); 1136184588Sdfr} 1137184588Sdfr 1138184588Sdfrstatic OM_uint32 1139184588Sdfrkrb5_verify_mic_new(struct krb5_context *kc, struct mbuf *m, struct mbuf *mic) 1140184588Sdfr{ 1141184588Sdfr OM_uint32 res; 1142184588Sdfr struct krb5_key_state *key = kc->kc_recv_sign_Kc; 1143184588Sdfr struct mbuf *mlast; 1144184588Sdfr uint8_t *p; 1145184588Sdfr int flags; 1146184588Sdfr size_t mlen, cklen; 1147184588Sdfr char buf[32]; 1148184588Sdfr 1149184588Sdfr mlen = m_length(m, &mlast); 1150184588Sdfr cklen = key->ks_class->ec_checksumlen; 1151184588Sdfr 1152184588Sdfr KASSERT(mic->m_next == NULL, ("MIC should be contiguous")); 1153184588Sdfr if (mic->m_len != 16 + cklen) 1154184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1155184588Sdfr p = mic->m_data; 1156184588Sdfr 1157184588Sdfr /* TOK_ID */ 1158184588Sdfr if (p[0] != 0x04) 1159184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1160184588Sdfr if (p[1] != 0x04) 1161184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1162184588Sdfr 1163184588Sdfr /* Flags */ 1164184588Sdfr flags = 0; 1165184588Sdfr if (is_initiator(kc)) 1166184588Sdfr flags |= GSS_TOKEN_SENT_BY_ACCEPTOR; 1167184588Sdfr if (kc->kc_more_flags & ACCEPTOR_SUBKEY) 1168184588Sdfr flags |= GSS_TOKEN_ACCEPTOR_SUBKEY; 1169184588Sdfr if (p[2] != flags) 1170184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1171184588Sdfr 1172184588Sdfr /* Filler */ 1173184588Sdfr if (p[3] != 0xff) 1174184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1175184588Sdfr if (p[4] != 0xff) 1176184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1177184588Sdfr if (p[5] != 0xff) 1178184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1179184588Sdfr if (p[6] != 0xff) 1180184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1181184588Sdfr if (p[7] != 0xff) 1182184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1183184588Sdfr 1184184588Sdfr /* SND_SEQ */ 1185184588Sdfr if (kc->kc_msg_order.km_flags & 1186184588Sdfr (GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG)) { 1187184588Sdfr uint32_t seq; 1188184588Sdfr if (p[8] || p[9] || p[10] || p[11]) { 1189184588Sdfr res = GSS_S_UNSEQ_TOKEN; 1190184588Sdfr } else { 1191184588Sdfr seq = (p[12] << 24) | (p[13] << 16) 1192184588Sdfr | (p[14] << 8) | p[15]; 1193184588Sdfr res = krb5_sequence_check(kc, seq); 1194184588Sdfr } 1195184588Sdfr if (GSS_ERROR(res)) 1196184588Sdfr return (res); 1197184588Sdfr } else { 1198184588Sdfr res = GSS_S_COMPLETE; 1199184588Sdfr } 1200184588Sdfr 1201184588Sdfr /* 1202184588Sdfr * SGN_CKSUM: 1203184588Sdfr * 1204184588Sdfr * Calculate the keyed checksum of the message plus the first 1205184588Sdfr * 16 bytes of the token header. 1206184588Sdfr */ 1207184588Sdfr m_copydata(mic, 16, cklen, buf); 1208184588Sdfr mlast->m_next = mic; 1209184588Sdfr krb5_checksum(key, 0, m, 0, mlen + 16, cklen); 1210184588Sdfr mlast->m_next = NULL; 1211184588Sdfr if (bcmp(buf, p + 16, cklen)) { 1212184588Sdfr return (GSS_S_BAD_SIG); 1213184588Sdfr } 1214184588Sdfr 1215184588Sdfr return (GSS_S_COMPLETE); 1216184588Sdfr} 1217184588Sdfr 1218184588Sdfrstatic OM_uint32 1219194202Srmacklemkrb5_verify_mic(gss_ctx_id_t ctx, OM_uint32 *minor_status, 1220184588Sdfr struct mbuf *m, struct mbuf *mic, gss_qop_t *qop_state) 1221184588Sdfr{ 1222194202Srmacklem struct krb5_context *kc = (struct krb5_context *)ctx; 1223184588Sdfr 1224184588Sdfr *minor_status = 0; 1225184588Sdfr if (qop_state) 1226184588Sdfr *qop_state = GSS_C_QOP_DEFAULT; 1227184588Sdfr 1228184588Sdfr if (time_uptime > kc->kc_lifetime) 1229184588Sdfr return (GSS_S_CONTEXT_EXPIRED); 1230184588Sdfr 1231184588Sdfr switch (kc->kc_tokenkey->ks_class->ec_type) { 1232184588Sdfr case ETYPE_DES_CBC_CRC: 1233184588Sdfr return (krb5_verify_mic_old(kc, m, mic, sgn_alg_des_md5)); 1234184588Sdfr 1235184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5: 1236184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5_56: 1237184588Sdfr return (krb5_verify_mic_old(kc, m, mic, sgn_alg_hmac_md5)); 1238184588Sdfr 1239184588Sdfr case ETYPE_DES3_CBC_SHA1: 1240184588Sdfr return (krb5_verify_mic_old(kc, m, mic, sgn_alg_des3_sha1)); 1241184588Sdfr 1242184588Sdfr default: 1243184588Sdfr return (krb5_verify_mic_new(kc, m, mic)); 1244184588Sdfr } 1245184588Sdfr 1246184588Sdfr return (GSS_S_FAILURE); 1247184588Sdfr} 1248184588Sdfr 1249184588Sdfrstatic OM_uint32 1250184588Sdfrkrb5_wrap_old(struct krb5_context *kc, int conf_req_flag, 1251184588Sdfr struct mbuf **mp, int *conf_state, 1252184588Sdfr uint8_t sgn_alg[2], uint8_t seal_alg[2]) 1253184588Sdfr{ 1254184588Sdfr struct mbuf *m, *mlast, *tm, *cm, *pm; 1255184588Sdfr size_t mlen, tlen, padlen, datalen; 1256184588Sdfr uint8_t *p, dir; 1257184588Sdfr size_t cklen; 1258184588Sdfr uint8_t buf[8]; 1259184588Sdfr uint32_t seq; 1260184588Sdfr 1261184588Sdfr /* 1262184588Sdfr * How many trailing pad bytes do we need? 1263184588Sdfr */ 1264184588Sdfr m = *mp; 1265184588Sdfr mlen = m_length(m, &mlast); 1266184588Sdfr tlen = kc->kc_tokenkey->ks_class->ec_msgblocklen; 1267184588Sdfr padlen = tlen - (mlen % tlen); 1268184588Sdfr 1269184588Sdfr /* 1270184588Sdfr * The data part of the token has eight bytes of random 1271184588Sdfr * confounder prepended and followed by up to eight bytes of 1272184588Sdfr * padding bytes each of which is set to the number of padding 1273184588Sdfr * bytes. 1274184588Sdfr */ 1275184588Sdfr datalen = mlen + 8 + padlen; 1276184588Sdfr tlen = token_length(kc->kc_tokenkey); 1277184588Sdfr 1278184588Sdfr p = krb5_make_token("\x02\x01", tlen, datalen + tlen, &tm); 1279184588Sdfr p += 2; /* TOK_ID */ 1280184588Sdfr *p++ = sgn_alg[0]; /* SGN_ALG */ 1281184588Sdfr *p++ = sgn_alg[1]; 1282184588Sdfr if (conf_req_flag) { 1283184588Sdfr *p++ = seal_alg[0]; /* SEAL_ALG */ 1284184588Sdfr *p++ = seal_alg[1]; 1285184588Sdfr } else { 1286184588Sdfr *p++ = 0xff; /* SEAL_ALG = none */ 1287184588Sdfr *p++ = 0xff; 1288184588Sdfr } 1289184588Sdfr 1290184588Sdfr *p++ = 0xff; /* filler */ 1291184588Sdfr *p++ = 0xff; 1292184588Sdfr 1293184588Sdfr /* 1294184588Sdfr * Copy the padded message data. 1295184588Sdfr */ 1296184588Sdfr if (M_LEADINGSPACE(m) >= 8) { 1297184588Sdfr m->m_data -= 8; 1298184588Sdfr m->m_len += 8; 1299184588Sdfr } else { 1300184588Sdfr MGET(cm, M_WAITOK, MT_DATA); 1301184588Sdfr cm->m_len = 8; 1302184588Sdfr cm->m_next = m; 1303184588Sdfr m = cm; 1304184588Sdfr } 1305184588Sdfr arc4rand(m->m_data, 8, 0); 1306184588Sdfr if (M_TRAILINGSPACE(mlast) >= padlen) { 1307184588Sdfr memset(mlast->m_data + mlast->m_len, padlen, padlen); 1308184588Sdfr mlast->m_len += padlen; 1309184588Sdfr } else { 1310184588Sdfr MGET(pm, M_WAITOK, MT_DATA); 1311184588Sdfr memset(pm->m_data, padlen, padlen); 1312184588Sdfr pm->m_len = padlen; 1313184588Sdfr mlast->m_next = pm; 1314184588Sdfr mlast = pm; 1315184588Sdfr } 1316184588Sdfr tm->m_next = m; 1317184588Sdfr 1318184588Sdfr /* 1319184588Sdfr * SGN_CKSUM: 1320184588Sdfr * 1321184588Sdfr * Calculate the keyed checksum of the token header plus the 1322184588Sdfr * padded message. Fiddle with tm->m_len so that we only 1323184588Sdfr * checksum the 8 bytes of head that we care about. 1324184588Sdfr */ 1325184588Sdfr cklen = kc->kc_checksumkey->ks_class->ec_checksumlen; 1326184588Sdfr tlen = tm->m_len; 1327184588Sdfr tm->m_len = p - (uint8_t *) tm->m_data; 1328184588Sdfr MGET(cm, M_WAITOK, MT_DATA); 1329184588Sdfr cm->m_len = cklen; 1330184588Sdfr mlast->m_next = cm; 1331184588Sdfr krb5_checksum(kc->kc_checksumkey, 13, tm, tm->m_len - 8, 1332184588Sdfr datalen + 8, cklen); 1333184588Sdfr tm->m_len = tlen; 1334184588Sdfr mlast->m_next = NULL; 1335184588Sdfr bcopy(cm->m_data, p + 8, cklen); 1336184588Sdfr m_free(cm); 1337184588Sdfr 1338184588Sdfr /* 1339184588Sdfr * SND_SEQ: 1340184588Sdfr * 1341184588Sdfr * Take the four bytes of the sequence number least 1342184588Sdfr * significant first (most signficant first for ARCFOUR) 1343184588Sdfr * followed by four bytes of direction marker (zero for 1344184588Sdfr * initiator and 0xff for acceptor). Encrypt that data using 1345184588Sdfr * the SGN_CKSUM as IV. 1346184588Sdfr */ 1347184588Sdfr seq = atomic_fetchadd_32(&kc->kc_local_seqnumber, 1); 1348184588Sdfr if (sgn_alg[0] == 0x11) { 1349184588Sdfr p[0] = (seq >> 24); 1350184588Sdfr p[1] = (seq >> 16); 1351184588Sdfr p[2] = (seq >> 8); 1352184588Sdfr p[3] = (seq >> 0); 1353184588Sdfr } else { 1354184588Sdfr p[0] = (seq >> 0); 1355184588Sdfr p[1] = (seq >> 8); 1356184588Sdfr p[2] = (seq >> 16); 1357184588Sdfr p[3] = (seq >> 24); 1358184588Sdfr } 1359184588Sdfr if (is_initiator(kc)) { 1360184588Sdfr dir = 0; 1361184588Sdfr } else { 1362184588Sdfr dir = 0xff; 1363184588Sdfr } 1364184588Sdfr p[4] = dir; 1365184588Sdfr p[5] = dir; 1366184588Sdfr p[6] = dir; 1367184588Sdfr p[7] = dir; 1368184588Sdfr krb5_encrypt(kc->kc_tokenkey, tm, p - (uint8_t *) tm->m_data, 1369184588Sdfr 8, p + 8, 8); 1370184588Sdfr 1371184588Sdfr if (conf_req_flag) { 1372184588Sdfr /* 1373184588Sdfr * Encrypt the padded message with an IV of zero for 1374184588Sdfr * DES and DES3, or an IV of the sequence number in 1375184588Sdfr * big-endian format for ARCFOUR. 1376184588Sdfr */ 1377184588Sdfr if (seal_alg[0] == 0x10) { 1378184588Sdfr buf[0] = (seq >> 24); 1379184588Sdfr buf[1] = (seq >> 16); 1380184588Sdfr buf[2] = (seq >> 8); 1381184588Sdfr buf[3] = (seq >> 0); 1382184588Sdfr krb5_encrypt(kc->kc_encryptkey, m, 0, datalen, 1383184588Sdfr buf, 4); 1384184588Sdfr } else { 1385184588Sdfr krb5_encrypt(kc->kc_encryptkey, m, 0, datalen, 1386184588Sdfr NULL, 0); 1387184588Sdfr } 1388184588Sdfr } 1389184588Sdfr 1390184588Sdfr if (conf_state) 1391184588Sdfr *conf_state = conf_req_flag; 1392184588Sdfr 1393184588Sdfr *mp = tm; 1394184588Sdfr return (GSS_S_COMPLETE); 1395184588Sdfr} 1396184588Sdfr 1397184588Sdfrstatic OM_uint32 1398184588Sdfrkrb5_wrap_new(struct krb5_context *kc, int conf_req_flag, 1399184588Sdfr struct mbuf **mp, int *conf_state) 1400184588Sdfr{ 1401184588Sdfr struct krb5_key_state *Ke = kc->kc_send_seal_Ke; 1402184588Sdfr struct krb5_key_state *Ki = kc->kc_send_seal_Ki; 1403184588Sdfr struct krb5_key_state *Kc = kc->kc_send_seal_Kc; 1404184588Sdfr const struct krb5_encryption_class *ec = Ke->ks_class; 1405184588Sdfr struct mbuf *m, *mlast, *tm; 1406184588Sdfr uint8_t *p; 1407184588Sdfr int flags, EC; 1408184588Sdfr size_t mlen, blen, mblen, cklen, ctlen; 1409184588Sdfr uint32_t seq; 1410184588Sdfr static char zpad[32]; 1411184588Sdfr 1412184588Sdfr m = *mp; 1413184588Sdfr mlen = m_length(m, &mlast); 1414184588Sdfr 1415184588Sdfr blen = ec->ec_blocklen; 1416184588Sdfr mblen = ec->ec_msgblocklen; 1417184588Sdfr cklen = ec->ec_checksumlen; 1418184588Sdfr 1419184588Sdfr if (conf_req_flag) { 1420184588Sdfr /* 1421184588Sdfr * For sealed messages, we need space for 16 bytes of 1422184588Sdfr * header, blen confounder, plaintext, padding, copy 1423184588Sdfr * of header and checksum. 1424184588Sdfr * 1425184588Sdfr * We pad to mblen (which may be different from 1426184588Sdfr * blen). If the encryption class is using CTS, mblen 1427184588Sdfr * will be one (i.e. no padding required). 1428184588Sdfr */ 1429184588Sdfr if (mblen > 1) 1430184588Sdfr EC = mlen % mblen; 1431184588Sdfr else 1432184588Sdfr EC = 0; 1433184588Sdfr ctlen = blen + mlen + EC + 16; 1434184588Sdfr 1435184588Sdfr /* 1436184588Sdfr * Put initial header and confounder before the 1437184588Sdfr * message. 1438184588Sdfr */ 1439184588Sdfr M_PREPEND(m, 16 + blen, M_WAITOK); 1440184588Sdfr 1441184588Sdfr /* 1442184588Sdfr * Append padding + copy of header and checksum. Try 1443184588Sdfr * to fit this into the end of the original message, 1444184588Sdfr * otherwise allocate a trailer. 1445184588Sdfr */ 1446184588Sdfr if (M_TRAILINGSPACE(mlast) >= EC + 16 + cklen) { 1447184588Sdfr tm = NULL; 1448184588Sdfr mlast->m_len += EC + 16 + cklen; 1449184588Sdfr } else { 1450184588Sdfr MGET(tm, M_WAITOK, MT_DATA); 1451184588Sdfr tm->m_len = EC + 16 + cklen; 1452184588Sdfr mlast->m_next = tm; 1453184588Sdfr } 1454184588Sdfr } else { 1455184588Sdfr /* 1456184588Sdfr * For unsealed messages, we need 16 bytes of header 1457184588Sdfr * plus space for the plaintext and a checksum. EC is 1458184588Sdfr * set to the checksum size. We leave space in tm for 1459184588Sdfr * a copy of the header - this will be trimmed later. 1460184588Sdfr */ 1461184588Sdfr M_PREPEND(m, 16, M_WAITOK); 1462184588Sdfr 1463184588Sdfr MGET(tm, M_WAITOK, MT_DATA); 1464184588Sdfr tm->m_len = cklen + 16; 1465184588Sdfr mlast->m_next = tm; 1466184588Sdfr ctlen = 0; 1467184588Sdfr EC = cklen; 1468184588Sdfr } 1469184588Sdfr 1470184588Sdfr p = m->m_data; 1471184588Sdfr 1472184588Sdfr /* TOK_ID */ 1473184588Sdfr p[0] = 0x05; 1474184588Sdfr p[1] = 0x04; 1475184588Sdfr 1476184588Sdfr /* Flags */ 1477184588Sdfr flags = 0; 1478184588Sdfr if (conf_req_flag) 1479184588Sdfr flags = GSS_TOKEN_SEALED; 1480184588Sdfr if (is_acceptor(kc)) 1481184588Sdfr flags |= GSS_TOKEN_SENT_BY_ACCEPTOR; 1482184588Sdfr if (kc->kc_more_flags & ACCEPTOR_SUBKEY) 1483184588Sdfr flags |= GSS_TOKEN_ACCEPTOR_SUBKEY; 1484184588Sdfr p[2] = flags; 1485184588Sdfr 1486184588Sdfr /* Filler */ 1487184588Sdfr p[3] = 0xff; 1488184588Sdfr 1489184588Sdfr /* EC + RRC - set to zero initially */ 1490184588Sdfr p[4] = 0; 1491184588Sdfr p[5] = 0; 1492184588Sdfr p[6] = 0; 1493184588Sdfr p[7] = 0; 1494184588Sdfr 1495184588Sdfr /* SND_SEQ */ 1496184588Sdfr p[8] = 0; 1497184588Sdfr p[9] = 0; 1498184588Sdfr p[10] = 0; 1499184588Sdfr p[11] = 0; 1500184588Sdfr seq = atomic_fetchadd_32(&kc->kc_local_seqnumber, 1); 1501184588Sdfr p[12] = (seq >> 24); 1502184588Sdfr p[13] = (seq >> 16); 1503184588Sdfr p[14] = (seq >> 8); 1504184588Sdfr p[15] = (seq >> 0); 1505184588Sdfr 1506184588Sdfr if (conf_req_flag) { 1507184588Sdfr /* 1508184588Sdfr * Encrypt according to RFC 4121 section 4.2 and RFC 1509184588Sdfr * 3961 section 5.3. Note: we don't generate tokens 1510184588Sdfr * with RRC values other than zero. If we did, we 1511184588Sdfr * should zero RRC in the copied header. 1512184588Sdfr */ 1513184588Sdfr arc4rand(p + 16, blen, 0); 1514184588Sdfr if (EC) { 1515184588Sdfr m_copyback(m, 16 + blen + mlen, EC, zpad); 1516184588Sdfr } 1517184588Sdfr m_copyback(m, 16 + blen + mlen + EC, 16, p); 1518184588Sdfr 1519184588Sdfr krb5_checksum(Ki, 0, m, 16, ctlen, cklen); 1520184588Sdfr krb5_encrypt(Ke, m, 16, ctlen, NULL, 0); 1521184588Sdfr } else { 1522184588Sdfr /* 1523184588Sdfr * The plaintext message is followed by a checksum of 1524184588Sdfr * the plaintext plus a version of the header where EC 1525184588Sdfr * and RRC are set to zero. Also, the original EC must 1526184588Sdfr * be our checksum size. 1527184588Sdfr */ 1528184588Sdfr bcopy(p, tm->m_data, 16); 1529184588Sdfr krb5_checksum(Kc, 0, m, 16, mlen + 16, cklen); 1530184588Sdfr tm->m_data += 16; 1531184588Sdfr tm->m_len -= 16; 1532184588Sdfr } 1533184588Sdfr 1534184588Sdfr /* 1535184588Sdfr * Finally set EC to its actual value 1536184588Sdfr */ 1537184588Sdfr p[4] = EC >> 8; 1538184588Sdfr p[5] = EC; 1539184588Sdfr 1540184588Sdfr *mp = m; 1541184588Sdfr return (GSS_S_COMPLETE); 1542184588Sdfr} 1543184588Sdfr 1544184588Sdfrstatic OM_uint32 1545194202Srmacklemkrb5_wrap(gss_ctx_id_t ctx, OM_uint32 *minor_status, 1546184588Sdfr int conf_req_flag, gss_qop_t qop_req, 1547184588Sdfr struct mbuf **mp, int *conf_state) 1548184588Sdfr{ 1549194202Srmacklem struct krb5_context *kc = (struct krb5_context *)ctx; 1550184588Sdfr 1551184588Sdfr *minor_status = 0; 1552184588Sdfr if (conf_state) 1553184588Sdfr *conf_state = 0; 1554184588Sdfr 1555184588Sdfr if (qop_req != GSS_C_QOP_DEFAULT) 1556184588Sdfr return (GSS_S_BAD_QOP); 1557184588Sdfr 1558184588Sdfr if (time_uptime > kc->kc_lifetime) 1559184588Sdfr return (GSS_S_CONTEXT_EXPIRED); 1560184588Sdfr 1561184588Sdfr switch (kc->kc_tokenkey->ks_class->ec_type) { 1562184588Sdfr case ETYPE_DES_CBC_CRC: 1563184588Sdfr return (krb5_wrap_old(kc, conf_req_flag, 1564184588Sdfr mp, conf_state, sgn_alg_des_md5, seal_alg_des)); 1565184588Sdfr 1566184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5: 1567184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5_56: 1568184588Sdfr return (krb5_wrap_old(kc, conf_req_flag, 1569184588Sdfr mp, conf_state, sgn_alg_hmac_md5, seal_alg_rc4)); 1570184588Sdfr 1571184588Sdfr case ETYPE_DES3_CBC_SHA1: 1572184588Sdfr return (krb5_wrap_old(kc, conf_req_flag, 1573184588Sdfr mp, conf_state, sgn_alg_des3_sha1, seal_alg_des3)); 1574184588Sdfr 1575184588Sdfr default: 1576184588Sdfr return (krb5_wrap_new(kc, conf_req_flag, mp, conf_state)); 1577184588Sdfr } 1578184588Sdfr 1579184588Sdfr return (GSS_S_FAILURE); 1580184588Sdfr} 1581184588Sdfr 1582184588Sdfrstatic void 1583184588Sdfrm_trim(struct mbuf *m, int len) 1584184588Sdfr{ 1585184588Sdfr struct mbuf *n; 1586184588Sdfr int off; 1587184588Sdfr 1588250157Srmacklem if (m == NULL) 1589250157Srmacklem return; 1590184588Sdfr n = m_getptr(m, len, &off); 1591184588Sdfr if (n) { 1592184588Sdfr n->m_len = off; 1593184588Sdfr if (n->m_next) { 1594184588Sdfr m_freem(n->m_next); 1595184588Sdfr n->m_next = NULL; 1596184588Sdfr } 1597184588Sdfr } 1598184588Sdfr} 1599184588Sdfr 1600184588Sdfrstatic OM_uint32 1601184588Sdfrkrb5_unwrap_old(struct krb5_context *kc, struct mbuf **mp, int *conf_state, 1602184588Sdfr uint8_t sgn_alg[2], uint8_t seal_alg[2]) 1603184588Sdfr{ 1604184588Sdfr OM_uint32 res; 1605250157Srmacklem struct mbuf *m, *mlast, *hm, *cm, *n; 1606184588Sdfr uint8_t *p, dir; 1607184588Sdfr size_t mlen, tlen, elen, datalen, padlen; 1608184588Sdfr size_t cklen; 1609184588Sdfr uint8_t buf[32]; 1610184588Sdfr uint32_t seq; 1611184588Sdfr int i, conf; 1612184588Sdfr 1613184588Sdfr m = *mp; 1614184588Sdfr mlen = m_length(m, &mlast); 1615184588Sdfr 1616184588Sdfr tlen = token_length(kc->kc_tokenkey); 1617184588Sdfr cklen = kc->kc_tokenkey->ks_class->ec_checksumlen; 1618184588Sdfr 1619184588Sdfr p = krb5_verify_token("\x02\x01", tlen, &m, &elen, TRUE); 1620184588Sdfr *mp = m; 1621184588Sdfr if (!p) 1622184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1623184588Sdfr datalen = elen - tlen; 1624184588Sdfr 1625184588Sdfr /* 1626184588Sdfr * Trim the framing header first to make life a little easier 1627184588Sdfr * later. 1628184588Sdfr */ 1629184588Sdfr m_adj(m, p - (uint8_t *) m->m_data); 1630184588Sdfr 1631184588Sdfr /* TOK_ID */ 1632184588Sdfr p += 2; 1633184588Sdfr 1634184588Sdfr /* SGN_ALG */ 1635184588Sdfr if (p[0] != sgn_alg[0] || p[1] != sgn_alg[1]) 1636184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1637184588Sdfr p += 2; 1638184588Sdfr 1639184588Sdfr /* SEAL_ALG */ 1640184588Sdfr if (p[0] == seal_alg[0] && p[1] == seal_alg[1]) 1641184588Sdfr conf = 1; 1642184588Sdfr else if (p[0] == 0xff && p[1] == 0xff) 1643184588Sdfr conf = 0; 1644184588Sdfr else 1645184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1646184588Sdfr p += 2; 1647184588Sdfr 1648184588Sdfr if (p[0] != 0xff || p[1] != 0xff) 1649184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1650184588Sdfr p += 2; 1651184588Sdfr 1652184588Sdfr /* 1653184588Sdfr * SND_SEQ: 1654184588Sdfr * 1655184588Sdfr * Take the four bytes of the sequence number least 1656184588Sdfr * significant first (most significant for ARCFOUR) followed 1657184588Sdfr * by four bytes of direction marker (zero for initiator and 1658184588Sdfr * 0xff for acceptor). Encrypt that data using the SGN_CKSUM 1659184588Sdfr * as IV. 1660184588Sdfr */ 1661184588Sdfr krb5_decrypt(kc->kc_tokenkey, m, 8, 8, p + 8, 8); 1662184588Sdfr if (sgn_alg[0] == 0x11) { 1663184588Sdfr seq = p[3] | (p[2] << 8) | (p[1] << 16) | (p[0] << 24); 1664184588Sdfr } else { 1665184588Sdfr seq = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); 1666184588Sdfr } 1667184588Sdfr 1668184588Sdfr if (is_initiator(kc)) { 1669184588Sdfr dir = 0xff; 1670184588Sdfr } else { 1671184588Sdfr dir = 0; 1672184588Sdfr } 1673184588Sdfr if (p[4] != dir || p[5] != dir || p[6] != dir || p[7] != dir) 1674184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1675184588Sdfr 1676184588Sdfr if (kc->kc_msg_order.km_flags & 1677184588Sdfr (GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG)) { 1678184588Sdfr res = krb5_sequence_check(kc, seq); 1679184588Sdfr if (GSS_ERROR(res)) 1680184588Sdfr return (res); 1681184588Sdfr } else { 1682184588Sdfr res = GSS_S_COMPLETE; 1683184588Sdfr } 1684184588Sdfr 1685184588Sdfr /* 1686184588Sdfr * If the token was encrypted, decode it in-place. 1687184588Sdfr */ 1688184588Sdfr if (conf) { 1689184588Sdfr /* 1690184588Sdfr * Decrypt the padded message with an IV of zero for 1691184588Sdfr * DES and DES3 or an IV of the big-endian encoded 1692184588Sdfr * sequence number for ARCFOUR. 1693184588Sdfr */ 1694184588Sdfr if (seal_alg[0] == 0x10) { 1695184588Sdfr krb5_decrypt(kc->kc_encryptkey, m, 16 + cklen, 1696184588Sdfr datalen, p, 4); 1697184588Sdfr } else { 1698184588Sdfr krb5_decrypt(kc->kc_encryptkey, m, 16 + cklen, 1699184588Sdfr datalen, NULL, 0); 1700184588Sdfr } 1701184588Sdfr } 1702184588Sdfr if (conf_state) 1703184588Sdfr *conf_state = conf; 1704184588Sdfr 1705184588Sdfr /* 1706184588Sdfr * Check the trailing pad bytes. 1707250157Srmacklem * RFC1964 specifies between 1<->8 bytes, each with a binary value 1708250157Srmacklem * equal to the number of bytes. 1709184588Sdfr */ 1710250157Srmacklem if (mlast->m_len > 0) 1711250157Srmacklem padlen = mlast->m_data[mlast->m_len - 1]; 1712250157Srmacklem else { 1713250157Srmacklem n = m_getptr(m, tlen + datalen - 1, &i); 1714250157Srmacklem /* 1715250157Srmacklem * When the position is exactly equal to the # of data bytes 1716250157Srmacklem * in the mbuf list, m_getptr() will return the last mbuf in 1717250157Srmacklem * the list and an off == m_len for that mbuf, so that case 1718250157Srmacklem * needs to be checked as well as a NULL return. 1719250157Srmacklem */ 1720250157Srmacklem if (n == NULL || n->m_len == i) 1721250157Srmacklem return (GSS_S_DEFECTIVE_TOKEN); 1722250157Srmacklem padlen = n->m_data[i]; 1723250157Srmacklem } 1724250157Srmacklem if (padlen < 1 || padlen > 8 || padlen > tlen + datalen) 1725250157Srmacklem return (GSS_S_DEFECTIVE_TOKEN); 1726184588Sdfr m_copydata(m, tlen + datalen - padlen, padlen, buf); 1727184588Sdfr for (i = 0; i < padlen; i++) { 1728184588Sdfr if (buf[i] != padlen) { 1729184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1730184588Sdfr } 1731184588Sdfr } 1732184588Sdfr 1733184588Sdfr /* 1734184588Sdfr * SGN_CKSUM: 1735184588Sdfr * 1736184588Sdfr * Calculate the keyed checksum of the token header plus the 1737184588Sdfr * padded message. We do a little mbuf surgery to trim out the 1738184588Sdfr * parts we don't want to checksum. 1739184588Sdfr */ 1740184588Sdfr hm = m; 1741184588Sdfr *mp = m = m_split(m, 16 + cklen, M_WAITOK); 1742184588Sdfr mlast = m_last(m); 1743184588Sdfr hm->m_len = 8; 1744184588Sdfr hm->m_next = m; 1745184588Sdfr MGET(cm, M_WAITOK, MT_DATA); 1746184588Sdfr cm->m_len = cklen; 1747184588Sdfr mlast->m_next = cm; 1748184588Sdfr 1749184588Sdfr krb5_checksum(kc->kc_checksumkey, 13, hm, 0, datalen + 8, cklen); 1750184588Sdfr hm->m_next = NULL; 1751184588Sdfr mlast->m_next = NULL; 1752184588Sdfr 1753184588Sdfr if (bcmp(cm->m_data, hm->m_data + 16, cklen)) { 1754184588Sdfr m_freem(hm); 1755184588Sdfr m_free(cm); 1756184588Sdfr return (GSS_S_BAD_SIG); 1757184588Sdfr } 1758184588Sdfr m_freem(hm); 1759184588Sdfr m_free(cm); 1760184588Sdfr 1761184588Sdfr /* 1762184588Sdfr * Trim off the confounder and padding. 1763184588Sdfr */ 1764184588Sdfr m_adj(m, 8); 1765184588Sdfr if (mlast->m_len >= padlen) { 1766184588Sdfr mlast->m_len -= padlen; 1767184588Sdfr } else { 1768184588Sdfr m_trim(m, datalen - 8 - padlen); 1769184588Sdfr } 1770184588Sdfr 1771184588Sdfr *mp = m; 1772184588Sdfr return (res); 1773184588Sdfr} 1774184588Sdfr 1775184588Sdfrstatic OM_uint32 1776184588Sdfrkrb5_unwrap_new(struct krb5_context *kc, struct mbuf **mp, int *conf_state) 1777184588Sdfr{ 1778184588Sdfr OM_uint32 res; 1779184588Sdfr struct krb5_key_state *Ke = kc->kc_recv_seal_Ke; 1780184588Sdfr struct krb5_key_state *Ki = kc->kc_recv_seal_Ki; 1781184588Sdfr struct krb5_key_state *Kc = kc->kc_recv_seal_Kc; 1782184588Sdfr const struct krb5_encryption_class *ec = Ke->ks_class; 1783184588Sdfr struct mbuf *m, *mlast, *hm, *cm; 1784184588Sdfr uint8_t *p, *pp; 1785184588Sdfr int sealed, flags, EC, RRC; 1786184588Sdfr size_t blen, cklen, ctlen, mlen, plen, tlen; 1787184588Sdfr char buf[32], buf2[32]; 1788184588Sdfr 1789184588Sdfr m = *mp; 1790184588Sdfr mlen = m_length(m, &mlast); 1791184588Sdfr 1792184588Sdfr if (mlen <= 16) 1793184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1794184588Sdfr if (m->m_len < 16) { 1795184588Sdfr m = m_pullup(m, 16); 1796184588Sdfr *mp = m; 1797184588Sdfr } 1798184588Sdfr p = m->m_data; 1799184588Sdfr 1800184588Sdfr /* TOK_ID */ 1801184588Sdfr if (p[0] != 0x05) 1802184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1803184588Sdfr if (p[1] != 0x04) 1804184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1805184588Sdfr 1806184588Sdfr /* Flags */ 1807184588Sdfr sealed = p[2] & GSS_TOKEN_SEALED; 1808184588Sdfr flags = sealed; 1809184588Sdfr if (is_initiator(kc)) 1810184588Sdfr flags |= GSS_TOKEN_SENT_BY_ACCEPTOR; 1811184588Sdfr if (kc->kc_more_flags & ACCEPTOR_SUBKEY) 1812184588Sdfr flags |= GSS_TOKEN_ACCEPTOR_SUBKEY; 1813184588Sdfr if (p[2] != flags) 1814184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1815184588Sdfr 1816184588Sdfr /* Filler */ 1817184588Sdfr if (p[3] != 0xff) 1818184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1819184588Sdfr 1820184588Sdfr /* EC + RRC */ 1821184588Sdfr EC = (p[4] << 8) + p[5]; 1822184588Sdfr RRC = (p[6] << 8) + p[7]; 1823184588Sdfr 1824184588Sdfr /* SND_SEQ */ 1825184588Sdfr if (kc->kc_msg_order.km_flags & 1826184588Sdfr (GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG)) { 1827184588Sdfr uint32_t seq; 1828184588Sdfr if (p[8] || p[9] || p[10] || p[11]) { 1829184588Sdfr res = GSS_S_UNSEQ_TOKEN; 1830184588Sdfr } else { 1831184588Sdfr seq = (p[12] << 24) | (p[13] << 16) 1832184588Sdfr | (p[14] << 8) | p[15]; 1833184588Sdfr res = krb5_sequence_check(kc, seq); 1834184588Sdfr } 1835184588Sdfr if (GSS_ERROR(res)) 1836184588Sdfr return (res); 1837184588Sdfr } else { 1838184588Sdfr res = GSS_S_COMPLETE; 1839184588Sdfr } 1840184588Sdfr 1841184588Sdfr /* 1842184588Sdfr * Separate the header before dealing with RRC. We only need 1843184588Sdfr * to keep the header if the message isn't encrypted. 1844184588Sdfr */ 1845184588Sdfr if (sealed) { 1846184588Sdfr hm = NULL; 1847184588Sdfr m_adj(m, 16); 1848184588Sdfr } else { 1849184588Sdfr hm = m; 1850184588Sdfr *mp = m = m_split(m, 16, M_WAITOK); 1851184588Sdfr mlast = m_last(m); 1852184588Sdfr } 1853184588Sdfr 1854184588Sdfr /* 1855184588Sdfr * Undo the effects of RRC by rotating left. 1856184588Sdfr */ 1857184588Sdfr if (RRC > 0) { 1858184588Sdfr struct mbuf *rm; 1859184588Sdfr size_t rlen; 1860184588Sdfr 1861184588Sdfr rlen = mlen - 16; 1862184588Sdfr if (RRC <= sizeof(buf) && m->m_len >= rlen) { 1863184588Sdfr /* 1864184588Sdfr * Simple case, just rearrange the bytes in m. 1865184588Sdfr */ 1866184588Sdfr bcopy(m->m_data, buf, RRC); 1867184588Sdfr bcopy(m->m_data + RRC, m->m_data, rlen - RRC); 1868184588Sdfr bcopy(buf, m->m_data + rlen - RRC, RRC); 1869184588Sdfr } else { 1870184588Sdfr /* 1871184588Sdfr * More complicated - rearrange the mbuf 1872184588Sdfr * chain. 1873184588Sdfr */ 1874184588Sdfr rm = m; 1875184588Sdfr *mp = m = m_split(m, RRC, M_WAITOK); 1876184588Sdfr m_cat(m, rm); 1877184588Sdfr mlast = rm; 1878184588Sdfr } 1879184588Sdfr } 1880184588Sdfr 1881184588Sdfr blen = ec->ec_blocklen; 1882184588Sdfr cklen = ec->ec_checksumlen; 1883184588Sdfr if (sealed) { 1884184588Sdfr /* 1885184588Sdfr * Decrypt according to RFC 4121 section 4.2 and RFC 1886184588Sdfr * 3961 section 5.3. The message must be large enough 1887184588Sdfr * for a blocksize confounder, at least one block of 1888184588Sdfr * cyphertext and a checksum. 1889184588Sdfr */ 1890184588Sdfr if (mlen < 16 + 2*blen + cklen) 1891184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1892184588Sdfr 1893184588Sdfr ctlen = mlen - 16 - cklen; 1894184588Sdfr krb5_decrypt(Ke, m, 0, ctlen, NULL, 0); 1895184588Sdfr 1896184588Sdfr /* 1897184588Sdfr * The size of the plaintext is ctlen minus blocklen 1898184588Sdfr * (for the confounder), 16 (for the copy of the token 1899184588Sdfr * header) and EC (for the filler). The actual 1900184588Sdfr * plaintext starts after the confounder. 1901184588Sdfr */ 1902184588Sdfr plen = ctlen - blen - 16 - EC; 1903184588Sdfr pp = p + 16 + blen; 1904184588Sdfr 1905184588Sdfr /* 1906184588Sdfr * Checksum the padded plaintext. 1907184588Sdfr */ 1908184588Sdfr m_copydata(m, ctlen, cklen, buf); 1909184588Sdfr krb5_checksum(Ki, 0, m, 0, ctlen, cklen); 1910184588Sdfr m_copydata(m, ctlen, cklen, buf2); 1911184588Sdfr 1912184588Sdfr if (bcmp(buf, buf2, cklen)) 1913184588Sdfr return (GSS_S_BAD_SIG); 1914184588Sdfr 1915184588Sdfr /* 1916184588Sdfr * Trim the message back to just plaintext. 1917184588Sdfr */ 1918184588Sdfr m_adj(m, blen); 1919184588Sdfr tlen = 16 + EC + cklen; 1920184588Sdfr if (mlast->m_len >= tlen) { 1921184588Sdfr mlast->m_len -= tlen; 1922184588Sdfr } else { 1923184588Sdfr m_trim(m, plen); 1924184588Sdfr } 1925184588Sdfr } else { 1926184588Sdfr /* 1927184588Sdfr * The plaintext message is followed by a checksum of 1928184588Sdfr * the plaintext plus a version of the header where EC 1929184588Sdfr * and RRC are set to zero. Also, the original EC must 1930184588Sdfr * be our checksum size. 1931184588Sdfr */ 1932184588Sdfr if (mlen < 16 + cklen || EC != cklen) 1933184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1934184588Sdfr 1935184588Sdfr /* 1936184588Sdfr * The size of the plaintext is simply the message 1937184588Sdfr * size less header and checksum. The plaintext starts 1938184588Sdfr * right after the header (which we have saved in hm). 1939184588Sdfr */ 1940184588Sdfr plen = mlen - 16 - cklen; 1941184588Sdfr 1942184588Sdfr /* 1943184588Sdfr * Insert a copy of the header (with EC and RRC set to 1944184588Sdfr * zero) between the plaintext message and the 1945184588Sdfr * checksum. 1946184588Sdfr */ 1947184588Sdfr p = hm->m_data; 1948184588Sdfr p[4] = p[5] = p[6] = p[7] = 0; 1949184588Sdfr 1950184588Sdfr cm = m_split(m, plen, M_WAITOK); 1951184588Sdfr mlast = m_last(m); 1952184588Sdfr m->m_next = hm; 1953184588Sdfr hm->m_next = cm; 1954184588Sdfr 1955184588Sdfr bcopy(cm->m_data, buf, cklen); 1956184588Sdfr krb5_checksum(Kc, 0, m, 0, plen + 16, cklen); 1957184588Sdfr if (bcmp(cm->m_data, buf, cklen)) 1958184588Sdfr return (GSS_S_BAD_SIG); 1959184588Sdfr 1960184588Sdfr /* 1961184588Sdfr * The checksum matches, discard all buf the plaintext. 1962184588Sdfr */ 1963184588Sdfr mlast->m_next = NULL; 1964184588Sdfr m_freem(hm); 1965184588Sdfr } 1966184588Sdfr 1967184588Sdfr if (conf_state) 1968184588Sdfr *conf_state = (sealed != 0); 1969184588Sdfr 1970184588Sdfr return (res); 1971184588Sdfr} 1972184588Sdfr 1973184588Sdfrstatic OM_uint32 1974194202Srmacklemkrb5_unwrap(gss_ctx_id_t ctx, OM_uint32 *minor_status, 1975184588Sdfr struct mbuf **mp, int *conf_state, gss_qop_t *qop_state) 1976184588Sdfr{ 1977194202Srmacklem struct krb5_context *kc = (struct krb5_context *)ctx; 1978184588Sdfr OM_uint32 maj_stat; 1979184588Sdfr 1980184588Sdfr *minor_status = 0; 1981184588Sdfr if (qop_state) 1982184588Sdfr *qop_state = GSS_C_QOP_DEFAULT; 1983184588Sdfr if (conf_state) 1984184588Sdfr *conf_state = 0; 1985184588Sdfr 1986184588Sdfr if (time_uptime > kc->kc_lifetime) 1987184588Sdfr return (GSS_S_CONTEXT_EXPIRED); 1988184588Sdfr 1989184588Sdfr switch (kc->kc_tokenkey->ks_class->ec_type) { 1990184588Sdfr case ETYPE_DES_CBC_CRC: 1991184588Sdfr maj_stat = krb5_unwrap_old(kc, mp, conf_state, 1992184588Sdfr sgn_alg_des_md5, seal_alg_des); 1993184588Sdfr break; 1994184588Sdfr 1995184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5: 1996184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5_56: 1997184588Sdfr maj_stat = krb5_unwrap_old(kc, mp, conf_state, 1998184588Sdfr sgn_alg_hmac_md5, seal_alg_rc4); 1999184588Sdfr break; 2000184588Sdfr 2001184588Sdfr case ETYPE_DES3_CBC_SHA1: 2002184588Sdfr maj_stat = krb5_unwrap_old(kc, mp, conf_state, 2003184588Sdfr sgn_alg_des3_sha1, seal_alg_des3); 2004184588Sdfr break; 2005184588Sdfr 2006184588Sdfr default: 2007184588Sdfr maj_stat = krb5_unwrap_new(kc, mp, conf_state); 2008184588Sdfr break; 2009184588Sdfr } 2010184588Sdfr 2011184588Sdfr if (GSS_ERROR(maj_stat)) { 2012184588Sdfr m_freem(*mp); 2013184588Sdfr *mp = NULL; 2014184588Sdfr } 2015184588Sdfr 2016184588Sdfr return (maj_stat); 2017184588Sdfr} 2018184588Sdfr 2019184588Sdfrstatic OM_uint32 2020194202Srmacklemkrb5_wrap_size_limit(gss_ctx_id_t ctx, OM_uint32 *minor_status, 2021184588Sdfr int conf_req_flag, gss_qop_t qop_req, OM_uint32 req_output_size, 2022184588Sdfr OM_uint32 *max_input_size) 2023184588Sdfr{ 2024194202Srmacklem struct krb5_context *kc = (struct krb5_context *)ctx; 2025184588Sdfr const struct krb5_encryption_class *ec; 2026184588Sdfr OM_uint32 overhead; 2027184588Sdfr 2028184588Sdfr *minor_status = 0; 2029184588Sdfr *max_input_size = 0; 2030184588Sdfr 2031184588Sdfr if (qop_req != GSS_C_QOP_DEFAULT) 2032184588Sdfr return (GSS_S_BAD_QOP); 2033184588Sdfr 2034184588Sdfr ec = kc->kc_tokenkey->ks_class; 2035184588Sdfr switch (ec->ec_type) { 2036184588Sdfr case ETYPE_DES_CBC_CRC: 2037184588Sdfr case ETYPE_DES3_CBC_SHA1: 2038184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5: 2039184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5_56: 2040184588Sdfr /* 2041184588Sdfr * up to 5 bytes for [APPLICATION 0] SEQUENCE 2042184588Sdfr * 2 + krb5 oid length 2043184588Sdfr * 8 bytes of header 2044184588Sdfr * 8 bytes of confounder 2045184588Sdfr * maximum of 8 bytes of padding 2046184588Sdfr * checksum 2047184588Sdfr */ 2048184588Sdfr overhead = 5 + 2 + krb5_mech_oid.length; 2049184588Sdfr overhead += 8 + 8 + ec->ec_msgblocklen; 2050184588Sdfr overhead += ec->ec_checksumlen; 2051184588Sdfr break; 2052184588Sdfr 2053184588Sdfr default: 2054184588Sdfr if (conf_req_flag) { 2055184588Sdfr /* 2056184588Sdfr * 16 byts of header 2057184588Sdfr * blocklen bytes of confounder 2058184588Sdfr * up to msgblocklen - 1 bytes of padding 2059184588Sdfr * 16 bytes for copy of header 2060184588Sdfr * checksum 2061184588Sdfr */ 2062184588Sdfr overhead = 16 + ec->ec_blocklen; 2063184588Sdfr overhead += ec->ec_msgblocklen - 1; 2064184588Sdfr overhead += 16; 2065184588Sdfr overhead += ec->ec_checksumlen; 2066184588Sdfr } else { 2067184588Sdfr /* 2068184588Sdfr * 16 bytes of header plus checksum. 2069184588Sdfr */ 2070184588Sdfr overhead = 16 + ec->ec_checksumlen; 2071184588Sdfr } 2072184588Sdfr } 2073184588Sdfr 2074184588Sdfr *max_input_size = req_output_size - overhead; 2075184588Sdfr 2076184588Sdfr return (GSS_S_COMPLETE); 2077184588Sdfr} 2078184588Sdfr 2079184588Sdfrstatic kobj_method_t krb5_methods[] = { 2080184588Sdfr KOBJMETHOD(kgss_init, krb5_init), 2081184588Sdfr KOBJMETHOD(kgss_import, krb5_import), 2082184588Sdfr KOBJMETHOD(kgss_delete, krb5_delete), 2083184588Sdfr KOBJMETHOD(kgss_mech_type, krb5_mech_type), 2084184588Sdfr KOBJMETHOD(kgss_get_mic, krb5_get_mic), 2085184588Sdfr KOBJMETHOD(kgss_verify_mic, krb5_verify_mic), 2086184588Sdfr KOBJMETHOD(kgss_wrap, krb5_wrap), 2087184588Sdfr KOBJMETHOD(kgss_unwrap, krb5_unwrap), 2088184588Sdfr KOBJMETHOD(kgss_wrap_size_limit, krb5_wrap_size_limit), 2089184588Sdfr { 0, 0 } 2090184588Sdfr}; 2091184588Sdfr 2092184588Sdfrstatic struct kobj_class krb5_class = { 2093184588Sdfr "kerberosv5", 2094184588Sdfr krb5_methods, 2095184588Sdfr sizeof(struct krb5_context) 2096184588Sdfr}; 2097184588Sdfr 2098184588Sdfr/* 2099184588Sdfr * Kernel module glue 2100184588Sdfr */ 2101184588Sdfrstatic int 2102184588Sdfrkgssapi_krb5_modevent(module_t mod, int type, void *data) 2103184588Sdfr{ 2104184588Sdfr 2105184588Sdfr switch (type) { 2106184588Sdfr case MOD_LOAD: 2107184588Sdfr kgss_install_mech(&krb5_mech_oid, "kerberosv5", &krb5_class); 2108184588Sdfr break; 2109184588Sdfr 2110184588Sdfr case MOD_UNLOAD: 2111184588Sdfr kgss_uninstall_mech(&krb5_mech_oid); 2112184588Sdfr break; 2113184588Sdfr } 2114184588Sdfr 2115184588Sdfr 2116184588Sdfr return (0); 2117184588Sdfr} 2118184588Sdfrstatic moduledata_t kgssapi_krb5_mod = { 2119184588Sdfr "kgssapi_krb5", 2120184588Sdfr kgssapi_krb5_modevent, 2121184588Sdfr NULL, 2122184588Sdfr}; 2123184588SdfrDECLARE_MODULE(kgssapi_krb5, kgssapi_krb5_mod, SI_SUB_VFS, SI_ORDER_ANY); 2124184588SdfrMODULE_DEPEND(kgssapi_krb5, kgssapi, 1, 1, 1); 2125184588SdfrMODULE_DEPEND(kgssapi_krb5, crypto, 1, 1, 1); 2126184588SdfrMODULE_DEPEND(kgssapi_krb5, rc4, 1, 1, 1); 2127184588SdfrMODULE_VERSION(kgssapi_krb5, 1); 2128