krb5_mech.c revision 194202
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: head/sys/kgssapi/krb5/krb5_mech.c 194202 2009-06-14 17:33:46Z 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; 291184588Sdfr 292184588Sdfr default: 293184588Sdfr etype = keydata->kk_type; 294184588Sdfr } 295184588Sdfr 296184588Sdfr ec = krb5_find_encryption_class(etype); 297184588Sdfr if (!ec) 298184588Sdfr return (GSS_S_FAILURE); 299184588Sdfr 300184588Sdfr key = krb5_create_key(ec); 301184588Sdfr krb5_set_key(key, keydata->kk_key.kd_data); 302184588Sdfr kc->kc_tokenkey = key; 303184588Sdfr 304184588Sdfr switch (etype) { 305184588Sdfr case ETYPE_DES_CBC_CRC: 306184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5: 307184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5_56: { 308184588Sdfr /* 309184588Sdfr * Single DES and ARCFOUR uses a 'derived' key (XOR 310184588Sdfr * with 0xf0) for encrypting wrap tokens. The original 311184588Sdfr * key is used for checksums and sequence numbers. 312184588Sdfr */ 313184588Sdfr struct krb5_key_state *ekey; 314184588Sdfr uint8_t *ekp, *kp; 315184588Sdfr int i; 316184588Sdfr 317184588Sdfr ekey = krb5_create_key(ec); 318184588Sdfr ekp = ekey->ks_key; 319184588Sdfr kp = key->ks_key; 320184588Sdfr for (i = 0; i < ec->ec_keylen; i++) 321184588Sdfr ekp[i] = kp[i] ^ 0xf0; 322184588Sdfr krb5_set_key(ekey, ekp); 323184588Sdfr kc->kc_encryptkey = ekey; 324184588Sdfr refcount_acquire(&key->ks_refs); 325184588Sdfr kc->kc_checksumkey = key; 326184588Sdfr break; 327184588Sdfr } 328184588Sdfr 329184588Sdfr case ETYPE_DES3_CBC_SHA1: 330184588Sdfr /* 331184588Sdfr * Triple DES uses a RFC 3961 style derived key with 332184588Sdfr * usage number KG_USAGE_SIGN for checksums. The 333184588Sdfr * original key is used for encryption and sequence 334184588Sdfr * numbers. 335184588Sdfr */ 336184588Sdfr kc->kc_checksumkey = krb5_get_checksum_key(key, KG_USAGE_SIGN); 337184588Sdfr refcount_acquire(&key->ks_refs); 338184588Sdfr kc->kc_encryptkey = key; 339184588Sdfr break; 340184588Sdfr 341184588Sdfr default: 342184588Sdfr /* 343184588Sdfr * We need eight derived keys four for sending and 344184588Sdfr * four for receiving. 345184588Sdfr */ 346184588Sdfr if (is_initiator(kc)) { 347184588Sdfr /* 348184588Sdfr * We are initiator. 349184588Sdfr */ 350184588Sdfr kc->kc_send_seal_Ke = krb5_get_encryption_key(key, 351184588Sdfr KG_USAGE_INITIATOR_SEAL); 352184588Sdfr kc->kc_send_seal_Ki = krb5_get_integrity_key(key, 353184588Sdfr KG_USAGE_INITIATOR_SEAL); 354184588Sdfr kc->kc_send_seal_Kc = krb5_get_checksum_key(key, 355184588Sdfr KG_USAGE_INITIATOR_SEAL); 356184588Sdfr kc->kc_send_sign_Kc = krb5_get_checksum_key(key, 357184588Sdfr KG_USAGE_INITIATOR_SIGN); 358184588Sdfr 359184588Sdfr kc->kc_recv_seal_Ke = krb5_get_encryption_key(key, 360184588Sdfr KG_USAGE_ACCEPTOR_SEAL); 361184588Sdfr kc->kc_recv_seal_Ki = krb5_get_integrity_key(key, 362184588Sdfr KG_USAGE_ACCEPTOR_SEAL); 363184588Sdfr kc->kc_recv_seal_Kc = krb5_get_checksum_key(key, 364184588Sdfr KG_USAGE_ACCEPTOR_SEAL); 365184588Sdfr kc->kc_recv_sign_Kc = krb5_get_checksum_key(key, 366184588Sdfr KG_USAGE_ACCEPTOR_SIGN); 367184588Sdfr } else { 368184588Sdfr /* 369184588Sdfr * We are acceptor. 370184588Sdfr */ 371184588Sdfr kc->kc_send_seal_Ke = krb5_get_encryption_key(key, 372184588Sdfr KG_USAGE_ACCEPTOR_SEAL); 373184588Sdfr kc->kc_send_seal_Ki = krb5_get_integrity_key(key, 374184588Sdfr KG_USAGE_ACCEPTOR_SEAL); 375184588Sdfr kc->kc_send_seal_Kc = krb5_get_checksum_key(key, 376184588Sdfr KG_USAGE_ACCEPTOR_SEAL); 377184588Sdfr kc->kc_send_sign_Kc = krb5_get_checksum_key(key, 378184588Sdfr KG_USAGE_ACCEPTOR_SIGN); 379184588Sdfr 380184588Sdfr kc->kc_recv_seal_Ke = krb5_get_encryption_key(key, 381184588Sdfr KG_USAGE_INITIATOR_SEAL); 382184588Sdfr kc->kc_recv_seal_Ki = krb5_get_integrity_key(key, 383184588Sdfr KG_USAGE_INITIATOR_SEAL); 384184588Sdfr kc->kc_recv_seal_Kc = krb5_get_checksum_key(key, 385184588Sdfr KG_USAGE_INITIATOR_SEAL); 386184588Sdfr kc->kc_recv_sign_Kc = krb5_get_checksum_key(key, 387184588Sdfr KG_USAGE_INITIATOR_SIGN); 388184588Sdfr } 389184588Sdfr break; 390184588Sdfr } 391184588Sdfr 392184588Sdfr return (GSS_S_COMPLETE); 393184588Sdfr} 394184588Sdfr 395184588Sdfrstatic void 396194202Srmacklemkrb5_init(gss_ctx_id_t ctx) 397184588Sdfr{ 398194202Srmacklem struct krb5_context *kc = (struct krb5_context *)ctx; 399184588Sdfr 400184588Sdfr mtx_init(&kc->kc_lock, "krb5 gss lock", NULL, MTX_DEF); 401184588Sdfr} 402184588Sdfr 403184588Sdfrstatic OM_uint32 404194202Srmacklemkrb5_import(gss_ctx_id_t ctx, 405184588Sdfr enum sec_context_format format, 406184588Sdfr const gss_buffer_t context_token) 407184588Sdfr{ 408194202Srmacklem struct krb5_context *kc = (struct krb5_context *)ctx; 409184588Sdfr OM_uint32 res; 410184588Sdfr const uint8_t *p = (const uint8_t *) context_token->value; 411184588Sdfr size_t len = context_token->length; 412184588Sdfr uint32_t flags; 413184588Sdfr int i; 414184588Sdfr 415184588Sdfr /* 416184588Sdfr * We support heimdal 0.6 and heimdal 1.1 417184588Sdfr */ 418184588Sdfr if (format != KGSS_HEIMDAL_0_6 && format != KGSS_HEIMDAL_1_1) 419184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 420184588Sdfr 421184588Sdfr#define SC_LOCAL_ADDRESS 1 422184588Sdfr#define SC_REMOTE_ADDRESS 2 423184588Sdfr#define SC_KEYBLOCK 4 424184588Sdfr#define SC_LOCAL_SUBKEY 8 425184588Sdfr#define SC_REMOTE_SUBKEY 16 426184588Sdfr 427184588Sdfr /* 428184588Sdfr * Ensure that the token starts with krb5 oid. 429184588Sdfr */ 430184588Sdfr if (p[0] != 0x00 || p[1] != krb5_mech_oid.length 431184588Sdfr || len < krb5_mech_oid.length + 2 432184588Sdfr || bcmp(krb5_mech_oid.elements, p + 2, 433184588Sdfr krb5_mech_oid.length)) 434184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 435184588Sdfr p += krb5_mech_oid.length + 2; 436184588Sdfr len -= krb5_mech_oid.length + 2; 437184588Sdfr 438184588Sdfr flags = get_uint32(&p, &len); 439184588Sdfr kc->kc_ac_flags = get_uint32(&p, &len); 440184588Sdfr if (flags & SC_LOCAL_ADDRESS) 441184588Sdfr get_address(&p, &len, &kc->kc_local_address); 442184588Sdfr if (flags & SC_REMOTE_ADDRESS) 443184588Sdfr get_address(&p, &len, &kc->kc_remote_address); 444184588Sdfr kc->kc_local_port = get_uint16(&p, &len); 445184588Sdfr kc->kc_remote_port = get_uint16(&p, &len); 446184588Sdfr if (flags & SC_KEYBLOCK) 447184588Sdfr get_keyblock(&p, &len, &kc->kc_keyblock); 448184588Sdfr if (flags & SC_LOCAL_SUBKEY) 449184588Sdfr get_keyblock(&p, &len, &kc->kc_local_subkey); 450184588Sdfr if (flags & SC_REMOTE_SUBKEY) 451184588Sdfr get_keyblock(&p, &len, &kc->kc_remote_subkey); 452184588Sdfr kc->kc_local_seqnumber = get_uint32(&p, &len); 453184588Sdfr kc->kc_remote_seqnumber = get_uint32(&p, &len); 454184588Sdfr kc->kc_keytype = get_uint32(&p, &len); 455184588Sdfr kc->kc_cksumtype = get_uint32(&p, &len); 456184588Sdfr get_data(&p, &len, &kc->kc_source_name); 457184588Sdfr get_data(&p, &len, &kc->kc_target_name); 458184588Sdfr kc->kc_ctx_flags = get_uint32(&p, &len); 459184588Sdfr kc->kc_more_flags = get_uint32(&p, &len); 460184588Sdfr kc->kc_lifetime = get_uint32(&p, &len); 461184588Sdfr /* 462184588Sdfr * Heimdal 1.1 adds the message order stuff. 463184588Sdfr */ 464184588Sdfr if (format == KGSS_HEIMDAL_1_1) { 465184588Sdfr kc->kc_msg_order.km_flags = get_uint32(&p, &len); 466184588Sdfr kc->kc_msg_order.km_start = get_uint32(&p, &len); 467184588Sdfr kc->kc_msg_order.km_length = get_uint32(&p, &len); 468184588Sdfr kc->kc_msg_order.km_jitter_window = get_uint32(&p, &len); 469184588Sdfr kc->kc_msg_order.km_first_seq = get_uint32(&p, &len); 470184588Sdfr kc->kc_msg_order.km_elem = 471184588Sdfr malloc(kc->kc_msg_order.km_jitter_window * sizeof(uint32_t), 472184588Sdfr M_GSSAPI, M_WAITOK); 473184588Sdfr for (i = 0; i < kc->kc_msg_order.km_jitter_window; i++) 474184588Sdfr kc->kc_msg_order.km_elem[i] = get_uint32(&p, &len); 475184588Sdfr } else { 476184588Sdfr kc->kc_msg_order.km_flags = 0; 477184588Sdfr } 478184588Sdfr 479184588Sdfr res = get_keys(kc); 480184588Sdfr if (GSS_ERROR(res)) 481184588Sdfr return (res); 482184588Sdfr 483184588Sdfr /* 484184588Sdfr * We don't need these anymore. 485184588Sdfr */ 486184588Sdfr delete_keyblock(&kc->kc_keyblock); 487184588Sdfr delete_keyblock(&kc->kc_local_subkey); 488184588Sdfr delete_keyblock(&kc->kc_remote_subkey); 489184588Sdfr 490184588Sdfr return (GSS_S_COMPLETE); 491184588Sdfr} 492184588Sdfr 493184588Sdfrstatic void 494194202Srmacklemkrb5_delete(gss_ctx_id_t ctx, gss_buffer_t output_token) 495184588Sdfr{ 496194202Srmacklem struct krb5_context *kc = (struct krb5_context *)ctx; 497184588Sdfr 498184588Sdfr delete_address(&kc->kc_local_address); 499184588Sdfr delete_address(&kc->kc_remote_address); 500184588Sdfr delete_keyblock(&kc->kc_keyblock); 501184588Sdfr delete_keyblock(&kc->kc_local_subkey); 502184588Sdfr delete_keyblock(&kc->kc_remote_subkey); 503184588Sdfr delete_data(&kc->kc_source_name); 504184588Sdfr delete_data(&kc->kc_target_name); 505184588Sdfr if (kc->kc_msg_order.km_elem) 506184588Sdfr free(kc->kc_msg_order.km_elem, M_GSSAPI); 507184588Sdfr if (output_token) { 508184588Sdfr output_token->length = 0; 509184588Sdfr output_token->value = NULL; 510184588Sdfr } 511184588Sdfr if (kc->kc_tokenkey) { 512184588Sdfr krb5_free_key(kc->kc_tokenkey); 513184588Sdfr if (kc->kc_encryptkey) { 514184588Sdfr krb5_free_key(kc->kc_encryptkey); 515184588Sdfr krb5_free_key(kc->kc_checksumkey); 516184588Sdfr } else { 517184588Sdfr krb5_free_key(kc->kc_send_seal_Ke); 518184588Sdfr krb5_free_key(kc->kc_send_seal_Ki); 519184588Sdfr krb5_free_key(kc->kc_send_seal_Kc); 520184588Sdfr krb5_free_key(kc->kc_send_sign_Kc); 521184588Sdfr krb5_free_key(kc->kc_recv_seal_Ke); 522184588Sdfr krb5_free_key(kc->kc_recv_seal_Ki); 523184588Sdfr krb5_free_key(kc->kc_recv_seal_Kc); 524184588Sdfr krb5_free_key(kc->kc_recv_sign_Kc); 525184588Sdfr } 526184588Sdfr } 527184588Sdfr mtx_destroy(&kc->kc_lock); 528184588Sdfr} 529184588Sdfr 530184588Sdfrstatic gss_OID 531194202Srmacklemkrb5_mech_type(gss_ctx_id_t ctx) 532184588Sdfr{ 533184588Sdfr 534184588Sdfr return (&krb5_mech_oid); 535184588Sdfr} 536184588Sdfr 537184588Sdfr/* 538184588Sdfr * Make a token with the given type and length (the length includes 539184588Sdfr * the TOK_ID), initialising the token header appropriately. Return a 540184588Sdfr * pointer to the TOK_ID of the token. A new mbuf is allocated with 541184588Sdfr * the framing header plus hlen bytes of space. 542184588Sdfr * 543184588Sdfr * Format is as follows: 544184588Sdfr * 545184588Sdfr * 0x60 [APPLICATION 0] SEQUENCE 546184588Sdfr * DER encoded length length of oid + type + inner token length 547184588Sdfr * 0x06 NN <oid data> OID of mechanism type 548184588Sdfr * TT TT TOK_ID 549184588Sdfr * <inner token> data for inner token 550184588Sdfr * 551184588Sdfr * 1: der encoded length 552184588Sdfr */ 553184588Sdfrstatic void * 554184588Sdfrkrb5_make_token(char tok_id[2], size_t hlen, size_t len, struct mbuf **mp) 555184588Sdfr{ 556184588Sdfr size_t inside_len, len_len, tlen; 557184588Sdfr gss_OID oid = &krb5_mech_oid; 558184588Sdfr struct mbuf *m; 559184588Sdfr uint8_t *p; 560184588Sdfr 561184588Sdfr inside_len = 2 + oid->length + len; 562184588Sdfr if (inside_len < 128) 563184588Sdfr len_len = 1; 564184588Sdfr else if (inside_len < 0x100) 565184588Sdfr len_len = 2; 566184588Sdfr else if (inside_len < 0x10000) 567184588Sdfr len_len = 3; 568184588Sdfr else if (inside_len < 0x1000000) 569184588Sdfr len_len = 4; 570184588Sdfr else 571184588Sdfr len_len = 5; 572184588Sdfr 573184588Sdfr tlen = 1 + len_len + 2 + oid->length + hlen; 574184588Sdfr KASSERT(tlen <= MLEN, ("token head too large")); 575184588Sdfr MGET(m, M_WAITOK, MT_DATA); 576184588Sdfr M_ALIGN(m, tlen); 577184588Sdfr m->m_len = tlen; 578184588Sdfr 579184588Sdfr p = (uint8_t *) m->m_data; 580184588Sdfr *p++ = 0x60; 581184588Sdfr switch (len_len) { 582184588Sdfr case 1: 583184588Sdfr *p++ = inside_len; 584184588Sdfr break; 585184588Sdfr case 2: 586184588Sdfr *p++ = 0x81; 587184588Sdfr *p++ = inside_len; 588184588Sdfr break; 589184588Sdfr case 3: 590184588Sdfr *p++ = 0x82; 591184588Sdfr *p++ = inside_len >> 8; 592184588Sdfr *p++ = inside_len; 593184588Sdfr break; 594184588Sdfr case 4: 595184588Sdfr *p++ = 0x83; 596184588Sdfr *p++ = inside_len >> 16; 597184588Sdfr *p++ = inside_len >> 8; 598184588Sdfr *p++ = inside_len; 599184588Sdfr break; 600184588Sdfr case 5: 601184588Sdfr *p++ = 0x84; 602184588Sdfr *p++ = inside_len >> 24; 603184588Sdfr *p++ = inside_len >> 16; 604184588Sdfr *p++ = inside_len >> 8; 605184588Sdfr *p++ = inside_len; 606184588Sdfr break; 607184588Sdfr } 608184588Sdfr 609184588Sdfr *p++ = 0x06; 610184588Sdfr *p++ = oid->length; 611184588Sdfr bcopy(oid->elements, p, oid->length); 612184588Sdfr p += oid->length; 613184588Sdfr 614184588Sdfr p[0] = tok_id[0]; 615184588Sdfr p[1] = tok_id[1]; 616184588Sdfr 617184588Sdfr *mp = m; 618184588Sdfr 619184588Sdfr return (p); 620184588Sdfr} 621184588Sdfr 622184588Sdfr/* 623184588Sdfr * Verify a token, checking the inner token length and mechanism oid. 624184588Sdfr * pointer to the first byte of the TOK_ID. The length of the 625184588Sdfr * encapsulated data is checked to be at least len bytes; the actual 626184588Sdfr * length of the encapsulated data (including TOK_ID) is returned in 627184588Sdfr * *encap_len. 628184588Sdfr * 629184588Sdfr * If can_pullup is TRUE and the token header is fragmented, we will 630184588Sdfr * rearrange it. 631184588Sdfr * 632184588Sdfr * Format is as follows: 633184588Sdfr * 634184588Sdfr * 0x60 [APPLICATION 0] SEQUENCE 635184588Sdfr * DER encoded length length of oid + type + inner token length 636184588Sdfr * 0x06 NN <oid data> OID of mechanism type 637184588Sdfr * TT TT TOK_ID 638184588Sdfr * <inner token> data for inner token 639184588Sdfr * 640184588Sdfr * 1: der encoded length 641184588Sdfr */ 642184588Sdfrstatic void * 643184588Sdfrkrb5_verify_token(char tok_id[2], size_t len, struct mbuf **mp, 644184588Sdfr size_t *encap_len, bool_t can_pullup) 645184588Sdfr{ 646184588Sdfr struct mbuf *m; 647184588Sdfr size_t tlen, hlen, len_len, inside_len; 648184588Sdfr gss_OID oid = &krb5_mech_oid; 649184588Sdfr uint8_t *p; 650184588Sdfr 651184588Sdfr m = *mp; 652184588Sdfr tlen = m_length(m, NULL); 653184588Sdfr if (tlen < 2) 654184588Sdfr return (NULL); 655184588Sdfr 656184588Sdfr /* 657184588Sdfr * Ensure that at least the framing part of the token is 658184588Sdfr * contigous. 659184588Sdfr */ 660184588Sdfr if (m->m_len < 2) { 661184588Sdfr if (can_pullup) 662184588Sdfr *mp = m = m_pullup(m, 2); 663184588Sdfr else 664184588Sdfr return (NULL); 665184588Sdfr } 666184588Sdfr 667184588Sdfr p = m->m_data; 668184588Sdfr 669184588Sdfr if (*p++ != 0x60) 670184588Sdfr return (NULL); 671184588Sdfr 672184588Sdfr if (*p < 0x80) { 673184588Sdfr inside_len = *p++; 674184588Sdfr len_len = 1; 675184588Sdfr } else { 676184588Sdfr /* 677184588Sdfr * Ensure there is enough space for the DER encoded length. 678184588Sdfr */ 679184588Sdfr len_len = (*p & 0x7f) + 1; 680184588Sdfr if (tlen < len_len + 1) 681184588Sdfr return (NULL); 682184588Sdfr if (m->m_len < len_len + 1) { 683184588Sdfr if (can_pullup) 684184588Sdfr *mp = m = m_pullup(m, len_len + 1); 685184588Sdfr else 686184588Sdfr return (NULL); 687184588Sdfr p = m->m_data + 1; 688184588Sdfr } 689184588Sdfr 690184588Sdfr switch (*p++) { 691184588Sdfr case 0x81: 692184588Sdfr inside_len = *p++; 693184588Sdfr break; 694184588Sdfr 695184588Sdfr case 0x82: 696184588Sdfr inside_len = (p[0] << 8) | p[1]; 697184588Sdfr p += 2; 698184588Sdfr break; 699184588Sdfr 700184588Sdfr case 0x83: 701184588Sdfr inside_len = (p[0] << 16) | (p[1] << 8) | p[2]; 702184588Sdfr p += 3; 703184588Sdfr break; 704184588Sdfr 705184588Sdfr case 0x84: 706184588Sdfr inside_len = (p[0] << 24) | (p[1] << 16) 707184588Sdfr | (p[2] << 8) | p[3]; 708184588Sdfr p += 4; 709184588Sdfr break; 710184588Sdfr 711184588Sdfr default: 712184588Sdfr return (NULL); 713184588Sdfr } 714184588Sdfr } 715184588Sdfr 716184588Sdfr if (tlen != inside_len + len_len + 1) 717184588Sdfr return (NULL); 718184588Sdfr if (inside_len < 2 + oid->length + len) 719184588Sdfr return (NULL); 720184588Sdfr 721184588Sdfr /* 722184588Sdfr * Now that we know the value of len_len, we can pullup the 723184588Sdfr * whole header. The header is 1 + len_len + 2 + oid->length + 724184588Sdfr * len bytes. 725184588Sdfr */ 726184588Sdfr hlen = 1 + len_len + 2 + oid->length + len; 727184588Sdfr if (m->m_len < hlen) { 728184588Sdfr if (can_pullup) 729184588Sdfr *mp = m = m_pullup(m, hlen); 730184588Sdfr else 731184588Sdfr return (NULL); 732184588Sdfr p = m->m_data + 1 + len_len; 733184588Sdfr } 734184588Sdfr 735184588Sdfr if (*p++ != 0x06) 736184588Sdfr return (NULL); 737184588Sdfr if (*p++ != oid->length) 738184588Sdfr return (NULL); 739184588Sdfr if (bcmp(oid->elements, p, oid->length)) 740184588Sdfr return (NULL); 741184588Sdfr p += oid->length; 742184588Sdfr 743184588Sdfr if (p[0] != tok_id[0]) 744184588Sdfr return (NULL); 745184588Sdfr 746184588Sdfr if (p[1] != tok_id[1]) 747184588Sdfr return (NULL); 748184588Sdfr 749184588Sdfr *encap_len = inside_len - 2 - oid->length; 750184588Sdfr 751184588Sdfr return (p); 752184588Sdfr} 753184588Sdfr 754184588Sdfrstatic void 755184588Sdfrkrb5_insert_seq(struct krb5_msg_order *mo, uint32_t seq, int index) 756184588Sdfr{ 757184588Sdfr int i; 758184588Sdfr 759184588Sdfr if (mo->km_length < mo->km_jitter_window) 760184588Sdfr mo->km_length++; 761184588Sdfr 762184588Sdfr for (i = mo->km_length - 1; i > index; i--) 763184588Sdfr mo->km_elem[i] = mo->km_elem[i - 1]; 764184588Sdfr mo->km_elem[index] = seq; 765184588Sdfr} 766184588Sdfr 767184588Sdfr/* 768184588Sdfr * Check sequence numbers according to RFC 2743 section 1.2.3. 769184588Sdfr */ 770184588Sdfrstatic OM_uint32 771184588Sdfrkrb5_sequence_check(struct krb5_context *kc, uint32_t seq) 772184588Sdfr{ 773184588Sdfr OM_uint32 res = GSS_S_FAILURE; 774184588Sdfr struct krb5_msg_order *mo = &kc->kc_msg_order; 775184588Sdfr int check_sequence = mo->km_flags & GSS_C_SEQUENCE_FLAG; 776184588Sdfr int check_replay = mo->km_flags & GSS_C_REPLAY_FLAG; 777184588Sdfr int i; 778184588Sdfr 779184588Sdfr mtx_lock(&kc->kc_lock); 780184588Sdfr 781184588Sdfr /* 782184588Sdfr * Message is in-sequence with no gap. 783184588Sdfr */ 784184588Sdfr if (mo->km_length == 0 || seq == mo->km_elem[0] + 1) { 785184588Sdfr /* 786184588Sdfr * This message is received in-sequence with no gaps. 787184588Sdfr */ 788184588Sdfr krb5_insert_seq(mo, seq, 0); 789184588Sdfr res = GSS_S_COMPLETE; 790184588Sdfr goto out; 791184588Sdfr } 792184588Sdfr 793184588Sdfr if (seq > mo->km_elem[0]) { 794184588Sdfr /* 795184588Sdfr * This message is received in-sequence with a gap. 796184588Sdfr */ 797184588Sdfr krb5_insert_seq(mo, seq, 0); 798184588Sdfr if (check_sequence) 799184588Sdfr res = GSS_S_GAP_TOKEN; 800184588Sdfr else 801184588Sdfr res = GSS_S_COMPLETE; 802184588Sdfr goto out; 803184588Sdfr } 804184588Sdfr 805184588Sdfr if (seq < mo->km_elem[mo->km_length - 1]) { 806184588Sdfr if (check_replay && !check_sequence) 807184588Sdfr res = GSS_S_OLD_TOKEN; 808184588Sdfr else 809184588Sdfr res = GSS_S_UNSEQ_TOKEN; 810184588Sdfr goto out; 811184588Sdfr } 812184588Sdfr 813184588Sdfr for (i = 0; i < mo->km_length; i++) { 814184588Sdfr if (mo->km_elem[i] == seq) { 815184588Sdfr res = GSS_S_DUPLICATE_TOKEN; 816184588Sdfr goto out; 817184588Sdfr } 818184588Sdfr if (mo->km_elem[i] < seq) { 819184588Sdfr /* 820184588Sdfr * We need to insert this seq here, 821184588Sdfr */ 822184588Sdfr krb5_insert_seq(mo, seq, i); 823184588Sdfr if (check_replay && !check_sequence) 824184588Sdfr res = GSS_S_COMPLETE; 825184588Sdfr else 826184588Sdfr res = GSS_S_UNSEQ_TOKEN; 827184588Sdfr goto out; 828184588Sdfr } 829184588Sdfr } 830184588Sdfr 831184588Sdfrout: 832184588Sdfr mtx_unlock(&kc->kc_lock); 833184588Sdfr 834184588Sdfr return (res); 835184588Sdfr} 836184588Sdfr 837184588Sdfrstatic uint8_t sgn_alg_des_md5[] = { 0x00, 0x00 }; 838184588Sdfrstatic uint8_t seal_alg_des[] = { 0x00, 0x00 }; 839184588Sdfrstatic uint8_t sgn_alg_des3_sha1[] = { 0x04, 0x00 }; 840184588Sdfrstatic uint8_t seal_alg_des3[] = { 0x02, 0x00 }; 841184588Sdfrstatic uint8_t seal_alg_rc4[] = { 0x10, 0x00 }; 842184588Sdfrstatic uint8_t sgn_alg_hmac_md5[] = { 0x11, 0x00 }; 843184588Sdfr 844184588Sdfr/* 845184588Sdfr * Return the size of the inner token given the use of the key's 846184588Sdfr * encryption class. For wrap tokens, the length of the padded 847184588Sdfr * plaintext will be added to this. 848184588Sdfr */ 849184588Sdfrstatic size_t 850184588Sdfrtoken_length(struct krb5_key_state *key) 851184588Sdfr{ 852184588Sdfr 853184588Sdfr return (16 + key->ks_class->ec_checksumlen); 854184588Sdfr} 855184588Sdfr 856184588Sdfrstatic OM_uint32 857184588Sdfrkrb5_get_mic_old(struct krb5_context *kc, struct mbuf *m, 858184588Sdfr struct mbuf **micp, uint8_t sgn_alg[2]) 859184588Sdfr{ 860184588Sdfr struct mbuf *mlast, *mic, *tm; 861184588Sdfr uint8_t *p, dir; 862184588Sdfr size_t tlen, mlen, cklen; 863184588Sdfr uint32_t seq; 864184588Sdfr char buf[8]; 865184588Sdfr 866184588Sdfr mlen = m_length(m, &mlast); 867184588Sdfr 868184588Sdfr tlen = token_length(kc->kc_tokenkey); 869184588Sdfr p = krb5_make_token("\x01\x01", tlen, tlen, &mic); 870184588Sdfr p += 2; /* TOK_ID */ 871184588Sdfr *p++ = sgn_alg[0]; /* SGN_ALG */ 872184588Sdfr *p++ = sgn_alg[1]; 873184588Sdfr 874184588Sdfr *p++ = 0xff; /* filler */ 875184588Sdfr *p++ = 0xff; 876184588Sdfr *p++ = 0xff; 877184588Sdfr *p++ = 0xff; 878184588Sdfr 879184588Sdfr /* 880184588Sdfr * SGN_CKSUM: 881184588Sdfr * 882184588Sdfr * Calculate the keyed checksum of the token header plus the 883184588Sdfr * message. 884184588Sdfr */ 885184588Sdfr cklen = kc->kc_checksumkey->ks_class->ec_checksumlen; 886184588Sdfr 887184588Sdfr mic->m_len = p - (uint8_t *) mic->m_data; 888184588Sdfr mic->m_next = m; 889184588Sdfr MGET(tm, M_WAITOK, MT_DATA); 890184588Sdfr tm->m_len = cklen; 891184588Sdfr mlast->m_next = tm; 892184588Sdfr 893184588Sdfr krb5_checksum(kc->kc_checksumkey, 15, mic, mic->m_len - 8, 894184588Sdfr 8 + mlen, cklen); 895184588Sdfr bcopy(tm->m_data, p + 8, cklen); 896184588Sdfr mic->m_next = NULL; 897184588Sdfr mlast->m_next = NULL; 898184588Sdfr m_free(tm); 899184588Sdfr 900184588Sdfr /* 901184588Sdfr * SND_SEQ: 902184588Sdfr * 903184588Sdfr * Take the four bytes of the sequence number least 904184588Sdfr * significant first followed by four bytes of direction 905184588Sdfr * marker (zero for initiator and 0xff for acceptor). Encrypt 906184588Sdfr * that data using the SGN_CKSUM as IV. Note: ARC4 wants the 907184588Sdfr * sequence number big-endian. 908184588Sdfr */ 909184588Sdfr seq = atomic_fetchadd_32(&kc->kc_local_seqnumber, 1); 910184588Sdfr if (sgn_alg[0] == 0x11) { 911184588Sdfr p[0] = (seq >> 24); 912184588Sdfr p[1] = (seq >> 16); 913184588Sdfr p[2] = (seq >> 8); 914184588Sdfr p[3] = (seq >> 0); 915184588Sdfr } else { 916184588Sdfr p[0] = (seq >> 0); 917184588Sdfr p[1] = (seq >> 8); 918184588Sdfr p[2] = (seq >> 16); 919184588Sdfr p[3] = (seq >> 24); 920184588Sdfr } 921184588Sdfr if (is_initiator(kc)) { 922184588Sdfr dir = 0; 923184588Sdfr } else { 924184588Sdfr dir = 0xff; 925184588Sdfr } 926184588Sdfr p[4] = dir; 927184588Sdfr p[5] = dir; 928184588Sdfr p[6] = dir; 929184588Sdfr p[7] = dir; 930184588Sdfr bcopy(p + 8, buf, 8); 931184588Sdfr 932184588Sdfr /* 933184588Sdfr * Set the mic buffer to its final size so that the encrypt 934184588Sdfr * can see the SND_SEQ part. 935184588Sdfr */ 936184588Sdfr mic->m_len += 8 + cklen; 937184588Sdfr krb5_encrypt(kc->kc_tokenkey, mic, mic->m_len - cklen - 8, 8, buf, 8); 938184588Sdfr 939184588Sdfr *micp = mic; 940184588Sdfr return (GSS_S_COMPLETE); 941184588Sdfr} 942184588Sdfr 943184588Sdfrstatic OM_uint32 944184588Sdfrkrb5_get_mic_new(struct krb5_context *kc, struct mbuf *m, 945184588Sdfr struct mbuf **micp) 946184588Sdfr{ 947184588Sdfr struct krb5_key_state *key = kc->kc_send_sign_Kc; 948184588Sdfr struct mbuf *mlast, *mic; 949184588Sdfr uint8_t *p; 950184588Sdfr int flags; 951184588Sdfr size_t mlen, cklen; 952184588Sdfr uint32_t seq; 953184588Sdfr 954184588Sdfr mlen = m_length(m, &mlast); 955184588Sdfr cklen = key->ks_class->ec_checksumlen; 956184588Sdfr 957184588Sdfr KASSERT(16 + cklen <= MLEN, ("checksum too large for an mbuf")); 958184588Sdfr MGET(mic, M_WAITOK, MT_DATA); 959184588Sdfr M_ALIGN(mic, 16 + cklen); 960184588Sdfr mic->m_len = 16 + cklen; 961184588Sdfr p = mic->m_data; 962184588Sdfr 963184588Sdfr /* TOK_ID */ 964184588Sdfr p[0] = 0x04; 965184588Sdfr p[1] = 0x04; 966184588Sdfr 967184588Sdfr /* Flags */ 968184588Sdfr flags = 0; 969184588Sdfr if (is_acceptor(kc)) 970184588Sdfr flags |= GSS_TOKEN_SENT_BY_ACCEPTOR; 971184588Sdfr if (kc->kc_more_flags & ACCEPTOR_SUBKEY) 972184588Sdfr flags |= GSS_TOKEN_ACCEPTOR_SUBKEY; 973184588Sdfr p[2] = flags; 974184588Sdfr 975184588Sdfr /* Filler */ 976184588Sdfr p[3] = 0xff; 977184588Sdfr p[4] = 0xff; 978184588Sdfr p[5] = 0xff; 979184588Sdfr p[6] = 0xff; 980184588Sdfr p[7] = 0xff; 981184588Sdfr 982184588Sdfr /* SND_SEQ */ 983184588Sdfr p[8] = 0; 984184588Sdfr p[9] = 0; 985184588Sdfr p[10] = 0; 986184588Sdfr p[11] = 0; 987184588Sdfr seq = atomic_fetchadd_32(&kc->kc_local_seqnumber, 1); 988184588Sdfr p[12] = (seq >> 24); 989184588Sdfr p[13] = (seq >> 16); 990184588Sdfr p[14] = (seq >> 8); 991184588Sdfr p[15] = (seq >> 0); 992184588Sdfr 993184588Sdfr /* 994184588Sdfr * SGN_CKSUM: 995184588Sdfr * 996184588Sdfr * Calculate the keyed checksum of the message plus the first 997184588Sdfr * 16 bytes of the token header. 998184588Sdfr */ 999184588Sdfr mlast->m_next = mic; 1000184588Sdfr krb5_checksum(key, 0, m, 0, mlen + 16, cklen); 1001184588Sdfr mlast->m_next = NULL; 1002184588Sdfr 1003184588Sdfr *micp = mic; 1004184588Sdfr return (GSS_S_COMPLETE); 1005184588Sdfr} 1006184588Sdfr 1007184588Sdfrstatic OM_uint32 1008194202Srmacklemkrb5_get_mic(gss_ctx_id_t ctx, OM_uint32 *minor_status, 1009184588Sdfr gss_qop_t qop_req, struct mbuf *m, struct mbuf **micp) 1010184588Sdfr{ 1011194202Srmacklem struct krb5_context *kc = (struct krb5_context *)ctx; 1012184588Sdfr 1013184588Sdfr *minor_status = 0; 1014184588Sdfr 1015184588Sdfr if (qop_req != GSS_C_QOP_DEFAULT) 1016184588Sdfr return (GSS_S_BAD_QOP); 1017184588Sdfr 1018184588Sdfr if (time_uptime > kc->kc_lifetime) 1019184588Sdfr return (GSS_S_CONTEXT_EXPIRED); 1020184588Sdfr 1021184588Sdfr switch (kc->kc_tokenkey->ks_class->ec_type) { 1022184588Sdfr case ETYPE_DES_CBC_CRC: 1023184588Sdfr return (krb5_get_mic_old(kc, m, micp, sgn_alg_des_md5)); 1024184588Sdfr 1025184588Sdfr case ETYPE_DES3_CBC_SHA1: 1026184588Sdfr return (krb5_get_mic_old(kc, m, micp, sgn_alg_des3_sha1)); 1027184588Sdfr 1028184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5: 1029184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5_56: 1030184588Sdfr return (krb5_get_mic_old(kc, m, micp, sgn_alg_hmac_md5)); 1031184588Sdfr 1032184588Sdfr default: 1033184588Sdfr return (krb5_get_mic_new(kc, m, micp)); 1034184588Sdfr } 1035184588Sdfr 1036184588Sdfr return (GSS_S_FAILURE); 1037184588Sdfr} 1038184588Sdfr 1039184588Sdfrstatic OM_uint32 1040184588Sdfrkrb5_verify_mic_old(struct krb5_context *kc, struct mbuf *m, struct mbuf *mic, 1041184588Sdfr uint8_t sgn_alg[2]) 1042184588Sdfr{ 1043184588Sdfr struct mbuf *mlast, *tm; 1044184588Sdfr uint8_t *p, *tp, dir; 1045184588Sdfr size_t mlen, tlen, elen, miclen; 1046184588Sdfr size_t cklen; 1047184588Sdfr uint32_t seq; 1048184588Sdfr 1049184588Sdfr mlen = m_length(m, &mlast); 1050184588Sdfr 1051184588Sdfr tlen = token_length(kc->kc_tokenkey); 1052184588Sdfr p = krb5_verify_token("\x01\x01", tlen, &mic, &elen, FALSE); 1053184588Sdfr if (!p) 1054184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1055184588Sdfr#if 0 1056184588Sdfr /* 1057184588Sdfr * Disable this check - heimdal-1.1 generates DES3 MIC tokens 1058184588Sdfr * that are 2 bytes too big. 1059184588Sdfr */ 1060184588Sdfr if (elen != tlen) 1061184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1062184588Sdfr#endif 1063184588Sdfr /* TOK_ID */ 1064184588Sdfr p += 2; 1065184588Sdfr 1066184588Sdfr /* SGN_ALG */ 1067184588Sdfr if (p[0] != sgn_alg[0] || p[1] != sgn_alg[1]) 1068184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1069184588Sdfr p += 2; 1070184588Sdfr 1071184588Sdfr if (p[0] != 0xff || p[1] != 0xff || p[2] != 0xff || p[3] != 0xff) 1072184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1073184588Sdfr p += 4; 1074184588Sdfr 1075184588Sdfr /* 1076184588Sdfr * SGN_CKSUM: 1077184588Sdfr * 1078184588Sdfr * Calculate the keyed checksum of the token header plus the 1079184588Sdfr * message. 1080184588Sdfr */ 1081184588Sdfr cklen = kc->kc_checksumkey->ks_class->ec_checksumlen; 1082184588Sdfr miclen = mic->m_len; 1083184588Sdfr mic->m_len = p - (uint8_t *) mic->m_data; 1084184588Sdfr mic->m_next = m; 1085184588Sdfr MGET(tm, M_WAITOK, MT_DATA); 1086184588Sdfr tm->m_len = cklen; 1087184588Sdfr mlast->m_next = tm; 1088184588Sdfr 1089184588Sdfr krb5_checksum(kc->kc_checksumkey, 15, mic, mic->m_len - 8, 1090184588Sdfr 8 + mlen, cklen); 1091184588Sdfr mic->m_next = NULL; 1092184588Sdfr mlast->m_next = NULL; 1093184588Sdfr if (bcmp(tm->m_data, p + 8, cklen)) { 1094184588Sdfr m_free(tm); 1095184588Sdfr return (GSS_S_BAD_SIG); 1096184588Sdfr } 1097184588Sdfr 1098184588Sdfr /* 1099184588Sdfr * SND_SEQ: 1100184588Sdfr * 1101184588Sdfr * Take the four bytes of the sequence number least 1102184588Sdfr * significant first followed by four bytes of direction 1103184588Sdfr * marker (zero for initiator and 0xff for acceptor). Encrypt 1104184588Sdfr * that data using the SGN_CKSUM as IV. Note: ARC4 wants the 1105184588Sdfr * sequence number big-endian. 1106184588Sdfr */ 1107184588Sdfr bcopy(p, tm->m_data, 8); 1108184588Sdfr tm->m_len = 8; 1109184588Sdfr krb5_decrypt(kc->kc_tokenkey, tm, 0, 8, p + 8, 8); 1110184588Sdfr 1111184588Sdfr tp = tm->m_data; 1112184588Sdfr if (sgn_alg[0] == 0x11) { 1113184588Sdfr seq = tp[3] | (tp[2] << 8) | (tp[1] << 16) | (tp[0] << 24); 1114184588Sdfr } else { 1115184588Sdfr seq = tp[0] | (tp[1] << 8) | (tp[2] << 16) | (tp[3] << 24); 1116184588Sdfr } 1117184588Sdfr 1118184588Sdfr if (is_initiator(kc)) { 1119184588Sdfr dir = 0xff; 1120184588Sdfr } else { 1121184588Sdfr dir = 0; 1122184588Sdfr } 1123184588Sdfr if (tp[4] != dir || tp[5] != dir || tp[6] != dir || tp[7] != dir) { 1124184588Sdfr m_free(tm); 1125184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1126184588Sdfr } 1127184588Sdfr m_free(tm); 1128184588Sdfr 1129184588Sdfr if (kc->kc_msg_order.km_flags & 1130184588Sdfr (GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG)) { 1131184588Sdfr return (krb5_sequence_check(kc, seq)); 1132184588Sdfr } 1133184588Sdfr 1134184588Sdfr return (GSS_S_COMPLETE); 1135184588Sdfr} 1136184588Sdfr 1137184588Sdfrstatic OM_uint32 1138184588Sdfrkrb5_verify_mic_new(struct krb5_context *kc, struct mbuf *m, struct mbuf *mic) 1139184588Sdfr{ 1140184588Sdfr OM_uint32 res; 1141184588Sdfr struct krb5_key_state *key = kc->kc_recv_sign_Kc; 1142184588Sdfr struct mbuf *mlast; 1143184588Sdfr uint8_t *p; 1144184588Sdfr int flags; 1145184588Sdfr size_t mlen, cklen; 1146184588Sdfr char buf[32]; 1147184588Sdfr 1148184588Sdfr mlen = m_length(m, &mlast); 1149184588Sdfr cklen = key->ks_class->ec_checksumlen; 1150184588Sdfr 1151184588Sdfr KASSERT(mic->m_next == NULL, ("MIC should be contiguous")); 1152184588Sdfr if (mic->m_len != 16 + cklen) 1153184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1154184588Sdfr p = mic->m_data; 1155184588Sdfr 1156184588Sdfr /* TOK_ID */ 1157184588Sdfr if (p[0] != 0x04) 1158184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1159184588Sdfr if (p[1] != 0x04) 1160184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1161184588Sdfr 1162184588Sdfr /* Flags */ 1163184588Sdfr flags = 0; 1164184588Sdfr if (is_initiator(kc)) 1165184588Sdfr flags |= GSS_TOKEN_SENT_BY_ACCEPTOR; 1166184588Sdfr if (kc->kc_more_flags & ACCEPTOR_SUBKEY) 1167184588Sdfr flags |= GSS_TOKEN_ACCEPTOR_SUBKEY; 1168184588Sdfr if (p[2] != flags) 1169184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1170184588Sdfr 1171184588Sdfr /* Filler */ 1172184588Sdfr if (p[3] != 0xff) 1173184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1174184588Sdfr if (p[4] != 0xff) 1175184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1176184588Sdfr if (p[5] != 0xff) 1177184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1178184588Sdfr if (p[6] != 0xff) 1179184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1180184588Sdfr if (p[7] != 0xff) 1181184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1182184588Sdfr 1183184588Sdfr /* SND_SEQ */ 1184184588Sdfr if (kc->kc_msg_order.km_flags & 1185184588Sdfr (GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG)) { 1186184588Sdfr uint32_t seq; 1187184588Sdfr if (p[8] || p[9] || p[10] || p[11]) { 1188184588Sdfr res = GSS_S_UNSEQ_TOKEN; 1189184588Sdfr } else { 1190184588Sdfr seq = (p[12] << 24) | (p[13] << 16) 1191184588Sdfr | (p[14] << 8) | p[15]; 1192184588Sdfr res = krb5_sequence_check(kc, seq); 1193184588Sdfr } 1194184588Sdfr if (GSS_ERROR(res)) 1195184588Sdfr return (res); 1196184588Sdfr } else { 1197184588Sdfr res = GSS_S_COMPLETE; 1198184588Sdfr } 1199184588Sdfr 1200184588Sdfr /* 1201184588Sdfr * SGN_CKSUM: 1202184588Sdfr * 1203184588Sdfr * Calculate the keyed checksum of the message plus the first 1204184588Sdfr * 16 bytes of the token header. 1205184588Sdfr */ 1206184588Sdfr m_copydata(mic, 16, cklen, buf); 1207184588Sdfr mlast->m_next = mic; 1208184588Sdfr krb5_checksum(key, 0, m, 0, mlen + 16, cklen); 1209184588Sdfr mlast->m_next = NULL; 1210184588Sdfr if (bcmp(buf, p + 16, cklen)) { 1211184588Sdfr return (GSS_S_BAD_SIG); 1212184588Sdfr } 1213184588Sdfr 1214184588Sdfr return (GSS_S_COMPLETE); 1215184588Sdfr} 1216184588Sdfr 1217184588Sdfrstatic OM_uint32 1218194202Srmacklemkrb5_verify_mic(gss_ctx_id_t ctx, OM_uint32 *minor_status, 1219184588Sdfr struct mbuf *m, struct mbuf *mic, gss_qop_t *qop_state) 1220184588Sdfr{ 1221194202Srmacklem struct krb5_context *kc = (struct krb5_context *)ctx; 1222184588Sdfr 1223184588Sdfr *minor_status = 0; 1224184588Sdfr if (qop_state) 1225184588Sdfr *qop_state = GSS_C_QOP_DEFAULT; 1226184588Sdfr 1227184588Sdfr if (time_uptime > kc->kc_lifetime) 1228184588Sdfr return (GSS_S_CONTEXT_EXPIRED); 1229184588Sdfr 1230184588Sdfr switch (kc->kc_tokenkey->ks_class->ec_type) { 1231184588Sdfr case ETYPE_DES_CBC_CRC: 1232184588Sdfr return (krb5_verify_mic_old(kc, m, mic, sgn_alg_des_md5)); 1233184588Sdfr 1234184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5: 1235184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5_56: 1236184588Sdfr return (krb5_verify_mic_old(kc, m, mic, sgn_alg_hmac_md5)); 1237184588Sdfr 1238184588Sdfr case ETYPE_DES3_CBC_SHA1: 1239184588Sdfr return (krb5_verify_mic_old(kc, m, mic, sgn_alg_des3_sha1)); 1240184588Sdfr 1241184588Sdfr default: 1242184588Sdfr return (krb5_verify_mic_new(kc, m, mic)); 1243184588Sdfr } 1244184588Sdfr 1245184588Sdfr return (GSS_S_FAILURE); 1246184588Sdfr} 1247184588Sdfr 1248184588Sdfrstatic OM_uint32 1249184588Sdfrkrb5_wrap_old(struct krb5_context *kc, int conf_req_flag, 1250184588Sdfr struct mbuf **mp, int *conf_state, 1251184588Sdfr uint8_t sgn_alg[2], uint8_t seal_alg[2]) 1252184588Sdfr{ 1253184588Sdfr struct mbuf *m, *mlast, *tm, *cm, *pm; 1254184588Sdfr size_t mlen, tlen, padlen, datalen; 1255184588Sdfr uint8_t *p, dir; 1256184588Sdfr size_t cklen; 1257184588Sdfr uint8_t buf[8]; 1258184588Sdfr uint32_t seq; 1259184588Sdfr 1260184588Sdfr /* 1261184588Sdfr * How many trailing pad bytes do we need? 1262184588Sdfr */ 1263184588Sdfr m = *mp; 1264184588Sdfr mlen = m_length(m, &mlast); 1265184588Sdfr tlen = kc->kc_tokenkey->ks_class->ec_msgblocklen; 1266184588Sdfr padlen = tlen - (mlen % tlen); 1267184588Sdfr 1268184588Sdfr /* 1269184588Sdfr * The data part of the token has eight bytes of random 1270184588Sdfr * confounder prepended and followed by up to eight bytes of 1271184588Sdfr * padding bytes each of which is set to the number of padding 1272184588Sdfr * bytes. 1273184588Sdfr */ 1274184588Sdfr datalen = mlen + 8 + padlen; 1275184588Sdfr tlen = token_length(kc->kc_tokenkey); 1276184588Sdfr 1277184588Sdfr p = krb5_make_token("\x02\x01", tlen, datalen + tlen, &tm); 1278184588Sdfr p += 2; /* TOK_ID */ 1279184588Sdfr *p++ = sgn_alg[0]; /* SGN_ALG */ 1280184588Sdfr *p++ = sgn_alg[1]; 1281184588Sdfr if (conf_req_flag) { 1282184588Sdfr *p++ = seal_alg[0]; /* SEAL_ALG */ 1283184588Sdfr *p++ = seal_alg[1]; 1284184588Sdfr } else { 1285184588Sdfr *p++ = 0xff; /* SEAL_ALG = none */ 1286184588Sdfr *p++ = 0xff; 1287184588Sdfr } 1288184588Sdfr 1289184588Sdfr *p++ = 0xff; /* filler */ 1290184588Sdfr *p++ = 0xff; 1291184588Sdfr 1292184588Sdfr /* 1293184588Sdfr * Copy the padded message data. 1294184588Sdfr */ 1295184588Sdfr if (M_LEADINGSPACE(m) >= 8) { 1296184588Sdfr m->m_data -= 8; 1297184588Sdfr m->m_len += 8; 1298184588Sdfr } else { 1299184588Sdfr MGET(cm, M_WAITOK, MT_DATA); 1300184588Sdfr cm->m_len = 8; 1301184588Sdfr cm->m_next = m; 1302184588Sdfr m = cm; 1303184588Sdfr } 1304184588Sdfr arc4rand(m->m_data, 8, 0); 1305184588Sdfr if (M_TRAILINGSPACE(mlast) >= padlen) { 1306184588Sdfr memset(mlast->m_data + mlast->m_len, padlen, padlen); 1307184588Sdfr mlast->m_len += padlen; 1308184588Sdfr } else { 1309184588Sdfr MGET(pm, M_WAITOK, MT_DATA); 1310184588Sdfr memset(pm->m_data, padlen, padlen); 1311184588Sdfr pm->m_len = padlen; 1312184588Sdfr mlast->m_next = pm; 1313184588Sdfr mlast = pm; 1314184588Sdfr } 1315184588Sdfr tm->m_next = m; 1316184588Sdfr 1317184588Sdfr /* 1318184588Sdfr * SGN_CKSUM: 1319184588Sdfr * 1320184588Sdfr * Calculate the keyed checksum of the token header plus the 1321184588Sdfr * padded message. Fiddle with tm->m_len so that we only 1322184588Sdfr * checksum the 8 bytes of head that we care about. 1323184588Sdfr */ 1324184588Sdfr cklen = kc->kc_checksumkey->ks_class->ec_checksumlen; 1325184588Sdfr tlen = tm->m_len; 1326184588Sdfr tm->m_len = p - (uint8_t *) tm->m_data; 1327184588Sdfr MGET(cm, M_WAITOK, MT_DATA); 1328184588Sdfr cm->m_len = cklen; 1329184588Sdfr mlast->m_next = cm; 1330184588Sdfr krb5_checksum(kc->kc_checksumkey, 13, tm, tm->m_len - 8, 1331184588Sdfr datalen + 8, cklen); 1332184588Sdfr tm->m_len = tlen; 1333184588Sdfr mlast->m_next = NULL; 1334184588Sdfr bcopy(cm->m_data, p + 8, cklen); 1335184588Sdfr m_free(cm); 1336184588Sdfr 1337184588Sdfr /* 1338184588Sdfr * SND_SEQ: 1339184588Sdfr * 1340184588Sdfr * Take the four bytes of the sequence number least 1341184588Sdfr * significant first (most signficant first for ARCFOUR) 1342184588Sdfr * followed by four bytes of direction marker (zero for 1343184588Sdfr * initiator and 0xff for acceptor). Encrypt that data using 1344184588Sdfr * the SGN_CKSUM as IV. 1345184588Sdfr */ 1346184588Sdfr seq = atomic_fetchadd_32(&kc->kc_local_seqnumber, 1); 1347184588Sdfr if (sgn_alg[0] == 0x11) { 1348184588Sdfr p[0] = (seq >> 24); 1349184588Sdfr p[1] = (seq >> 16); 1350184588Sdfr p[2] = (seq >> 8); 1351184588Sdfr p[3] = (seq >> 0); 1352184588Sdfr } else { 1353184588Sdfr p[0] = (seq >> 0); 1354184588Sdfr p[1] = (seq >> 8); 1355184588Sdfr p[2] = (seq >> 16); 1356184588Sdfr p[3] = (seq >> 24); 1357184588Sdfr } 1358184588Sdfr if (is_initiator(kc)) { 1359184588Sdfr dir = 0; 1360184588Sdfr } else { 1361184588Sdfr dir = 0xff; 1362184588Sdfr } 1363184588Sdfr p[4] = dir; 1364184588Sdfr p[5] = dir; 1365184588Sdfr p[6] = dir; 1366184588Sdfr p[7] = dir; 1367184588Sdfr krb5_encrypt(kc->kc_tokenkey, tm, p - (uint8_t *) tm->m_data, 1368184588Sdfr 8, p + 8, 8); 1369184588Sdfr 1370184588Sdfr if (conf_req_flag) { 1371184588Sdfr /* 1372184588Sdfr * Encrypt the padded message with an IV of zero for 1373184588Sdfr * DES and DES3, or an IV of the sequence number in 1374184588Sdfr * big-endian format for ARCFOUR. 1375184588Sdfr */ 1376184588Sdfr if (seal_alg[0] == 0x10) { 1377184588Sdfr buf[0] = (seq >> 24); 1378184588Sdfr buf[1] = (seq >> 16); 1379184588Sdfr buf[2] = (seq >> 8); 1380184588Sdfr buf[3] = (seq >> 0); 1381184588Sdfr krb5_encrypt(kc->kc_encryptkey, m, 0, datalen, 1382184588Sdfr buf, 4); 1383184588Sdfr } else { 1384184588Sdfr krb5_encrypt(kc->kc_encryptkey, m, 0, datalen, 1385184588Sdfr NULL, 0); 1386184588Sdfr } 1387184588Sdfr } 1388184588Sdfr 1389184588Sdfr if (conf_state) 1390184588Sdfr *conf_state = conf_req_flag; 1391184588Sdfr 1392184588Sdfr *mp = tm; 1393184588Sdfr return (GSS_S_COMPLETE); 1394184588Sdfr} 1395184588Sdfr 1396184588Sdfrstatic OM_uint32 1397184588Sdfrkrb5_wrap_new(struct krb5_context *kc, int conf_req_flag, 1398184588Sdfr struct mbuf **mp, int *conf_state) 1399184588Sdfr{ 1400184588Sdfr struct krb5_key_state *Ke = kc->kc_send_seal_Ke; 1401184588Sdfr struct krb5_key_state *Ki = kc->kc_send_seal_Ki; 1402184588Sdfr struct krb5_key_state *Kc = kc->kc_send_seal_Kc; 1403184588Sdfr const struct krb5_encryption_class *ec = Ke->ks_class; 1404184588Sdfr struct mbuf *m, *mlast, *tm; 1405184588Sdfr uint8_t *p; 1406184588Sdfr int flags, EC; 1407184588Sdfr size_t mlen, blen, mblen, cklen, ctlen; 1408184588Sdfr uint32_t seq; 1409184588Sdfr static char zpad[32]; 1410184588Sdfr 1411184588Sdfr m = *mp; 1412184588Sdfr mlen = m_length(m, &mlast); 1413184588Sdfr 1414184588Sdfr blen = ec->ec_blocklen; 1415184588Sdfr mblen = ec->ec_msgblocklen; 1416184588Sdfr cklen = ec->ec_checksumlen; 1417184588Sdfr 1418184588Sdfr if (conf_req_flag) { 1419184588Sdfr /* 1420184588Sdfr * For sealed messages, we need space for 16 bytes of 1421184588Sdfr * header, blen confounder, plaintext, padding, copy 1422184588Sdfr * of header and checksum. 1423184588Sdfr * 1424184588Sdfr * We pad to mblen (which may be different from 1425184588Sdfr * blen). If the encryption class is using CTS, mblen 1426184588Sdfr * will be one (i.e. no padding required). 1427184588Sdfr */ 1428184588Sdfr if (mblen > 1) 1429184588Sdfr EC = mlen % mblen; 1430184588Sdfr else 1431184588Sdfr EC = 0; 1432184588Sdfr ctlen = blen + mlen + EC + 16; 1433184588Sdfr 1434184588Sdfr /* 1435184588Sdfr * Put initial header and confounder before the 1436184588Sdfr * message. 1437184588Sdfr */ 1438184588Sdfr M_PREPEND(m, 16 + blen, M_WAITOK); 1439184588Sdfr 1440184588Sdfr /* 1441184588Sdfr * Append padding + copy of header and checksum. Try 1442184588Sdfr * to fit this into the end of the original message, 1443184588Sdfr * otherwise allocate a trailer. 1444184588Sdfr */ 1445184588Sdfr if (M_TRAILINGSPACE(mlast) >= EC + 16 + cklen) { 1446184588Sdfr tm = NULL; 1447184588Sdfr mlast->m_len += EC + 16 + cklen; 1448184588Sdfr } else { 1449184588Sdfr MGET(tm, M_WAITOK, MT_DATA); 1450184588Sdfr tm->m_len = EC + 16 + cklen; 1451184588Sdfr mlast->m_next = tm; 1452184588Sdfr } 1453184588Sdfr } else { 1454184588Sdfr /* 1455184588Sdfr * For unsealed messages, we need 16 bytes of header 1456184588Sdfr * plus space for the plaintext and a checksum. EC is 1457184588Sdfr * set to the checksum size. We leave space in tm for 1458184588Sdfr * a copy of the header - this will be trimmed later. 1459184588Sdfr */ 1460184588Sdfr M_PREPEND(m, 16, M_WAITOK); 1461184588Sdfr 1462184588Sdfr MGET(tm, M_WAITOK, MT_DATA); 1463184588Sdfr tm->m_len = cklen + 16; 1464184588Sdfr mlast->m_next = tm; 1465184588Sdfr ctlen = 0; 1466184588Sdfr EC = cklen; 1467184588Sdfr } 1468184588Sdfr 1469184588Sdfr p = m->m_data; 1470184588Sdfr 1471184588Sdfr /* TOK_ID */ 1472184588Sdfr p[0] = 0x05; 1473184588Sdfr p[1] = 0x04; 1474184588Sdfr 1475184588Sdfr /* Flags */ 1476184588Sdfr flags = 0; 1477184588Sdfr if (conf_req_flag) 1478184588Sdfr flags = GSS_TOKEN_SEALED; 1479184588Sdfr if (is_acceptor(kc)) 1480184588Sdfr flags |= GSS_TOKEN_SENT_BY_ACCEPTOR; 1481184588Sdfr if (kc->kc_more_flags & ACCEPTOR_SUBKEY) 1482184588Sdfr flags |= GSS_TOKEN_ACCEPTOR_SUBKEY; 1483184588Sdfr p[2] = flags; 1484184588Sdfr 1485184588Sdfr /* Filler */ 1486184588Sdfr p[3] = 0xff; 1487184588Sdfr 1488184588Sdfr /* EC + RRC - set to zero initially */ 1489184588Sdfr p[4] = 0; 1490184588Sdfr p[5] = 0; 1491184588Sdfr p[6] = 0; 1492184588Sdfr p[7] = 0; 1493184588Sdfr 1494184588Sdfr /* SND_SEQ */ 1495184588Sdfr p[8] = 0; 1496184588Sdfr p[9] = 0; 1497184588Sdfr p[10] = 0; 1498184588Sdfr p[11] = 0; 1499184588Sdfr seq = atomic_fetchadd_32(&kc->kc_local_seqnumber, 1); 1500184588Sdfr p[12] = (seq >> 24); 1501184588Sdfr p[13] = (seq >> 16); 1502184588Sdfr p[14] = (seq >> 8); 1503184588Sdfr p[15] = (seq >> 0); 1504184588Sdfr 1505184588Sdfr if (conf_req_flag) { 1506184588Sdfr /* 1507184588Sdfr * Encrypt according to RFC 4121 section 4.2 and RFC 1508184588Sdfr * 3961 section 5.3. Note: we don't generate tokens 1509184588Sdfr * with RRC values other than zero. If we did, we 1510184588Sdfr * should zero RRC in the copied header. 1511184588Sdfr */ 1512184588Sdfr arc4rand(p + 16, blen, 0); 1513184588Sdfr if (EC) { 1514184588Sdfr m_copyback(m, 16 + blen + mlen, EC, zpad); 1515184588Sdfr } 1516184588Sdfr m_copyback(m, 16 + blen + mlen + EC, 16, p); 1517184588Sdfr 1518184588Sdfr krb5_checksum(Ki, 0, m, 16, ctlen, cklen); 1519184588Sdfr krb5_encrypt(Ke, m, 16, ctlen, NULL, 0); 1520184588Sdfr } else { 1521184588Sdfr /* 1522184588Sdfr * The plaintext message is followed by a checksum of 1523184588Sdfr * the plaintext plus a version of the header where EC 1524184588Sdfr * and RRC are set to zero. Also, the original EC must 1525184588Sdfr * be our checksum size. 1526184588Sdfr */ 1527184588Sdfr bcopy(p, tm->m_data, 16); 1528184588Sdfr krb5_checksum(Kc, 0, m, 16, mlen + 16, cklen); 1529184588Sdfr tm->m_data += 16; 1530184588Sdfr tm->m_len -= 16; 1531184588Sdfr } 1532184588Sdfr 1533184588Sdfr /* 1534184588Sdfr * Finally set EC to its actual value 1535184588Sdfr */ 1536184588Sdfr p[4] = EC >> 8; 1537184588Sdfr p[5] = EC; 1538184588Sdfr 1539184588Sdfr *mp = m; 1540184588Sdfr return (GSS_S_COMPLETE); 1541184588Sdfr} 1542184588Sdfr 1543184588Sdfrstatic OM_uint32 1544194202Srmacklemkrb5_wrap(gss_ctx_id_t ctx, OM_uint32 *minor_status, 1545184588Sdfr int conf_req_flag, gss_qop_t qop_req, 1546184588Sdfr struct mbuf **mp, int *conf_state) 1547184588Sdfr{ 1548194202Srmacklem struct krb5_context *kc = (struct krb5_context *)ctx; 1549184588Sdfr 1550184588Sdfr *minor_status = 0; 1551184588Sdfr if (conf_state) 1552184588Sdfr *conf_state = 0; 1553184588Sdfr 1554184588Sdfr if (qop_req != GSS_C_QOP_DEFAULT) 1555184588Sdfr return (GSS_S_BAD_QOP); 1556184588Sdfr 1557184588Sdfr if (time_uptime > kc->kc_lifetime) 1558184588Sdfr return (GSS_S_CONTEXT_EXPIRED); 1559184588Sdfr 1560184588Sdfr switch (kc->kc_tokenkey->ks_class->ec_type) { 1561184588Sdfr case ETYPE_DES_CBC_CRC: 1562184588Sdfr return (krb5_wrap_old(kc, conf_req_flag, 1563184588Sdfr mp, conf_state, sgn_alg_des_md5, seal_alg_des)); 1564184588Sdfr 1565184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5: 1566184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5_56: 1567184588Sdfr return (krb5_wrap_old(kc, conf_req_flag, 1568184588Sdfr mp, conf_state, sgn_alg_hmac_md5, seal_alg_rc4)); 1569184588Sdfr 1570184588Sdfr case ETYPE_DES3_CBC_SHA1: 1571184588Sdfr return (krb5_wrap_old(kc, conf_req_flag, 1572184588Sdfr mp, conf_state, sgn_alg_des3_sha1, seal_alg_des3)); 1573184588Sdfr 1574184588Sdfr default: 1575184588Sdfr return (krb5_wrap_new(kc, conf_req_flag, mp, conf_state)); 1576184588Sdfr } 1577184588Sdfr 1578184588Sdfr return (GSS_S_FAILURE); 1579184588Sdfr} 1580184588Sdfr 1581184588Sdfrstatic void 1582184588Sdfrm_trim(struct mbuf *m, int len) 1583184588Sdfr{ 1584184588Sdfr struct mbuf *n; 1585184588Sdfr int off; 1586184588Sdfr 1587184588Sdfr n = m_getptr(m, len, &off); 1588184588Sdfr if (n) { 1589184588Sdfr n->m_len = off; 1590184588Sdfr if (n->m_next) { 1591184588Sdfr m_freem(n->m_next); 1592184588Sdfr n->m_next = NULL; 1593184588Sdfr } 1594184588Sdfr } 1595184588Sdfr} 1596184588Sdfr 1597184588Sdfrstatic OM_uint32 1598184588Sdfrkrb5_unwrap_old(struct krb5_context *kc, struct mbuf **mp, int *conf_state, 1599184588Sdfr uint8_t sgn_alg[2], uint8_t seal_alg[2]) 1600184588Sdfr{ 1601184588Sdfr OM_uint32 res; 1602184588Sdfr struct mbuf *m, *mlast, *hm, *cm; 1603184588Sdfr uint8_t *p, dir; 1604184588Sdfr size_t mlen, tlen, elen, datalen, padlen; 1605184588Sdfr size_t cklen; 1606184588Sdfr uint8_t buf[32]; 1607184588Sdfr uint32_t seq; 1608184588Sdfr int i, conf; 1609184588Sdfr 1610184588Sdfr m = *mp; 1611184588Sdfr mlen = m_length(m, &mlast); 1612184588Sdfr 1613184588Sdfr tlen = token_length(kc->kc_tokenkey); 1614184588Sdfr cklen = kc->kc_tokenkey->ks_class->ec_checksumlen; 1615184588Sdfr 1616184588Sdfr p = krb5_verify_token("\x02\x01", tlen, &m, &elen, TRUE); 1617184588Sdfr *mp = m; 1618184588Sdfr if (!p) 1619184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1620184588Sdfr datalen = elen - tlen; 1621184588Sdfr 1622184588Sdfr /* 1623184588Sdfr * Trim the framing header first to make life a little easier 1624184588Sdfr * later. 1625184588Sdfr */ 1626184588Sdfr m_adj(m, p - (uint8_t *) m->m_data); 1627184588Sdfr 1628184588Sdfr /* TOK_ID */ 1629184588Sdfr p += 2; 1630184588Sdfr 1631184588Sdfr /* SGN_ALG */ 1632184588Sdfr if (p[0] != sgn_alg[0] || p[1] != sgn_alg[1]) 1633184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1634184588Sdfr p += 2; 1635184588Sdfr 1636184588Sdfr /* SEAL_ALG */ 1637184588Sdfr if (p[0] == seal_alg[0] && p[1] == seal_alg[1]) 1638184588Sdfr conf = 1; 1639184588Sdfr else if (p[0] == 0xff && p[1] == 0xff) 1640184588Sdfr conf = 0; 1641184588Sdfr else 1642184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1643184588Sdfr p += 2; 1644184588Sdfr 1645184588Sdfr if (p[0] != 0xff || p[1] != 0xff) 1646184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1647184588Sdfr p += 2; 1648184588Sdfr 1649184588Sdfr /* 1650184588Sdfr * SND_SEQ: 1651184588Sdfr * 1652184588Sdfr * Take the four bytes of the sequence number least 1653184588Sdfr * significant first (most significant for ARCFOUR) followed 1654184588Sdfr * by four bytes of direction marker (zero for initiator and 1655184588Sdfr * 0xff for acceptor). Encrypt that data using the SGN_CKSUM 1656184588Sdfr * as IV. 1657184588Sdfr */ 1658184588Sdfr krb5_decrypt(kc->kc_tokenkey, m, 8, 8, p + 8, 8); 1659184588Sdfr if (sgn_alg[0] == 0x11) { 1660184588Sdfr seq = p[3] | (p[2] << 8) | (p[1] << 16) | (p[0] << 24); 1661184588Sdfr } else { 1662184588Sdfr seq = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); 1663184588Sdfr } 1664184588Sdfr 1665184588Sdfr if (is_initiator(kc)) { 1666184588Sdfr dir = 0xff; 1667184588Sdfr } else { 1668184588Sdfr dir = 0; 1669184588Sdfr } 1670184588Sdfr if (p[4] != dir || p[5] != dir || p[6] != dir || p[7] != dir) 1671184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1672184588Sdfr 1673184588Sdfr if (kc->kc_msg_order.km_flags & 1674184588Sdfr (GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG)) { 1675184588Sdfr res = krb5_sequence_check(kc, seq); 1676184588Sdfr if (GSS_ERROR(res)) 1677184588Sdfr return (res); 1678184588Sdfr } else { 1679184588Sdfr res = GSS_S_COMPLETE; 1680184588Sdfr } 1681184588Sdfr 1682184588Sdfr /* 1683184588Sdfr * If the token was encrypted, decode it in-place. 1684184588Sdfr */ 1685184588Sdfr if (conf) { 1686184588Sdfr /* 1687184588Sdfr * Decrypt the padded message with an IV of zero for 1688184588Sdfr * DES and DES3 or an IV of the big-endian encoded 1689184588Sdfr * sequence number for ARCFOUR. 1690184588Sdfr */ 1691184588Sdfr if (seal_alg[0] == 0x10) { 1692184588Sdfr krb5_decrypt(kc->kc_encryptkey, m, 16 + cklen, 1693184588Sdfr datalen, p, 4); 1694184588Sdfr } else { 1695184588Sdfr krb5_decrypt(kc->kc_encryptkey, m, 16 + cklen, 1696184588Sdfr datalen, NULL, 0); 1697184588Sdfr } 1698184588Sdfr } 1699184588Sdfr if (conf_state) 1700184588Sdfr *conf_state = conf; 1701184588Sdfr 1702184588Sdfr /* 1703184588Sdfr * Check the trailing pad bytes. 1704184588Sdfr */ 1705184588Sdfr KASSERT(mlast->m_len > 0, ("Unexpected empty mbuf")); 1706184588Sdfr padlen = mlast->m_data[mlast->m_len - 1]; 1707184588Sdfr m_copydata(m, tlen + datalen - padlen, padlen, buf); 1708184588Sdfr for (i = 0; i < padlen; i++) { 1709184588Sdfr if (buf[i] != padlen) { 1710184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1711184588Sdfr } 1712184588Sdfr } 1713184588Sdfr 1714184588Sdfr /* 1715184588Sdfr * SGN_CKSUM: 1716184588Sdfr * 1717184588Sdfr * Calculate the keyed checksum of the token header plus the 1718184588Sdfr * padded message. We do a little mbuf surgery to trim out the 1719184588Sdfr * parts we don't want to checksum. 1720184588Sdfr */ 1721184588Sdfr hm = m; 1722184588Sdfr *mp = m = m_split(m, 16 + cklen, M_WAITOK); 1723184588Sdfr mlast = m_last(m); 1724184588Sdfr hm->m_len = 8; 1725184588Sdfr hm->m_next = m; 1726184588Sdfr MGET(cm, M_WAITOK, MT_DATA); 1727184588Sdfr cm->m_len = cklen; 1728184588Sdfr mlast->m_next = cm; 1729184588Sdfr 1730184588Sdfr krb5_checksum(kc->kc_checksumkey, 13, hm, 0, datalen + 8, cklen); 1731184588Sdfr hm->m_next = NULL; 1732184588Sdfr mlast->m_next = NULL; 1733184588Sdfr 1734184588Sdfr if (bcmp(cm->m_data, hm->m_data + 16, cklen)) { 1735184588Sdfr m_freem(hm); 1736184588Sdfr m_free(cm); 1737184588Sdfr return (GSS_S_BAD_SIG); 1738184588Sdfr } 1739184588Sdfr m_freem(hm); 1740184588Sdfr m_free(cm); 1741184588Sdfr 1742184588Sdfr /* 1743184588Sdfr * Trim off the confounder and padding. 1744184588Sdfr */ 1745184588Sdfr m_adj(m, 8); 1746184588Sdfr if (mlast->m_len >= padlen) { 1747184588Sdfr mlast->m_len -= padlen; 1748184588Sdfr } else { 1749184588Sdfr m_trim(m, datalen - 8 - padlen); 1750184588Sdfr } 1751184588Sdfr 1752184588Sdfr *mp = m; 1753184588Sdfr return (res); 1754184588Sdfr} 1755184588Sdfr 1756184588Sdfrstatic OM_uint32 1757184588Sdfrkrb5_unwrap_new(struct krb5_context *kc, struct mbuf **mp, int *conf_state) 1758184588Sdfr{ 1759184588Sdfr OM_uint32 res; 1760184588Sdfr struct krb5_key_state *Ke = kc->kc_recv_seal_Ke; 1761184588Sdfr struct krb5_key_state *Ki = kc->kc_recv_seal_Ki; 1762184588Sdfr struct krb5_key_state *Kc = kc->kc_recv_seal_Kc; 1763184588Sdfr const struct krb5_encryption_class *ec = Ke->ks_class; 1764184588Sdfr struct mbuf *m, *mlast, *hm, *cm; 1765184588Sdfr uint8_t *p, *pp; 1766184588Sdfr int sealed, flags, EC, RRC; 1767184588Sdfr size_t blen, cklen, ctlen, mlen, plen, tlen; 1768184588Sdfr char buf[32], buf2[32]; 1769184588Sdfr 1770184588Sdfr m = *mp; 1771184588Sdfr mlen = m_length(m, &mlast); 1772184588Sdfr 1773184588Sdfr if (mlen <= 16) 1774184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1775184588Sdfr if (m->m_len < 16) { 1776184588Sdfr m = m_pullup(m, 16); 1777184588Sdfr *mp = m; 1778184588Sdfr } 1779184588Sdfr p = m->m_data; 1780184588Sdfr 1781184588Sdfr /* TOK_ID */ 1782184588Sdfr if (p[0] != 0x05) 1783184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1784184588Sdfr if (p[1] != 0x04) 1785184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1786184588Sdfr 1787184588Sdfr /* Flags */ 1788184588Sdfr sealed = p[2] & GSS_TOKEN_SEALED; 1789184588Sdfr flags = sealed; 1790184588Sdfr if (is_initiator(kc)) 1791184588Sdfr flags |= GSS_TOKEN_SENT_BY_ACCEPTOR; 1792184588Sdfr if (kc->kc_more_flags & ACCEPTOR_SUBKEY) 1793184588Sdfr flags |= GSS_TOKEN_ACCEPTOR_SUBKEY; 1794184588Sdfr if (p[2] != flags) 1795184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1796184588Sdfr 1797184588Sdfr /* Filler */ 1798184588Sdfr if (p[3] != 0xff) 1799184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1800184588Sdfr 1801184588Sdfr /* EC + RRC */ 1802184588Sdfr EC = (p[4] << 8) + p[5]; 1803184588Sdfr RRC = (p[6] << 8) + p[7]; 1804184588Sdfr 1805184588Sdfr /* SND_SEQ */ 1806184588Sdfr if (kc->kc_msg_order.km_flags & 1807184588Sdfr (GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG)) { 1808184588Sdfr uint32_t seq; 1809184588Sdfr if (p[8] || p[9] || p[10] || p[11]) { 1810184588Sdfr res = GSS_S_UNSEQ_TOKEN; 1811184588Sdfr } else { 1812184588Sdfr seq = (p[12] << 24) | (p[13] << 16) 1813184588Sdfr | (p[14] << 8) | p[15]; 1814184588Sdfr res = krb5_sequence_check(kc, seq); 1815184588Sdfr } 1816184588Sdfr if (GSS_ERROR(res)) 1817184588Sdfr return (res); 1818184588Sdfr } else { 1819184588Sdfr res = GSS_S_COMPLETE; 1820184588Sdfr } 1821184588Sdfr 1822184588Sdfr /* 1823184588Sdfr * Separate the header before dealing with RRC. We only need 1824184588Sdfr * to keep the header if the message isn't encrypted. 1825184588Sdfr */ 1826184588Sdfr if (sealed) { 1827184588Sdfr hm = NULL; 1828184588Sdfr m_adj(m, 16); 1829184588Sdfr } else { 1830184588Sdfr hm = m; 1831184588Sdfr *mp = m = m_split(m, 16, M_WAITOK); 1832184588Sdfr mlast = m_last(m); 1833184588Sdfr } 1834184588Sdfr 1835184588Sdfr /* 1836184588Sdfr * Undo the effects of RRC by rotating left. 1837184588Sdfr */ 1838184588Sdfr if (RRC > 0) { 1839184588Sdfr struct mbuf *rm; 1840184588Sdfr size_t rlen; 1841184588Sdfr 1842184588Sdfr rlen = mlen - 16; 1843184588Sdfr if (RRC <= sizeof(buf) && m->m_len >= rlen) { 1844184588Sdfr /* 1845184588Sdfr * Simple case, just rearrange the bytes in m. 1846184588Sdfr */ 1847184588Sdfr bcopy(m->m_data, buf, RRC); 1848184588Sdfr bcopy(m->m_data + RRC, m->m_data, rlen - RRC); 1849184588Sdfr bcopy(buf, m->m_data + rlen - RRC, RRC); 1850184588Sdfr } else { 1851184588Sdfr /* 1852184588Sdfr * More complicated - rearrange the mbuf 1853184588Sdfr * chain. 1854184588Sdfr */ 1855184588Sdfr rm = m; 1856184588Sdfr *mp = m = m_split(m, RRC, M_WAITOK); 1857184588Sdfr m_cat(m, rm); 1858184588Sdfr mlast = rm; 1859184588Sdfr } 1860184588Sdfr } 1861184588Sdfr 1862184588Sdfr blen = ec->ec_blocklen; 1863184588Sdfr cklen = ec->ec_checksumlen; 1864184588Sdfr if (sealed) { 1865184588Sdfr /* 1866184588Sdfr * Decrypt according to RFC 4121 section 4.2 and RFC 1867184588Sdfr * 3961 section 5.3. The message must be large enough 1868184588Sdfr * for a blocksize confounder, at least one block of 1869184588Sdfr * cyphertext and a checksum. 1870184588Sdfr */ 1871184588Sdfr if (mlen < 16 + 2*blen + cklen) 1872184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1873184588Sdfr 1874184588Sdfr ctlen = mlen - 16 - cklen; 1875184588Sdfr krb5_decrypt(Ke, m, 0, ctlen, NULL, 0); 1876184588Sdfr 1877184588Sdfr /* 1878184588Sdfr * The size of the plaintext is ctlen minus blocklen 1879184588Sdfr * (for the confounder), 16 (for the copy of the token 1880184588Sdfr * header) and EC (for the filler). The actual 1881184588Sdfr * plaintext starts after the confounder. 1882184588Sdfr */ 1883184588Sdfr plen = ctlen - blen - 16 - EC; 1884184588Sdfr pp = p + 16 + blen; 1885184588Sdfr 1886184588Sdfr /* 1887184588Sdfr * Checksum the padded plaintext. 1888184588Sdfr */ 1889184588Sdfr m_copydata(m, ctlen, cklen, buf); 1890184588Sdfr krb5_checksum(Ki, 0, m, 0, ctlen, cklen); 1891184588Sdfr m_copydata(m, ctlen, cklen, buf2); 1892184588Sdfr 1893184588Sdfr if (bcmp(buf, buf2, cklen)) 1894184588Sdfr return (GSS_S_BAD_SIG); 1895184588Sdfr 1896184588Sdfr /* 1897184588Sdfr * Trim the message back to just plaintext. 1898184588Sdfr */ 1899184588Sdfr m_adj(m, blen); 1900184588Sdfr tlen = 16 + EC + cklen; 1901184588Sdfr if (mlast->m_len >= tlen) { 1902184588Sdfr mlast->m_len -= tlen; 1903184588Sdfr } else { 1904184588Sdfr m_trim(m, plen); 1905184588Sdfr } 1906184588Sdfr } else { 1907184588Sdfr /* 1908184588Sdfr * The plaintext message is followed by a checksum of 1909184588Sdfr * the plaintext plus a version of the header where EC 1910184588Sdfr * and RRC are set to zero. Also, the original EC must 1911184588Sdfr * be our checksum size. 1912184588Sdfr */ 1913184588Sdfr if (mlen < 16 + cklen || EC != cklen) 1914184588Sdfr return (GSS_S_DEFECTIVE_TOKEN); 1915184588Sdfr 1916184588Sdfr /* 1917184588Sdfr * The size of the plaintext is simply the message 1918184588Sdfr * size less header and checksum. The plaintext starts 1919184588Sdfr * right after the header (which we have saved in hm). 1920184588Sdfr */ 1921184588Sdfr plen = mlen - 16 - cklen; 1922184588Sdfr 1923184588Sdfr /* 1924184588Sdfr * Insert a copy of the header (with EC and RRC set to 1925184588Sdfr * zero) between the plaintext message and the 1926184588Sdfr * checksum. 1927184588Sdfr */ 1928184588Sdfr p = hm->m_data; 1929184588Sdfr p[4] = p[5] = p[6] = p[7] = 0; 1930184588Sdfr 1931184588Sdfr cm = m_split(m, plen, M_WAITOK); 1932184588Sdfr mlast = m_last(m); 1933184588Sdfr m->m_next = hm; 1934184588Sdfr hm->m_next = cm; 1935184588Sdfr 1936184588Sdfr bcopy(cm->m_data, buf, cklen); 1937184588Sdfr krb5_checksum(Kc, 0, m, 0, plen + 16, cklen); 1938184588Sdfr if (bcmp(cm->m_data, buf, cklen)) 1939184588Sdfr return (GSS_S_BAD_SIG); 1940184588Sdfr 1941184588Sdfr /* 1942184588Sdfr * The checksum matches, discard all buf the plaintext. 1943184588Sdfr */ 1944184588Sdfr mlast->m_next = NULL; 1945184588Sdfr m_freem(hm); 1946184588Sdfr } 1947184588Sdfr 1948184588Sdfr if (conf_state) 1949184588Sdfr *conf_state = (sealed != 0); 1950184588Sdfr 1951184588Sdfr return (res); 1952184588Sdfr} 1953184588Sdfr 1954184588Sdfrstatic OM_uint32 1955194202Srmacklemkrb5_unwrap(gss_ctx_id_t ctx, OM_uint32 *minor_status, 1956184588Sdfr struct mbuf **mp, int *conf_state, gss_qop_t *qop_state) 1957184588Sdfr{ 1958194202Srmacklem struct krb5_context *kc = (struct krb5_context *)ctx; 1959184588Sdfr OM_uint32 maj_stat; 1960184588Sdfr 1961184588Sdfr *minor_status = 0; 1962184588Sdfr if (qop_state) 1963184588Sdfr *qop_state = GSS_C_QOP_DEFAULT; 1964184588Sdfr if (conf_state) 1965184588Sdfr *conf_state = 0; 1966184588Sdfr 1967184588Sdfr if (time_uptime > kc->kc_lifetime) 1968184588Sdfr return (GSS_S_CONTEXT_EXPIRED); 1969184588Sdfr 1970184588Sdfr switch (kc->kc_tokenkey->ks_class->ec_type) { 1971184588Sdfr case ETYPE_DES_CBC_CRC: 1972184588Sdfr maj_stat = krb5_unwrap_old(kc, mp, conf_state, 1973184588Sdfr sgn_alg_des_md5, seal_alg_des); 1974184588Sdfr break; 1975184588Sdfr 1976184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5: 1977184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5_56: 1978184588Sdfr maj_stat = krb5_unwrap_old(kc, mp, conf_state, 1979184588Sdfr sgn_alg_hmac_md5, seal_alg_rc4); 1980184588Sdfr break; 1981184588Sdfr 1982184588Sdfr case ETYPE_DES3_CBC_SHA1: 1983184588Sdfr maj_stat = krb5_unwrap_old(kc, mp, conf_state, 1984184588Sdfr sgn_alg_des3_sha1, seal_alg_des3); 1985184588Sdfr break; 1986184588Sdfr 1987184588Sdfr default: 1988184588Sdfr maj_stat = krb5_unwrap_new(kc, mp, conf_state); 1989184588Sdfr break; 1990184588Sdfr } 1991184588Sdfr 1992184588Sdfr if (GSS_ERROR(maj_stat)) { 1993184588Sdfr m_freem(*mp); 1994184588Sdfr *mp = NULL; 1995184588Sdfr } 1996184588Sdfr 1997184588Sdfr return (maj_stat); 1998184588Sdfr} 1999184588Sdfr 2000184588Sdfrstatic OM_uint32 2001194202Srmacklemkrb5_wrap_size_limit(gss_ctx_id_t ctx, OM_uint32 *minor_status, 2002184588Sdfr int conf_req_flag, gss_qop_t qop_req, OM_uint32 req_output_size, 2003184588Sdfr OM_uint32 *max_input_size) 2004184588Sdfr{ 2005194202Srmacklem struct krb5_context *kc = (struct krb5_context *)ctx; 2006184588Sdfr const struct krb5_encryption_class *ec; 2007184588Sdfr OM_uint32 overhead; 2008184588Sdfr 2009184588Sdfr *minor_status = 0; 2010184588Sdfr *max_input_size = 0; 2011184588Sdfr 2012184588Sdfr if (qop_req != GSS_C_QOP_DEFAULT) 2013184588Sdfr return (GSS_S_BAD_QOP); 2014184588Sdfr 2015184588Sdfr ec = kc->kc_tokenkey->ks_class; 2016184588Sdfr switch (ec->ec_type) { 2017184588Sdfr case ETYPE_DES_CBC_CRC: 2018184588Sdfr case ETYPE_DES3_CBC_SHA1: 2019184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5: 2020184588Sdfr case ETYPE_ARCFOUR_HMAC_MD5_56: 2021184588Sdfr /* 2022184588Sdfr * up to 5 bytes for [APPLICATION 0] SEQUENCE 2023184588Sdfr * 2 + krb5 oid length 2024184588Sdfr * 8 bytes of header 2025184588Sdfr * 8 bytes of confounder 2026184588Sdfr * maximum of 8 bytes of padding 2027184588Sdfr * checksum 2028184588Sdfr */ 2029184588Sdfr overhead = 5 + 2 + krb5_mech_oid.length; 2030184588Sdfr overhead += 8 + 8 + ec->ec_msgblocklen; 2031184588Sdfr overhead += ec->ec_checksumlen; 2032184588Sdfr break; 2033184588Sdfr 2034184588Sdfr default: 2035184588Sdfr if (conf_req_flag) { 2036184588Sdfr /* 2037184588Sdfr * 16 byts of header 2038184588Sdfr * blocklen bytes of confounder 2039184588Sdfr * up to msgblocklen - 1 bytes of padding 2040184588Sdfr * 16 bytes for copy of header 2041184588Sdfr * checksum 2042184588Sdfr */ 2043184588Sdfr overhead = 16 + ec->ec_blocklen; 2044184588Sdfr overhead += ec->ec_msgblocklen - 1; 2045184588Sdfr overhead += 16; 2046184588Sdfr overhead += ec->ec_checksumlen; 2047184588Sdfr } else { 2048184588Sdfr /* 2049184588Sdfr * 16 bytes of header plus checksum. 2050184588Sdfr */ 2051184588Sdfr overhead = 16 + ec->ec_checksumlen; 2052184588Sdfr } 2053184588Sdfr } 2054184588Sdfr 2055184588Sdfr *max_input_size = req_output_size - overhead; 2056184588Sdfr 2057184588Sdfr return (GSS_S_COMPLETE); 2058184588Sdfr} 2059184588Sdfr 2060184588Sdfrstatic kobj_method_t krb5_methods[] = { 2061184588Sdfr KOBJMETHOD(kgss_init, krb5_init), 2062184588Sdfr KOBJMETHOD(kgss_import, krb5_import), 2063184588Sdfr KOBJMETHOD(kgss_delete, krb5_delete), 2064184588Sdfr KOBJMETHOD(kgss_mech_type, krb5_mech_type), 2065184588Sdfr KOBJMETHOD(kgss_get_mic, krb5_get_mic), 2066184588Sdfr KOBJMETHOD(kgss_verify_mic, krb5_verify_mic), 2067184588Sdfr KOBJMETHOD(kgss_wrap, krb5_wrap), 2068184588Sdfr KOBJMETHOD(kgss_unwrap, krb5_unwrap), 2069184588Sdfr KOBJMETHOD(kgss_wrap_size_limit, krb5_wrap_size_limit), 2070184588Sdfr { 0, 0 } 2071184588Sdfr}; 2072184588Sdfr 2073184588Sdfrstatic struct kobj_class krb5_class = { 2074184588Sdfr "kerberosv5", 2075184588Sdfr krb5_methods, 2076184588Sdfr sizeof(struct krb5_context) 2077184588Sdfr}; 2078184588Sdfr 2079184588Sdfr/* 2080184588Sdfr * Kernel module glue 2081184588Sdfr */ 2082184588Sdfrstatic int 2083184588Sdfrkgssapi_krb5_modevent(module_t mod, int type, void *data) 2084184588Sdfr{ 2085184588Sdfr 2086184588Sdfr switch (type) { 2087184588Sdfr case MOD_LOAD: 2088184588Sdfr kgss_install_mech(&krb5_mech_oid, "kerberosv5", &krb5_class); 2089184588Sdfr break; 2090184588Sdfr 2091184588Sdfr case MOD_UNLOAD: 2092184588Sdfr kgss_uninstall_mech(&krb5_mech_oid); 2093184588Sdfr break; 2094184588Sdfr } 2095184588Sdfr 2096184588Sdfr 2097184588Sdfr return (0); 2098184588Sdfr} 2099184588Sdfrstatic moduledata_t kgssapi_krb5_mod = { 2100184588Sdfr "kgssapi_krb5", 2101184588Sdfr kgssapi_krb5_modevent, 2102184588Sdfr NULL, 2103184588Sdfr}; 2104184588SdfrDECLARE_MODULE(kgssapi_krb5, kgssapi_krb5_mod, SI_SUB_VFS, SI_ORDER_ANY); 2105184588SdfrMODULE_DEPEND(kgssapi_krb5, kgssapi, 1, 1, 1); 2106184588SdfrMODULE_DEPEND(kgssapi_krb5, crypto, 1, 1, 1); 2107184588SdfrMODULE_DEPEND(kgssapi_krb5, rc4, 1, 1, 1); 2108184588SdfrMODULE_VERSION(kgssapi_krb5, 1); 2109