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