]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/kgssapi/krb5/krb5_mech.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / kgssapi / krb5 / krb5_mech.c
1 /*-
2  * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3  * Authors: Doug Rabson <dfr@rabson.org>
4  * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include "opt_inet6.h"
32
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/kobj.h>
36 #include <sys/lock.h>
37 #include <sys/malloc.h>
38 #include <sys/mbuf.h>
39 #include <sys/module.h>
40 #include <sys/mutex.h>
41 #include <kgssapi/gssapi.h>
42 #include <kgssapi/gssapi_impl.h>
43
44 #include "kgss_if.h"
45 #include "kcrypto.h"
46
47 #define GSS_TOKEN_SENT_BY_ACCEPTOR      1
48 #define GSS_TOKEN_SEALED                2
49 #define GSS_TOKEN_ACCEPTOR_SUBKEY       4
50
51 static gss_OID_desc krb5_mech_oid =
52 {9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
53
54 struct krb5_data {
55         size_t          kd_length;
56         void            *kd_data;
57 };
58
59 struct krb5_keyblock {
60         uint16_t        kk_type; /* encryption type */
61         struct krb5_data kk_key; /* key data */
62 };
63
64 struct krb5_address {
65         uint16_t        ka_type;
66         struct krb5_data ka_addr;
67 };
68
69 /*
70  * The km_elem array is ordered so that the highest received sequence
71  * number is listed first.
72  */
73 struct krb5_msg_order {
74         uint32_t                km_flags;
75         uint32_t                km_start;
76         uint32_t                km_length;
77         uint32_t                km_jitter_window;
78         uint32_t                km_first_seq;
79         uint32_t                *km_elem;
80 };
81
82 struct krb5_context {
83         struct _gss_ctx_id_t    kc_common;
84         struct mtx              kc_lock;
85         uint32_t                kc_ac_flags;
86         uint32_t                kc_ctx_flags;
87         uint32_t                kc_more_flags;
88 #define LOCAL                   1
89 #define OPEN                    2
90 #define COMPAT_OLD_DES3         4
91 #define COMPAT_OLD_DES3_SELECTED 8
92 #define ACCEPTOR_SUBKEY         16
93         struct krb5_address     kc_local_address;
94         struct krb5_address     kc_remote_address;
95         uint16_t                kc_local_port;
96         uint16_t                kc_remote_port;
97         struct krb5_keyblock    kc_keyblock;
98         struct krb5_keyblock    kc_local_subkey;
99         struct krb5_keyblock    kc_remote_subkey;
100         volatile uint32_t       kc_local_seqnumber;
101         uint32_t                kc_remote_seqnumber;
102         uint32_t                kc_keytype;
103         uint32_t                kc_cksumtype;
104         struct krb5_data        kc_source_name;
105         struct krb5_data        kc_target_name;
106         uint32_t                kc_lifetime;
107         struct krb5_msg_order   kc_msg_order;
108         struct krb5_key_state   *kc_tokenkey;
109         struct krb5_key_state   *kc_encryptkey;
110         struct krb5_key_state   *kc_checksumkey;
111
112         struct krb5_key_state   *kc_send_seal_Ke;
113         struct krb5_key_state   *kc_send_seal_Ki;
114         struct krb5_key_state   *kc_send_seal_Kc;
115         struct krb5_key_state   *kc_send_sign_Kc;
116
117         struct krb5_key_state   *kc_recv_seal_Ke;
118         struct krb5_key_state   *kc_recv_seal_Ki;
119         struct krb5_key_state   *kc_recv_seal_Kc;
120         struct krb5_key_state   *kc_recv_sign_Kc;
121 };
122
123 static uint16_t
124 get_uint16(const uint8_t **pp, size_t *lenp)
125 {
126         const uint8_t *p = *pp;
127         uint16_t v;
128
129         if (*lenp < 2)
130                 return (0);
131
132         v = (p[0] << 8) | p[1];
133         *pp = p + 2;
134         *lenp = *lenp - 2;
135
136         return (v);
137 }
138
139 static uint32_t
140 get_uint32(const uint8_t **pp, size_t *lenp)
141 {
142         const uint8_t *p = *pp;
143         uint32_t v;
144
145         if (*lenp < 4)
146                 return (0);
147
148         v = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
149         *pp = p + 4;
150         *lenp = *lenp - 4;
151
152         return (v);
153 }
154
155 static void
156 get_data(const uint8_t **pp, size_t *lenp, struct krb5_data *dp)
157 {
158         size_t sz = get_uint32(pp, lenp);
159
160         dp->kd_length = sz;
161         dp->kd_data = malloc(sz, M_GSSAPI, M_WAITOK);
162
163         if (*lenp < sz)
164                 sz = *lenp;
165         bcopy(*pp, dp->kd_data, sz);
166         (*pp) += sz;
167         (*lenp) -= sz;
168 }
169
170 static void
171 delete_data(struct krb5_data *dp)
172 {
173         if (dp->kd_data) {
174                 free(dp->kd_data, M_GSSAPI);
175                 dp->kd_length = 0;
176                 dp->kd_data = NULL;
177         }
178 }
179
180 static void
181 get_address(const uint8_t **pp, size_t *lenp, struct krb5_address *ka)
182 {
183
184         ka->ka_type = get_uint16(pp, lenp);
185         get_data(pp, lenp, &ka->ka_addr);
186 }
187
188 static void
189 delete_address(struct krb5_address *ka)
190 {
191         delete_data(&ka->ka_addr);
192 }
193
194 static void
195 get_keyblock(const uint8_t **pp, size_t *lenp, struct krb5_keyblock *kk)
196 {
197
198         kk->kk_type = get_uint16(pp, lenp);
199         get_data(pp, lenp, &kk->kk_key);
200 }
201
202 static void
203 delete_keyblock(struct krb5_keyblock *kk)
204 {
205         if (kk->kk_key.kd_data)
206                 bzero(kk->kk_key.kd_data, kk->kk_key.kd_length);
207         delete_data(&kk->kk_key);
208 }
209
210 static void
211 copy_key(struct krb5_keyblock *from, struct krb5_keyblock **to)
212 {
213
214         if (from->kk_key.kd_length)
215                 *to = from;
216         else
217                 *to = NULL;
218 }
219
220 /*
221  * Return non-zero if we are initiator.
222  */
223 static __inline int
224 is_initiator(struct krb5_context *kc)
225 {
226         return (kc->kc_more_flags & LOCAL);
227 }
228
229 /*
230  * Return non-zero if we are acceptor.
231  */
232 static __inline int
233 is_acceptor(struct krb5_context *kc)
234 {
235         return !(kc->kc_more_flags & LOCAL);
236 }
237
238 static void
239 get_initiator_subkey(struct krb5_context *kc, struct krb5_keyblock **kdp)
240 {
241
242         if (is_initiator(kc))
243                 copy_key(&kc->kc_local_subkey, kdp);
244         else
245                 copy_key(&kc->kc_remote_subkey, kdp);
246         if (!*kdp)
247                 copy_key(&kc->kc_keyblock, kdp);
248 }
249
250 static void
251 get_acceptor_subkey(struct krb5_context *kc, struct krb5_keyblock **kdp)
252 {
253
254         if (is_initiator(kc))
255                 copy_key(&kc->kc_remote_subkey, kdp);
256         else
257                 copy_key(&kc->kc_local_subkey, kdp);
258 }
259
260 static OM_uint32
261 get_keys(struct krb5_context *kc)
262 {
263         struct krb5_keyblock *keydata;
264         struct krb5_encryption_class *ec;
265         struct krb5_key_state *key;
266         int etype;
267
268         keydata = NULL;
269         get_acceptor_subkey(kc, &keydata);
270         if (!keydata)
271                 if ((kc->kc_more_flags & ACCEPTOR_SUBKEY) == 0)
272                         get_initiator_subkey(kc, &keydata);
273         if (!keydata)
274                 return (GSS_S_FAILURE);
275
276         /*
277          * GSS-API treats all DES etypes the same and all DES3 etypes
278          * the same.
279          */
280         switch (keydata->kk_type) {
281         case ETYPE_DES_CBC_CRC:
282         case ETYPE_DES_CBC_MD4:
283         case ETYPE_DES_CBC_MD5:
284                 etype = ETYPE_DES_CBC_CRC;
285                 break;
286
287         case ETYPE_DES3_CBC_MD5:
288         case ETYPE_DES3_CBC_SHA1:
289         case ETYPE_OLD_DES3_CBC_SHA1:
290                 etype = ETYPE_DES3_CBC_SHA1;
291                 break;
292
293         default:
294                 etype = keydata->kk_type;
295         }
296
297         ec = krb5_find_encryption_class(etype);
298         if (!ec)
299                 return (GSS_S_FAILURE);
300
301         key = krb5_create_key(ec);
302         krb5_set_key(key, keydata->kk_key.kd_data);
303         kc->kc_tokenkey = key;
304
305         switch (etype) {
306         case ETYPE_DES_CBC_CRC:
307         case ETYPE_ARCFOUR_HMAC_MD5: 
308         case ETYPE_ARCFOUR_HMAC_MD5_56: {
309                 /*
310                  * Single DES and ARCFOUR uses a 'derived' key (XOR
311                  * with 0xf0) for encrypting wrap tokens. The original
312                  * key is used for checksums and sequence numbers.
313                  */
314                 struct krb5_key_state *ekey;
315                 uint8_t *ekp, *kp;
316                 int i;
317
318                 ekey = krb5_create_key(ec);
319                 ekp = ekey->ks_key;
320                 kp = key->ks_key;
321                 for (i = 0; i < ec->ec_keylen; i++)
322                         ekp[i] = kp[i] ^ 0xf0;
323                 krb5_set_key(ekey, ekp);
324                 kc->kc_encryptkey = ekey;
325                 refcount_acquire(&key->ks_refs);
326                 kc->kc_checksumkey = key;
327                 break;
328         }
329
330         case ETYPE_DES3_CBC_SHA1:
331                 /*
332                  * Triple DES uses a RFC 3961 style derived key with
333                  * usage number KG_USAGE_SIGN for checksums. The
334                  * original key is used for encryption and sequence
335                  * numbers.
336                  */
337                 kc->kc_checksumkey = krb5_get_checksum_key(key, KG_USAGE_SIGN);
338                 refcount_acquire(&key->ks_refs);
339                 kc->kc_encryptkey = key;
340                 break;
341
342         default:
343                 /*
344                  * We need eight derived keys four for sending and
345                  * four for receiving.
346                  */
347                 if (is_initiator(kc)) {
348                         /*
349                          * We are initiator.
350                          */
351                         kc->kc_send_seal_Ke = krb5_get_encryption_key(key,
352                             KG_USAGE_INITIATOR_SEAL);
353                         kc->kc_send_seal_Ki = krb5_get_integrity_key(key,
354                             KG_USAGE_INITIATOR_SEAL);
355                         kc->kc_send_seal_Kc = krb5_get_checksum_key(key,
356                             KG_USAGE_INITIATOR_SEAL);
357                         kc->kc_send_sign_Kc = krb5_get_checksum_key(key,
358                             KG_USAGE_INITIATOR_SIGN);
359
360                         kc->kc_recv_seal_Ke = krb5_get_encryption_key(key,
361                             KG_USAGE_ACCEPTOR_SEAL);
362                         kc->kc_recv_seal_Ki = krb5_get_integrity_key(key,
363                             KG_USAGE_ACCEPTOR_SEAL);
364                         kc->kc_recv_seal_Kc = krb5_get_checksum_key(key,
365                             KG_USAGE_ACCEPTOR_SEAL);
366                         kc->kc_recv_sign_Kc = krb5_get_checksum_key(key,
367                             KG_USAGE_ACCEPTOR_SIGN);
368                 } else {
369                         /*
370                          * We are acceptor.
371                          */
372                         kc->kc_send_seal_Ke = krb5_get_encryption_key(key,
373                             KG_USAGE_ACCEPTOR_SEAL);
374                         kc->kc_send_seal_Ki = krb5_get_integrity_key(key,
375                             KG_USAGE_ACCEPTOR_SEAL);
376                         kc->kc_send_seal_Kc = krb5_get_checksum_key(key,
377                             KG_USAGE_ACCEPTOR_SEAL);
378                         kc->kc_send_sign_Kc = krb5_get_checksum_key(key,
379                             KG_USAGE_ACCEPTOR_SIGN);
380
381                         kc->kc_recv_seal_Ke = krb5_get_encryption_key(key,
382                             KG_USAGE_INITIATOR_SEAL);
383                         kc->kc_recv_seal_Ki = krb5_get_integrity_key(key,
384                             KG_USAGE_INITIATOR_SEAL);
385                         kc->kc_recv_seal_Kc = krb5_get_checksum_key(key,
386                             KG_USAGE_INITIATOR_SEAL);
387                         kc->kc_recv_sign_Kc = krb5_get_checksum_key(key,
388                             KG_USAGE_INITIATOR_SIGN);
389                 }
390                 break;
391         }
392
393         return (GSS_S_COMPLETE);
394 }
395
396 static void
397 krb5_init(gss_ctx_id_t ctx)
398 {
399         struct krb5_context *kc = (struct krb5_context *)ctx;
400
401         mtx_init(&kc->kc_lock, "krb5 gss lock", NULL, MTX_DEF);
402 }
403
404 static OM_uint32
405 krb5_import(gss_ctx_id_t ctx,
406     enum sec_context_format format,
407     const gss_buffer_t context_token)
408 {
409         struct krb5_context *kc = (struct krb5_context *)ctx;
410         OM_uint32 res;
411         const uint8_t *p = (const uint8_t *) context_token->value;
412         size_t len = context_token->length;
413         uint32_t flags;
414         int i;
415         
416         /*
417          * We support heimdal 0.6 and heimdal 1.1
418          */
419         if (format != KGSS_HEIMDAL_0_6 && format != KGSS_HEIMDAL_1_1)
420                 return (GSS_S_DEFECTIVE_TOKEN);
421
422 #define SC_LOCAL_ADDRESS        1
423 #define SC_REMOTE_ADDRESS       2
424 #define SC_KEYBLOCK             4
425 #define SC_LOCAL_SUBKEY         8
426 #define SC_REMOTE_SUBKEY        16
427
428         /*
429          * Ensure that the token starts with krb5 oid.
430          */
431         if (p[0] != 0x00 || p[1] != krb5_mech_oid.length
432             || len < krb5_mech_oid.length + 2
433             || bcmp(krb5_mech_oid.elements, p + 2,
434                 krb5_mech_oid.length))
435                 return (GSS_S_DEFECTIVE_TOKEN);
436         p += krb5_mech_oid.length + 2;
437         len -= krb5_mech_oid.length + 2;
438
439         flags = get_uint32(&p, &len);
440         kc->kc_ac_flags = get_uint32(&p, &len);
441         if (flags & SC_LOCAL_ADDRESS)
442                 get_address(&p, &len, &kc->kc_local_address);
443         if (flags & SC_REMOTE_ADDRESS)
444                 get_address(&p, &len, &kc->kc_remote_address);
445         kc->kc_local_port = get_uint16(&p, &len);
446         kc->kc_remote_port = get_uint16(&p, &len);
447         if (flags & SC_KEYBLOCK)
448                 get_keyblock(&p, &len, &kc->kc_keyblock);
449         if (flags & SC_LOCAL_SUBKEY)
450                 get_keyblock(&p, &len, &kc->kc_local_subkey);
451         if (flags & SC_REMOTE_SUBKEY)
452                 get_keyblock(&p, &len, &kc->kc_remote_subkey);
453         kc->kc_local_seqnumber = get_uint32(&p, &len);
454         kc->kc_remote_seqnumber = get_uint32(&p, &len);
455         kc->kc_keytype = get_uint32(&p, &len);
456         kc->kc_cksumtype = get_uint32(&p, &len);
457         get_data(&p, &len, &kc->kc_source_name);
458         get_data(&p, &len, &kc->kc_target_name);
459         kc->kc_ctx_flags = get_uint32(&p, &len);
460         kc->kc_more_flags = get_uint32(&p, &len);
461         kc->kc_lifetime = get_uint32(&p, &len);
462         /*
463          * Heimdal 1.1 adds the message order stuff.
464          */
465         if (format == KGSS_HEIMDAL_1_1) {
466                 kc->kc_msg_order.km_flags = get_uint32(&p, &len);
467                 kc->kc_msg_order.km_start = get_uint32(&p, &len);
468                 kc->kc_msg_order.km_length = get_uint32(&p, &len);
469                 kc->kc_msg_order.km_jitter_window = get_uint32(&p, &len);
470                 kc->kc_msg_order.km_first_seq = get_uint32(&p, &len);
471                 kc->kc_msg_order.km_elem =
472                         malloc(kc->kc_msg_order.km_jitter_window * sizeof(uint32_t),
473                             M_GSSAPI, M_WAITOK);
474                 for (i = 0; i < kc->kc_msg_order.km_jitter_window; i++)
475                         kc->kc_msg_order.km_elem[i] = get_uint32(&p, &len);
476         } else {
477                 kc->kc_msg_order.km_flags = 0;
478         }
479
480         res = get_keys(kc);
481         if (GSS_ERROR(res))
482                 return (res);
483
484         /*
485          * We don't need these anymore.
486          */
487         delete_keyblock(&kc->kc_keyblock);
488         delete_keyblock(&kc->kc_local_subkey);
489         delete_keyblock(&kc->kc_remote_subkey);
490
491         return (GSS_S_COMPLETE);
492 }
493
494 static void
495 krb5_delete(gss_ctx_id_t ctx, gss_buffer_t output_token)
496 {
497         struct krb5_context *kc = (struct krb5_context *)ctx;
498
499         delete_address(&kc->kc_local_address);
500         delete_address(&kc->kc_remote_address);
501         delete_keyblock(&kc->kc_keyblock);
502         delete_keyblock(&kc->kc_local_subkey);
503         delete_keyblock(&kc->kc_remote_subkey);
504         delete_data(&kc->kc_source_name);
505         delete_data(&kc->kc_target_name);
506         if (kc->kc_msg_order.km_elem)
507                 free(kc->kc_msg_order.km_elem, M_GSSAPI);
508         if (output_token) {
509                 output_token->length = 0;
510                 output_token->value = NULL;
511         }
512         if (kc->kc_tokenkey) {
513                 krb5_free_key(kc->kc_tokenkey);
514                 if (kc->kc_encryptkey) {
515                         krb5_free_key(kc->kc_encryptkey);
516                         krb5_free_key(kc->kc_checksumkey);
517                 } else {
518                         krb5_free_key(kc->kc_send_seal_Ke);
519                         krb5_free_key(kc->kc_send_seal_Ki);
520                         krb5_free_key(kc->kc_send_seal_Kc);
521                         krb5_free_key(kc->kc_send_sign_Kc);
522                         krb5_free_key(kc->kc_recv_seal_Ke);
523                         krb5_free_key(kc->kc_recv_seal_Ki);
524                         krb5_free_key(kc->kc_recv_seal_Kc);
525                         krb5_free_key(kc->kc_recv_sign_Kc);
526                 }
527         }
528         mtx_destroy(&kc->kc_lock);
529 }
530
531 static gss_OID
532 krb5_mech_type(gss_ctx_id_t ctx)
533 {
534
535         return (&krb5_mech_oid);
536 }
537
538 /*
539  * Make a token with the given type and length (the length includes
540  * the TOK_ID), initialising the token header appropriately. Return a
541  * pointer to the TOK_ID of the token.  A new mbuf is allocated with
542  * the framing header plus hlen bytes of space.
543  *
544  * Format is as follows:
545  *
546  *      0x60                    [APPLICATION 0] SEQUENCE
547  *      DER encoded length      length of oid + type + inner token length
548  *      0x06 NN <oid data>      OID of mechanism type
549  *      TT TT                   TOK_ID
550  *      <inner token>           data for inner token
551  *      
552  * 1:           der encoded length
553  */
554 static void *
555 krb5_make_token(char tok_id[2], size_t hlen, size_t len, struct mbuf **mp)
556 {
557         size_t inside_len, len_len, tlen;
558         gss_OID oid = &krb5_mech_oid;
559         struct mbuf *m;
560         uint8_t *p;
561
562         inside_len = 2 + oid->length + len;
563         if (inside_len < 128)
564                 len_len = 1;
565         else if (inside_len < 0x100)
566                 len_len = 2;
567         else if (inside_len < 0x10000)
568                 len_len = 3;
569         else if (inside_len < 0x1000000)
570                 len_len = 4;
571         else
572                 len_len = 5;
573
574         tlen = 1 + len_len + 2 + oid->length + hlen;
575         KASSERT(tlen <= MLEN, ("token head too large"));
576         MGET(m, M_WAITOK, MT_DATA);
577         M_ALIGN(m, tlen);
578         m->m_len = tlen;
579
580         p = (uint8_t *) m->m_data;
581         *p++ = 0x60;
582         switch (len_len) {
583         case 1:
584                 *p++ = inside_len;
585                 break;
586         case 2:
587                 *p++ = 0x81;
588                 *p++ = inside_len;
589                 break;
590         case 3:
591                 *p++ = 0x82;
592                 *p++ = inside_len >> 8;
593                 *p++ = inside_len;
594                 break;
595         case 4:
596                 *p++ = 0x83;
597                 *p++ = inside_len >> 16;
598                 *p++ = inside_len >> 8;
599                 *p++ = inside_len;
600                 break;
601         case 5:
602                 *p++ = 0x84;
603                 *p++ = inside_len >> 24;
604                 *p++ = inside_len >> 16;
605                 *p++ = inside_len >> 8;
606                 *p++ = inside_len;
607                 break;
608         }
609
610         *p++ = 0x06;
611         *p++ = oid->length;
612         bcopy(oid->elements, p, oid->length);
613         p += oid->length;
614
615         p[0] = tok_id[0];
616         p[1] = tok_id[1];
617
618         *mp = m;
619
620         return (p);
621 }
622
623 /*
624  * Verify a token, checking the inner token length and mechanism oid.
625  * pointer to the first byte of the TOK_ID. The length of the
626  * encapsulated data is checked to be at least len bytes; the actual
627  * length of the encapsulated data (including TOK_ID) is returned in
628  * *encap_len.
629  *
630  * If can_pullup is TRUE and the token header is fragmented, we will
631  * rearrange it.
632  *
633  * Format is as follows:
634  *
635  *      0x60                    [APPLICATION 0] SEQUENCE
636  *      DER encoded length      length of oid + type + inner token length
637  *      0x06 NN <oid data>      OID of mechanism type
638  *      TT TT                   TOK_ID
639  *      <inner token>           data for inner token
640  *      
641  * 1:           der encoded length
642  */
643 static void *
644 krb5_verify_token(char tok_id[2], size_t len, struct mbuf **mp,
645     size_t *encap_len, bool_t can_pullup)
646 {
647         struct mbuf *m;
648         size_t tlen, hlen, len_len, inside_len;
649         gss_OID oid = &krb5_mech_oid;
650         uint8_t *p;
651
652         m = *mp;
653         tlen = m_length(m, NULL);
654         if (tlen < 2)
655                 return (NULL);
656
657         /*
658          * Ensure that at least the framing part of the token is
659          * contigous.
660          */
661         if (m->m_len < 2) {
662                 if (can_pullup)
663                         *mp = m = m_pullup(m, 2);
664                 else
665                         return (NULL);
666         }
667
668         p = m->m_data;
669
670         if (*p++ != 0x60)
671                 return (NULL);
672
673         if (*p < 0x80) {
674                 inside_len = *p++;
675                 len_len = 1;
676         } else {
677                 /*
678                  * Ensure there is enough space for the DER encoded length.
679                  */
680                 len_len = (*p & 0x7f) + 1;
681                 if (tlen < len_len + 1)
682                         return (NULL);
683                 if (m->m_len < len_len + 1) {
684                         if (can_pullup)
685                                 *mp = m = m_pullup(m, len_len + 1);
686                         else
687                                 return (NULL);
688                         p = m->m_data + 1;
689                 }
690
691                 switch (*p++) {
692                 case 0x81:
693                         inside_len = *p++;
694                         break;
695
696                 case 0x82:
697                         inside_len = (p[0] << 8) | p[1];
698                         p += 2;
699                         break;
700
701                 case 0x83:
702                         inside_len = (p[0] << 16) | (p[1] << 8) | p[2];
703                         p += 3;
704                         break;
705
706                 case 0x84:
707                         inside_len = (p[0] << 24) | (p[1] << 16)
708                                 | (p[2] << 8) | p[3];
709                         p += 4;
710                         break;
711
712                 default:
713                         return (NULL);
714                 }
715         }
716
717         if (tlen != inside_len + len_len + 1)
718                 return (NULL);
719         if (inside_len < 2 + oid->length + len)
720                 return (NULL);
721
722         /*
723          * Now that we know the value of len_len, we can pullup the
724          * whole header. The header is 1 + len_len + 2 + oid->length +
725          * len bytes.
726          */
727         hlen = 1 + len_len + 2 + oid->length + len;
728         if (m->m_len < hlen) {
729                 if (can_pullup)
730                         *mp = m = m_pullup(m, hlen);
731                 else
732                         return (NULL);
733                 p = m->m_data + 1 + len_len;
734         }
735
736         if (*p++ != 0x06)
737                 return (NULL);
738         if (*p++ != oid->length)
739                 return (NULL);
740         if (bcmp(oid->elements, p, oid->length))
741                 return (NULL);
742         p += oid->length;
743
744         if (p[0] != tok_id[0])
745                 return (NULL);
746
747         if (p[1] != tok_id[1])
748                 return (NULL);
749
750         *encap_len = inside_len - 2 - oid->length;
751
752         return (p);
753 }
754
755 static void
756 krb5_insert_seq(struct krb5_msg_order *mo, uint32_t seq, int index)
757 {
758         int i;
759
760         if (mo->km_length < mo->km_jitter_window)
761                 mo->km_length++;
762
763         for (i = mo->km_length - 1; i > index; i--)
764                 mo->km_elem[i] = mo->km_elem[i - 1];
765         mo->km_elem[index] = seq;
766 }
767
768 /*
769  * Check sequence numbers according to RFC 2743 section 1.2.3.
770  */
771 static OM_uint32
772 krb5_sequence_check(struct krb5_context *kc, uint32_t seq)
773 {
774         OM_uint32 res = GSS_S_FAILURE;
775         struct krb5_msg_order *mo = &kc->kc_msg_order;
776         int check_sequence = mo->km_flags & GSS_C_SEQUENCE_FLAG;
777         int check_replay = mo->km_flags & GSS_C_REPLAY_FLAG;
778         int i;
779
780         mtx_lock(&kc->kc_lock);
781
782         /*
783          * Message is in-sequence with no gap.
784          */
785         if (mo->km_length == 0 || seq == mo->km_elem[0] + 1) {
786                 /*
787                  * This message is received in-sequence with no gaps.
788                  */
789                 krb5_insert_seq(mo, seq, 0);
790                 res = GSS_S_COMPLETE;
791                 goto out;
792         }
793
794         if (seq > mo->km_elem[0]) {
795                 /*
796                  * This message is received in-sequence with a gap.
797                  */
798                 krb5_insert_seq(mo, seq, 0);
799                 if (check_sequence)
800                         res = GSS_S_GAP_TOKEN;
801                 else
802                         res = GSS_S_COMPLETE;
803                 goto out;
804         }
805
806         if (seq < mo->km_elem[mo->km_length - 1]) {
807                 if (check_replay && !check_sequence)
808                         res = GSS_S_OLD_TOKEN;
809                 else
810                         res = GSS_S_UNSEQ_TOKEN;
811                 goto out;
812         }
813
814         for (i = 0; i < mo->km_length; i++) {
815                 if (mo->km_elem[i] == seq) {
816                         res = GSS_S_DUPLICATE_TOKEN;
817                         goto out;
818                 }
819                 if (mo->km_elem[i] < seq) {
820                         /*
821                          * We need to insert this seq here,
822                          */
823                         krb5_insert_seq(mo, seq, i);
824                         if (check_replay && !check_sequence)
825                                 res = GSS_S_COMPLETE;
826                         else
827                                 res = GSS_S_UNSEQ_TOKEN;
828                         goto out;
829                 }
830         }
831
832 out:
833         mtx_unlock(&kc->kc_lock);
834
835         return (res);
836 }
837
838 static uint8_t sgn_alg_des_md5[] = { 0x00, 0x00 };
839 static uint8_t seal_alg_des[] = { 0x00, 0x00 };
840 static uint8_t sgn_alg_des3_sha1[] = { 0x04, 0x00 };
841 static uint8_t seal_alg_des3[] = { 0x02, 0x00 };
842 static uint8_t seal_alg_rc4[] = { 0x10, 0x00 };
843 static uint8_t sgn_alg_hmac_md5[] = { 0x11, 0x00 };
844
845 /*
846  * Return the size of the inner token given the use of the key's
847  * encryption class. For wrap tokens, the length of the padded
848  * plaintext will be added to this.
849  */
850 static size_t
851 token_length(struct krb5_key_state *key)
852 {
853
854         return (16 + key->ks_class->ec_checksumlen);
855 }
856
857 static OM_uint32
858 krb5_get_mic_old(struct krb5_context *kc, struct mbuf *m,
859     struct mbuf **micp, uint8_t sgn_alg[2])
860 {
861         struct mbuf *mlast, *mic, *tm;
862         uint8_t *p, dir;
863         size_t tlen, mlen, cklen;
864         uint32_t seq;
865         char buf[8];
866
867         mlen = m_length(m, &mlast);
868
869         tlen = token_length(kc->kc_tokenkey);
870         p = krb5_make_token("\x01\x01", tlen, tlen, &mic);
871         p += 2;                 /* TOK_ID */
872         *p++ = sgn_alg[0];      /* SGN_ALG */
873         *p++ = sgn_alg[1];
874
875         *p++ = 0xff;            /* filler */
876         *p++ = 0xff;
877         *p++ = 0xff;
878         *p++ = 0xff;
879
880         /*
881          * SGN_CKSUM:
882          *
883          * Calculate the keyed checksum of the token header plus the
884          * message.
885          */
886         cklen = kc->kc_checksumkey->ks_class->ec_checksumlen;
887
888         mic->m_len = p - (uint8_t *) mic->m_data;
889         mic->m_next = m;
890         MGET(tm, M_WAITOK, MT_DATA);
891         tm->m_len = cklen;
892         mlast->m_next = tm;
893
894         krb5_checksum(kc->kc_checksumkey, 15, mic, mic->m_len - 8,
895             8 + mlen, cklen);
896         bcopy(tm->m_data, p + 8, cklen);
897         mic->m_next = NULL;
898         mlast->m_next = NULL;
899         m_free(tm);
900         
901         /*
902          * SND_SEQ:
903          *
904          * Take the four bytes of the sequence number least
905          * significant first followed by four bytes of direction
906          * marker (zero for initiator and 0xff for acceptor). Encrypt
907          * that data using the SGN_CKSUM as IV. Note: ARC4 wants the
908          * sequence number big-endian.
909          */
910         seq = atomic_fetchadd_32(&kc->kc_local_seqnumber, 1);
911         if (sgn_alg[0] == 0x11) {
912                 p[0] = (seq >> 24);
913                 p[1] = (seq >> 16);
914                 p[2] = (seq >> 8);
915                 p[3] = (seq >> 0);
916         } else {
917                 p[0] = (seq >> 0);
918                 p[1] = (seq >> 8);
919                 p[2] = (seq >> 16);
920                 p[3] = (seq >> 24);
921         }
922         if (is_initiator(kc)) {
923                 dir = 0;
924         } else {
925                 dir = 0xff;
926         }
927         p[4] = dir;
928         p[5] = dir;
929         p[6] = dir;
930         p[7] = dir;
931         bcopy(p + 8, buf, 8);
932
933         /*
934          * Set the mic buffer to its final size so that the encrypt
935          * can see the SND_SEQ part.
936          */
937         mic->m_len += 8 + cklen;
938         krb5_encrypt(kc->kc_tokenkey, mic, mic->m_len - cklen - 8, 8, buf, 8);
939
940         *micp = mic;
941         return (GSS_S_COMPLETE);
942 }
943
944 static OM_uint32
945 krb5_get_mic_new(struct krb5_context *kc,  struct mbuf *m,
946     struct mbuf **micp)
947 {
948         struct krb5_key_state *key = kc->kc_send_sign_Kc;
949         struct mbuf *mlast, *mic;
950         uint8_t *p;
951         int flags;
952         size_t mlen, cklen;
953         uint32_t seq;
954
955         mlen = m_length(m, &mlast);
956         cklen = key->ks_class->ec_checksumlen;
957
958         KASSERT(16 + cklen <= MLEN, ("checksum too large for an mbuf"));
959         MGET(mic, M_WAITOK, MT_DATA);
960         M_ALIGN(mic, 16 + cklen);
961         mic->m_len = 16 + cklen;
962         p = mic->m_data;
963
964         /* TOK_ID */
965         p[0] = 0x04;
966         p[1] = 0x04;
967
968         /* Flags */
969         flags = 0;
970         if (is_acceptor(kc))
971                 flags |= GSS_TOKEN_SENT_BY_ACCEPTOR;
972         if (kc->kc_more_flags & ACCEPTOR_SUBKEY)
973                 flags |= GSS_TOKEN_ACCEPTOR_SUBKEY;
974         p[2] = flags;
975
976         /* Filler */
977         p[3] = 0xff;
978         p[4] = 0xff;
979         p[5] = 0xff;
980         p[6] = 0xff;
981         p[7] = 0xff;
982
983         /* SND_SEQ */
984         p[8] = 0;
985         p[9] = 0;
986         p[10] = 0;
987         p[11] = 0;
988         seq = atomic_fetchadd_32(&kc->kc_local_seqnumber, 1);
989         p[12] = (seq >> 24);
990         p[13] = (seq >> 16);
991         p[14] = (seq >> 8);
992         p[15] = (seq >> 0);
993
994         /*
995          * SGN_CKSUM:
996          *
997          * Calculate the keyed checksum of the message plus the first
998          * 16 bytes of the token header.
999          */
1000         mlast->m_next = mic;
1001         krb5_checksum(key, 0, m, 0, mlen + 16, cklen);
1002         mlast->m_next = NULL;
1003
1004         *micp = mic;
1005         return (GSS_S_COMPLETE);
1006 }
1007
1008 static OM_uint32
1009 krb5_get_mic(gss_ctx_id_t ctx, OM_uint32 *minor_status,
1010     gss_qop_t qop_req, struct mbuf *m, struct mbuf **micp)
1011 {
1012         struct krb5_context *kc = (struct krb5_context *)ctx;
1013
1014         *minor_status = 0;
1015
1016         if (qop_req != GSS_C_QOP_DEFAULT)
1017                 return (GSS_S_BAD_QOP);
1018
1019         if (time_uptime > kc->kc_lifetime)
1020                 return (GSS_S_CONTEXT_EXPIRED);
1021
1022         switch (kc->kc_tokenkey->ks_class->ec_type) {
1023         case ETYPE_DES_CBC_CRC:
1024                 return (krb5_get_mic_old(kc, m, micp, sgn_alg_des_md5));
1025
1026         case ETYPE_DES3_CBC_SHA1:
1027                 return (krb5_get_mic_old(kc, m, micp, sgn_alg_des3_sha1));
1028
1029         case ETYPE_ARCFOUR_HMAC_MD5:
1030         case ETYPE_ARCFOUR_HMAC_MD5_56:
1031                 return (krb5_get_mic_old(kc, m, micp, sgn_alg_hmac_md5));
1032
1033         default:
1034                 return (krb5_get_mic_new(kc, m, micp));
1035         }
1036
1037         return (GSS_S_FAILURE);
1038 }
1039
1040 static OM_uint32
1041 krb5_verify_mic_old(struct krb5_context *kc, struct mbuf *m, struct mbuf *mic,
1042     uint8_t sgn_alg[2])
1043 {
1044         struct mbuf *mlast, *tm;
1045         uint8_t *p, *tp, dir;
1046         size_t mlen, tlen, elen, miclen;
1047         size_t cklen;
1048         uint32_t seq;
1049
1050         mlen = m_length(m, &mlast);
1051
1052         tlen = token_length(kc->kc_tokenkey);
1053         p = krb5_verify_token("\x01\x01", tlen, &mic, &elen, FALSE);
1054         if (!p)
1055                 return (GSS_S_DEFECTIVE_TOKEN);
1056 #if 0
1057         /*
1058          * Disable this check - heimdal-1.1 generates DES3 MIC tokens
1059          * that are 2 bytes too big.
1060          */
1061         if (elen != tlen)
1062                 return (GSS_S_DEFECTIVE_TOKEN);
1063 #endif
1064         /* TOK_ID */
1065         p += 2;
1066
1067         /* SGN_ALG */
1068         if (p[0] != sgn_alg[0] || p[1] != sgn_alg[1])
1069                 return (GSS_S_DEFECTIVE_TOKEN);
1070         p += 2;
1071
1072         if (p[0] != 0xff || p[1] != 0xff || p[2] != 0xff || p[3] != 0xff)
1073                 return (GSS_S_DEFECTIVE_TOKEN);
1074         p += 4;
1075
1076         /*
1077          * SGN_CKSUM:
1078          *
1079          * Calculate the keyed checksum of the token header plus the
1080          * message.
1081          */
1082         cklen = kc->kc_checksumkey->ks_class->ec_checksumlen;
1083         miclen = mic->m_len;
1084         mic->m_len = p - (uint8_t *) mic->m_data;
1085         mic->m_next = m;
1086         MGET(tm, M_WAITOK, MT_DATA);
1087         tm->m_len = cklen;
1088         mlast->m_next = tm;
1089
1090         krb5_checksum(kc->kc_checksumkey, 15, mic, mic->m_len - 8,
1091             8 + mlen, cklen);
1092         mic->m_next = NULL;
1093         mlast->m_next = NULL;
1094         if (bcmp(tm->m_data, p + 8, cklen)) {
1095                 m_free(tm);
1096                 return (GSS_S_BAD_SIG);
1097         }
1098
1099         /*
1100          * SND_SEQ:
1101          *
1102          * Take the four bytes of the sequence number least
1103          * significant first followed by four bytes of direction
1104          * marker (zero for initiator and 0xff for acceptor). Encrypt
1105          * that data using the SGN_CKSUM as IV.  Note: ARC4 wants the
1106          * sequence number big-endian.
1107          */
1108         bcopy(p, tm->m_data, 8);
1109         tm->m_len = 8;
1110         krb5_decrypt(kc->kc_tokenkey, tm, 0, 8, p + 8, 8);
1111
1112         tp = tm->m_data;
1113         if (sgn_alg[0] == 0x11) {
1114                 seq = tp[3] | (tp[2] << 8) | (tp[1] << 16) | (tp[0] << 24);
1115         } else {
1116                 seq = tp[0] | (tp[1] << 8) | (tp[2] << 16) | (tp[3] << 24);
1117         }
1118
1119         if (is_initiator(kc)) {
1120                 dir = 0xff;
1121         } else {
1122                 dir = 0;
1123         }
1124         if (tp[4] != dir || tp[5] != dir || tp[6] != dir || tp[7] != dir) {
1125                 m_free(tm);
1126                 return (GSS_S_DEFECTIVE_TOKEN);
1127         }
1128         m_free(tm);
1129
1130         if (kc->kc_msg_order.km_flags &
1131                 (GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG)) {
1132                 return (krb5_sequence_check(kc, seq));
1133         }
1134
1135         return (GSS_S_COMPLETE);
1136 }
1137
1138 static OM_uint32
1139 krb5_verify_mic_new(struct krb5_context *kc, struct mbuf *m, struct mbuf *mic)
1140 {
1141         OM_uint32 res;
1142         struct krb5_key_state *key = kc->kc_recv_sign_Kc;
1143         struct mbuf *mlast;
1144         uint8_t *p;
1145         int flags;
1146         size_t mlen, cklen;
1147         char buf[32];
1148
1149         mlen = m_length(m, &mlast);
1150         cklen = key->ks_class->ec_checksumlen;
1151
1152         KASSERT(mic->m_next == NULL, ("MIC should be contiguous"));
1153         if (mic->m_len != 16 + cklen)
1154                 return (GSS_S_DEFECTIVE_TOKEN);
1155         p = mic->m_data;
1156
1157         /* TOK_ID */
1158         if (p[0] != 0x04)
1159                 return (GSS_S_DEFECTIVE_TOKEN);
1160         if (p[1] != 0x04)
1161                 return (GSS_S_DEFECTIVE_TOKEN);
1162
1163         /* Flags */
1164         flags = 0;
1165         if (is_initiator(kc))
1166                 flags |= GSS_TOKEN_SENT_BY_ACCEPTOR;
1167         if (kc->kc_more_flags & ACCEPTOR_SUBKEY)
1168                 flags |= GSS_TOKEN_ACCEPTOR_SUBKEY;
1169         if (p[2] != flags)
1170                 return (GSS_S_DEFECTIVE_TOKEN);
1171
1172         /* Filler */
1173         if (p[3] != 0xff)
1174                 return (GSS_S_DEFECTIVE_TOKEN);
1175         if (p[4] != 0xff)
1176                 return (GSS_S_DEFECTIVE_TOKEN);
1177         if (p[5] != 0xff)
1178                 return (GSS_S_DEFECTIVE_TOKEN);
1179         if (p[6] != 0xff)
1180                 return (GSS_S_DEFECTIVE_TOKEN);
1181         if (p[7] != 0xff)
1182                 return (GSS_S_DEFECTIVE_TOKEN);
1183
1184         /* SND_SEQ */
1185         if (kc->kc_msg_order.km_flags &
1186                 (GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG)) {
1187                 uint32_t seq;
1188                 if (p[8] || p[9] || p[10] || p[11]) {
1189                         res = GSS_S_UNSEQ_TOKEN;
1190                 } else {
1191                         seq = (p[12] << 24) | (p[13] << 16)
1192                                 | (p[14] << 8) | p[15];
1193                         res = krb5_sequence_check(kc, seq);
1194                 }
1195                 if (GSS_ERROR(res))
1196                         return (res);
1197         } else {
1198                 res = GSS_S_COMPLETE;
1199         }
1200
1201         /*
1202          * SGN_CKSUM:
1203          *
1204          * Calculate the keyed checksum of the message plus the first
1205          * 16 bytes of the token header.
1206          */
1207         m_copydata(mic, 16, cklen, buf);
1208         mlast->m_next = mic;
1209         krb5_checksum(key, 0, m, 0, mlen + 16, cklen);
1210         mlast->m_next = NULL;
1211         if (bcmp(buf, p + 16, cklen)) {
1212                 return (GSS_S_BAD_SIG);
1213         }
1214
1215         return (GSS_S_COMPLETE);
1216 }
1217
1218 static OM_uint32
1219 krb5_verify_mic(gss_ctx_id_t ctx, OM_uint32 *minor_status,
1220     struct mbuf *m, struct mbuf *mic, gss_qop_t *qop_state)
1221 {
1222         struct krb5_context *kc = (struct krb5_context *)ctx;
1223
1224         *minor_status = 0;
1225         if (qop_state)
1226                 *qop_state = GSS_C_QOP_DEFAULT;
1227
1228         if (time_uptime > kc->kc_lifetime)
1229                 return (GSS_S_CONTEXT_EXPIRED);
1230
1231         switch (kc->kc_tokenkey->ks_class->ec_type) {
1232         case ETYPE_DES_CBC_CRC:
1233                 return (krb5_verify_mic_old(kc, m, mic, sgn_alg_des_md5));
1234
1235         case ETYPE_ARCFOUR_HMAC_MD5:
1236         case ETYPE_ARCFOUR_HMAC_MD5_56:
1237                 return (krb5_verify_mic_old(kc, m, mic, sgn_alg_hmac_md5));
1238
1239         case ETYPE_DES3_CBC_SHA1:
1240                 return (krb5_verify_mic_old(kc, m, mic, sgn_alg_des3_sha1));
1241
1242         default:
1243                 return (krb5_verify_mic_new(kc, m, mic));
1244         }
1245
1246         return (GSS_S_FAILURE);
1247 }
1248
1249 static OM_uint32
1250 krb5_wrap_old(struct krb5_context *kc, int conf_req_flag,
1251     struct mbuf **mp, int *conf_state,
1252     uint8_t sgn_alg[2], uint8_t seal_alg[2])
1253 {
1254         struct mbuf *m, *mlast, *tm, *cm, *pm;
1255         size_t mlen, tlen, padlen, datalen;
1256         uint8_t *p, dir;
1257         size_t cklen;
1258         uint8_t buf[8];
1259         uint32_t seq;
1260
1261         /*
1262          * How many trailing pad bytes do we need?
1263          */
1264         m = *mp;
1265         mlen = m_length(m, &mlast);
1266         tlen = kc->kc_tokenkey->ks_class->ec_msgblocklen;
1267         padlen = tlen - (mlen % tlen);
1268
1269         /*
1270          * The data part of the token has eight bytes of random
1271          * confounder prepended and followed by up to eight bytes of
1272          * padding bytes each of which is set to the number of padding
1273          * bytes.
1274          */
1275         datalen = mlen + 8 + padlen;
1276         tlen = token_length(kc->kc_tokenkey);
1277
1278         p = krb5_make_token("\x02\x01", tlen, datalen + tlen, &tm);
1279         p += 2;                 /* TOK_ID */
1280         *p++ = sgn_alg[0];      /* SGN_ALG */
1281         *p++ = sgn_alg[1];
1282         if (conf_req_flag) {
1283                 *p++ = seal_alg[0]; /* SEAL_ALG */
1284                 *p++ = seal_alg[1];
1285         } else {
1286                 *p++ = 0xff;    /* SEAL_ALG = none */
1287                 *p++ = 0xff;
1288         }
1289
1290         *p++ = 0xff;            /* filler */
1291         *p++ = 0xff;
1292
1293         /*
1294          * Copy the padded message data.
1295          */
1296         if (M_LEADINGSPACE(m) >= 8) {
1297                 m->m_data -= 8;
1298                 m->m_len += 8;
1299         } else {
1300                 MGET(cm, M_WAITOK, MT_DATA);
1301                 cm->m_len = 8;
1302                 cm->m_next = m;
1303                 m = cm;
1304         }
1305         arc4rand(m->m_data, 8, 0);
1306         if (M_TRAILINGSPACE(mlast) >= padlen) {
1307                 memset(mlast->m_data + mlast->m_len, padlen, padlen);
1308                 mlast->m_len += padlen;
1309         } else {
1310                 MGET(pm, M_WAITOK, MT_DATA);
1311                 memset(pm->m_data, padlen, padlen);
1312                 pm->m_len = padlen;
1313                 mlast->m_next = pm;
1314                 mlast = pm;
1315         }
1316         tm->m_next = m;
1317
1318         /*
1319          * SGN_CKSUM:
1320          *
1321          * Calculate the keyed checksum of the token header plus the
1322          * padded message. Fiddle with tm->m_len so that we only
1323          * checksum the 8 bytes of head that we care about.
1324          */
1325         cklen = kc->kc_checksumkey->ks_class->ec_checksumlen;
1326         tlen = tm->m_len;
1327         tm->m_len = p - (uint8_t *) tm->m_data;
1328         MGET(cm, M_WAITOK, MT_DATA);
1329         cm->m_len = cklen;
1330         mlast->m_next = cm;
1331         krb5_checksum(kc->kc_checksumkey, 13, tm, tm->m_len - 8,
1332             datalen + 8, cklen);
1333         tm->m_len = tlen;
1334         mlast->m_next = NULL;
1335         bcopy(cm->m_data, p + 8, cklen);
1336         m_free(cm);
1337
1338         /*
1339          * SND_SEQ:
1340          *
1341          * Take the four bytes of the sequence number least
1342          * significant first (most signficant first for ARCFOUR)
1343          * followed by four bytes of direction marker (zero for
1344          * initiator and 0xff for acceptor). Encrypt that data using
1345          * the SGN_CKSUM as IV.
1346          */
1347         seq = atomic_fetchadd_32(&kc->kc_local_seqnumber, 1);
1348         if (sgn_alg[0] == 0x11) {
1349                 p[0] = (seq >> 24);
1350                 p[1] = (seq >> 16);
1351                 p[2] = (seq >> 8);
1352                 p[3] = (seq >> 0);
1353         } else {
1354                 p[0] = (seq >> 0);
1355                 p[1] = (seq >> 8);
1356                 p[2] = (seq >> 16);
1357                 p[3] = (seq >> 24);
1358         }
1359         if (is_initiator(kc)) {
1360                 dir = 0;
1361         } else {
1362                 dir = 0xff;
1363         }
1364         p[4] = dir;
1365         p[5] = dir;
1366         p[6] = dir;
1367         p[7] = dir;
1368         krb5_encrypt(kc->kc_tokenkey, tm, p - (uint8_t *) tm->m_data,
1369             8, p + 8, 8);
1370
1371         if (conf_req_flag) {
1372                 /*
1373                  * Encrypt the padded message with an IV of zero for
1374                  * DES and DES3, or an IV of the sequence number in
1375                  * big-endian format for ARCFOUR.
1376                  */
1377                 if (seal_alg[0] == 0x10) {
1378                         buf[0] = (seq >> 24);
1379                         buf[1] = (seq >> 16);
1380                         buf[2] = (seq >> 8);
1381                         buf[3] = (seq >> 0);
1382                         krb5_encrypt(kc->kc_encryptkey, m, 0, datalen,
1383                             buf, 4);
1384                 } else {
1385                         krb5_encrypt(kc->kc_encryptkey, m, 0, datalen,
1386                             NULL, 0);
1387                 }
1388         }
1389
1390         if (conf_state)
1391                 *conf_state = conf_req_flag;
1392
1393         *mp = tm;
1394         return (GSS_S_COMPLETE);
1395 }
1396
1397 static OM_uint32
1398 krb5_wrap_new(struct krb5_context *kc, int conf_req_flag,
1399     struct mbuf **mp, int *conf_state)
1400 {
1401         struct krb5_key_state *Ke = kc->kc_send_seal_Ke;
1402         struct krb5_key_state *Ki = kc->kc_send_seal_Ki;
1403         struct krb5_key_state *Kc = kc->kc_send_seal_Kc;
1404         const struct krb5_encryption_class *ec = Ke->ks_class;
1405         struct mbuf *m, *mlast, *tm;
1406         uint8_t *p;
1407         int flags, EC;
1408         size_t mlen, blen, mblen, cklen, ctlen;
1409         uint32_t seq;
1410         static char zpad[32];
1411
1412         m = *mp;
1413         mlen = m_length(m, &mlast);
1414
1415         blen = ec->ec_blocklen;
1416         mblen = ec->ec_msgblocklen;
1417         cklen = ec->ec_checksumlen;
1418
1419         if (conf_req_flag) {
1420                 /*
1421                  * For sealed messages, we need space for 16 bytes of
1422                  * header, blen confounder, plaintext, padding, copy
1423                  * of header and checksum.
1424                  *
1425                  * We pad to mblen (which may be different from
1426                  * blen). If the encryption class is using CTS, mblen
1427                  * will be one (i.e. no padding required).
1428                  */
1429                 if (mblen > 1)
1430                         EC = mlen % mblen;
1431                 else
1432                         EC = 0;
1433                 ctlen = blen + mlen + EC + 16;
1434
1435                 /*
1436                  * Put initial header and confounder before the
1437                  * message.
1438                  */
1439                 M_PREPEND(m, 16 + blen, M_WAITOK);
1440
1441                 /*
1442                  * Append padding + copy of header and checksum. Try
1443                  * to fit this into the end of the original message,
1444                  * otherwise allocate a trailer.
1445                  */
1446                 if (M_TRAILINGSPACE(mlast) >= EC + 16 + cklen) {
1447                         tm = NULL;
1448                         mlast->m_len += EC + 16 + cklen;
1449                 } else {
1450                         MGET(tm, M_WAITOK, MT_DATA);
1451                         tm->m_len = EC + 16 + cklen;
1452                         mlast->m_next = tm;
1453                 }
1454         } else {
1455                 /*
1456                  * For unsealed messages, we need 16 bytes of header
1457                  * plus space for the plaintext and a checksum. EC is
1458                  * set to the checksum size. We leave space in tm for
1459                  * a copy of the header - this will be trimmed later.
1460                  */
1461                 M_PREPEND(m, 16, M_WAITOK);
1462
1463                 MGET(tm, M_WAITOK, MT_DATA);
1464                 tm->m_len = cklen + 16;
1465                 mlast->m_next = tm;
1466                 ctlen = 0;
1467                 EC = cklen;
1468         }
1469
1470         p = m->m_data;
1471
1472         /* TOK_ID */
1473         p[0] = 0x05;
1474         p[1] = 0x04;
1475
1476         /* Flags */
1477         flags = 0;
1478         if (conf_req_flag)
1479                 flags = GSS_TOKEN_SEALED;
1480         if (is_acceptor(kc))
1481                 flags |= GSS_TOKEN_SENT_BY_ACCEPTOR;
1482         if (kc->kc_more_flags & ACCEPTOR_SUBKEY)
1483                 flags |= GSS_TOKEN_ACCEPTOR_SUBKEY;
1484         p[2] = flags;
1485
1486         /* Filler */
1487         p[3] = 0xff;
1488
1489         /* EC + RRC - set to zero initially */
1490         p[4] = 0;
1491         p[5] = 0;
1492         p[6] = 0;
1493         p[7] = 0;
1494
1495         /* SND_SEQ */
1496         p[8] = 0;
1497         p[9] = 0;
1498         p[10] = 0;
1499         p[11] = 0;
1500         seq = atomic_fetchadd_32(&kc->kc_local_seqnumber, 1);
1501         p[12] = (seq >> 24);
1502         p[13] = (seq >> 16);
1503         p[14] = (seq >> 8);
1504         p[15] = (seq >> 0);
1505
1506         if (conf_req_flag) {
1507                 /*
1508                  * Encrypt according to RFC 4121 section 4.2 and RFC
1509                  * 3961 section 5.3. Note: we don't generate tokens
1510                  * with RRC values other than zero. If we did, we
1511                  * should zero RRC in the copied header.
1512                  */
1513                 arc4rand(p + 16, blen, 0);
1514                 if (EC) {
1515                         m_copyback(m, 16 + blen + mlen, EC, zpad);
1516                 }
1517                 m_copyback(m, 16 + blen + mlen + EC, 16, p);
1518
1519                 krb5_checksum(Ki, 0, m, 16, ctlen, cklen);
1520                 krb5_encrypt(Ke, m, 16, ctlen, NULL, 0);
1521         } else {
1522                 /*
1523                  * The plaintext message is followed by a checksum of
1524                  * the plaintext plus a version of the header where EC
1525                  * and RRC are set to zero. Also, the original EC must
1526                  * be our checksum size.
1527                  */
1528                 bcopy(p, tm->m_data, 16);
1529                 krb5_checksum(Kc, 0, m, 16, mlen + 16, cklen);
1530                 tm->m_data += 16;
1531                 tm->m_len -= 16;
1532         }
1533
1534         /*
1535          * Finally set EC to its actual value
1536          */
1537         p[4] = EC >> 8;
1538         p[5] = EC;
1539
1540         *mp = m;
1541         return (GSS_S_COMPLETE);
1542 }
1543
1544 static OM_uint32
1545 krb5_wrap(gss_ctx_id_t ctx, OM_uint32 *minor_status,
1546     int conf_req_flag, gss_qop_t qop_req,
1547     struct mbuf **mp, int *conf_state)
1548 {
1549         struct krb5_context *kc = (struct krb5_context *)ctx;
1550
1551         *minor_status = 0;
1552         if (conf_state)
1553                 *conf_state = 0;
1554
1555         if (qop_req != GSS_C_QOP_DEFAULT)
1556                 return (GSS_S_BAD_QOP);
1557
1558         if (time_uptime > kc->kc_lifetime)
1559                 return (GSS_S_CONTEXT_EXPIRED);
1560
1561         switch (kc->kc_tokenkey->ks_class->ec_type) {
1562         case ETYPE_DES_CBC_CRC:
1563                 return (krb5_wrap_old(kc, conf_req_flag,
1564                         mp, conf_state, sgn_alg_des_md5, seal_alg_des));
1565
1566         case ETYPE_ARCFOUR_HMAC_MD5:
1567         case ETYPE_ARCFOUR_HMAC_MD5_56:
1568                 return (krb5_wrap_old(kc, conf_req_flag,
1569                         mp, conf_state, sgn_alg_hmac_md5, seal_alg_rc4));
1570
1571         case ETYPE_DES3_CBC_SHA1:
1572                 return (krb5_wrap_old(kc, conf_req_flag,
1573                         mp, conf_state, sgn_alg_des3_sha1, seal_alg_des3));
1574
1575         default:
1576                 return (krb5_wrap_new(kc, conf_req_flag, mp, conf_state));
1577         }
1578
1579         return (GSS_S_FAILURE);
1580 }
1581
1582 static void
1583 m_trim(struct mbuf *m, int len)
1584 {
1585         struct mbuf *n;
1586         int off;
1587
1588         if (m == NULL)
1589                 return;
1590         n = m_getptr(m, len, &off);
1591         if (n) {
1592                 n->m_len = off;
1593                 if (n->m_next) {
1594                         m_freem(n->m_next);
1595                         n->m_next = NULL;
1596                 }
1597         }
1598 }
1599
1600 static OM_uint32
1601 krb5_unwrap_old(struct krb5_context *kc, struct mbuf **mp, int *conf_state,
1602     uint8_t sgn_alg[2], uint8_t seal_alg[2])
1603 {
1604         OM_uint32 res;
1605         struct mbuf *m, *mlast, *hm, *cm, *n;
1606         uint8_t *p, dir;
1607         size_t mlen, tlen, elen, datalen, padlen;
1608         size_t cklen;
1609         uint8_t buf[32];
1610         uint32_t seq;
1611         int i, conf;
1612
1613         m = *mp;
1614         mlen = m_length(m, &mlast);
1615
1616         tlen = token_length(kc->kc_tokenkey);
1617         cklen = kc->kc_tokenkey->ks_class->ec_checksumlen;
1618
1619         p = krb5_verify_token("\x02\x01", tlen, &m, &elen, TRUE);
1620         *mp = m;
1621         if (!p)
1622                 return (GSS_S_DEFECTIVE_TOKEN);
1623         datalen = elen - tlen;
1624
1625         /*
1626          * Trim the framing header first to make life a little easier
1627          * later.
1628          */
1629         m_adj(m, p - (uint8_t *) m->m_data);
1630
1631         /* TOK_ID */
1632         p += 2;
1633
1634         /* SGN_ALG */
1635         if (p[0] != sgn_alg[0] || p[1] != sgn_alg[1])
1636                 return (GSS_S_DEFECTIVE_TOKEN);
1637         p += 2;
1638
1639         /* SEAL_ALG */
1640         if (p[0] == seal_alg[0] && p[1] == seal_alg[1])
1641                 conf = 1;
1642         else if (p[0] == 0xff && p[1] == 0xff)
1643                 conf = 0;
1644         else
1645                 return (GSS_S_DEFECTIVE_TOKEN);
1646         p += 2;
1647
1648         if (p[0] != 0xff || p[1] != 0xff)
1649                 return (GSS_S_DEFECTIVE_TOKEN);
1650         p += 2;
1651
1652         /*
1653          * SND_SEQ:
1654          *
1655          * Take the four bytes of the sequence number least
1656          * significant first (most significant for ARCFOUR) followed
1657          * by four bytes of direction marker (zero for initiator and
1658          * 0xff for acceptor). Encrypt that data using the SGN_CKSUM
1659          * as IV.
1660          */
1661         krb5_decrypt(kc->kc_tokenkey, m, 8, 8, p + 8, 8);
1662         if (sgn_alg[0] == 0x11) {
1663                 seq = p[3] | (p[2] << 8) | (p[1] << 16) | (p[0] << 24);
1664         } else {
1665                 seq = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
1666         }
1667
1668         if (is_initiator(kc)) {
1669                 dir = 0xff;
1670         } else {
1671                 dir = 0;
1672         }
1673         if (p[4] != dir || p[5] != dir || p[6] != dir || p[7] != dir)
1674                 return (GSS_S_DEFECTIVE_TOKEN);
1675
1676         if (kc->kc_msg_order.km_flags &
1677             (GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG)) {
1678                 res = krb5_sequence_check(kc, seq);
1679                 if (GSS_ERROR(res))
1680                         return (res);
1681         } else {
1682                 res = GSS_S_COMPLETE;
1683         }
1684
1685         /*
1686          * If the token was encrypted, decode it in-place.
1687          */
1688         if (conf) {
1689                 /*
1690                  * Decrypt the padded message with an IV of zero for
1691                  * DES and DES3 or an IV of the big-endian encoded
1692                  * sequence number for ARCFOUR.
1693                  */
1694                 if (seal_alg[0] == 0x10) {
1695                         krb5_decrypt(kc->kc_encryptkey, m, 16 + cklen,
1696                             datalen, p, 4);
1697                 } else {
1698                         krb5_decrypt(kc->kc_encryptkey, m, 16 + cklen,
1699                             datalen, NULL, 0);
1700                 }
1701         }
1702         if (conf_state)
1703                 *conf_state = conf;
1704
1705         /*
1706          * Check the trailing pad bytes.
1707          * RFC1964 specifies between 1<->8 bytes, each with a binary value
1708          * equal to the number of bytes.
1709          */
1710         if (mlast->m_len > 0)
1711                 padlen = mlast->m_data[mlast->m_len - 1];
1712         else {
1713                 n = m_getptr(m, tlen + datalen - 1, &i);
1714                 /*
1715                  * When the position is exactly equal to the # of data bytes
1716                  * in the mbuf list, m_getptr() will return the last mbuf in
1717                  * the list and an off == m_len for that mbuf, so that case
1718                  * needs to be checked as well as a NULL return.
1719                  */
1720                 if (n == NULL || n->m_len == i)
1721                         return (GSS_S_DEFECTIVE_TOKEN);
1722                 padlen = n->m_data[i];
1723         }
1724         if (padlen < 1 || padlen > 8 || padlen > tlen + datalen)
1725                 return (GSS_S_DEFECTIVE_TOKEN);
1726         m_copydata(m, tlen + datalen - padlen, padlen, buf);
1727         for (i = 0; i < padlen; i++) {
1728                 if (buf[i] != padlen) {
1729                         return (GSS_S_DEFECTIVE_TOKEN);
1730                 }
1731         }
1732
1733         /*
1734          * SGN_CKSUM:
1735          *
1736          * Calculate the keyed checksum of the token header plus the
1737          * padded message. We do a little mbuf surgery to trim out the
1738          * parts we don't want to checksum.
1739          */
1740         hm = m;
1741         *mp = m = m_split(m, 16 + cklen, M_WAITOK);
1742         mlast = m_last(m);
1743         hm->m_len = 8;
1744         hm->m_next = m;
1745         MGET(cm, M_WAITOK, MT_DATA);
1746         cm->m_len = cklen;
1747         mlast->m_next = cm;
1748
1749         krb5_checksum(kc->kc_checksumkey, 13, hm, 0, datalen + 8, cklen);
1750         hm->m_next = NULL;
1751         mlast->m_next = NULL;
1752
1753         if (bcmp(cm->m_data, hm->m_data + 16, cklen)) {
1754                 m_freem(hm);
1755                 m_free(cm);
1756                 return (GSS_S_BAD_SIG);
1757         }
1758         m_freem(hm);
1759         m_free(cm);
1760
1761         /*
1762          * Trim off the confounder and padding.
1763          */
1764         m_adj(m, 8);
1765         if (mlast->m_len >= padlen) {
1766                 mlast->m_len -= padlen;
1767         } else {
1768                 m_trim(m, datalen - 8 - padlen);
1769         }
1770
1771         *mp = m;
1772         return (res);
1773 }
1774
1775 static OM_uint32
1776 krb5_unwrap_new(struct krb5_context *kc, struct mbuf **mp, int *conf_state)
1777 {
1778         OM_uint32 res;
1779         struct krb5_key_state *Ke = kc->kc_recv_seal_Ke;
1780         struct krb5_key_state *Ki = kc->kc_recv_seal_Ki;
1781         struct krb5_key_state *Kc = kc->kc_recv_seal_Kc;
1782         const struct krb5_encryption_class *ec = Ke->ks_class;
1783         struct mbuf *m, *mlast, *hm, *cm;
1784         uint8_t *p, *pp;
1785         int sealed, flags, EC, RRC;
1786         size_t blen, cklen, ctlen, mlen, plen, tlen;
1787         char buf[32], buf2[32];
1788
1789         m = *mp;
1790         mlen = m_length(m, &mlast);
1791
1792         if (mlen <= 16)
1793                 return (GSS_S_DEFECTIVE_TOKEN);
1794         if (m->m_len < 16) {
1795                 m = m_pullup(m, 16);
1796                 *mp = m;
1797         }
1798         p = m->m_data;
1799
1800         /* TOK_ID */
1801         if (p[0] != 0x05)
1802                 return (GSS_S_DEFECTIVE_TOKEN);
1803         if (p[1] != 0x04)
1804                 return (GSS_S_DEFECTIVE_TOKEN);
1805
1806         /* Flags */
1807         sealed = p[2] & GSS_TOKEN_SEALED;
1808         flags = sealed;
1809         if (is_initiator(kc))
1810                 flags |= GSS_TOKEN_SENT_BY_ACCEPTOR;
1811         if (kc->kc_more_flags & ACCEPTOR_SUBKEY)
1812                 flags |= GSS_TOKEN_ACCEPTOR_SUBKEY;
1813         if (p[2] != flags)
1814                 return (GSS_S_DEFECTIVE_TOKEN);
1815
1816         /* Filler */
1817         if (p[3] != 0xff)
1818                 return (GSS_S_DEFECTIVE_TOKEN);
1819
1820         /* EC + RRC */
1821         EC = (p[4] << 8) + p[5];
1822         RRC = (p[6] << 8) + p[7];
1823
1824         /* SND_SEQ */
1825         if (kc->kc_msg_order.km_flags &
1826                 (GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG)) {
1827                 uint32_t seq;
1828                 if (p[8] || p[9] || p[10] || p[11]) {
1829                         res = GSS_S_UNSEQ_TOKEN;
1830                 } else {
1831                         seq = (p[12] << 24) | (p[13] << 16)
1832                                 | (p[14] << 8) | p[15];
1833                         res = krb5_sequence_check(kc, seq);
1834                 }
1835                 if (GSS_ERROR(res))
1836                         return (res);
1837         } else {
1838                 res = GSS_S_COMPLETE;
1839         }
1840
1841         /*
1842          * Separate the header before dealing with RRC. We only need
1843          * to keep the header if the message isn't encrypted.
1844          */
1845         if (sealed) {
1846                 hm = NULL;
1847                 m_adj(m, 16);
1848         } else {
1849                 hm = m;
1850                 *mp = m = m_split(m, 16, M_WAITOK);
1851                 mlast = m_last(m);
1852         }
1853
1854         /*
1855          * Undo the effects of RRC by rotating left.
1856          */
1857         if (RRC > 0) {
1858                 struct mbuf *rm;
1859                 size_t rlen;
1860
1861                 rlen = mlen - 16;
1862                 if (RRC <= sizeof(buf) && m->m_len >= rlen) {
1863                         /*
1864                          * Simple case, just rearrange the bytes in m.
1865                          */
1866                         bcopy(m->m_data, buf, RRC);
1867                         bcopy(m->m_data + RRC, m->m_data, rlen - RRC);
1868                         bcopy(buf, m->m_data + rlen - RRC, RRC);
1869                 } else {
1870                         /*
1871                          * More complicated - rearrange the mbuf
1872                          * chain.
1873                          */
1874                         rm = m;
1875                         *mp = m = m_split(m, RRC, M_WAITOK);
1876                         m_cat(m, rm);
1877                         mlast = rm;
1878                 }
1879         }
1880
1881         blen = ec->ec_blocklen;
1882         cklen = ec->ec_checksumlen;
1883         if (sealed) {
1884                 /*
1885                  * Decrypt according to RFC 4121 section 4.2 and RFC
1886                  * 3961 section 5.3. The message must be large enough
1887                  * for a blocksize confounder, at least one block of
1888                  * cyphertext and a checksum.
1889                  */
1890                 if (mlen < 16 + 2*blen + cklen)
1891                         return (GSS_S_DEFECTIVE_TOKEN);
1892
1893                 ctlen = mlen - 16 - cklen;
1894                 krb5_decrypt(Ke, m, 0, ctlen, NULL, 0);
1895
1896                 /*
1897                  * The size of the plaintext is ctlen minus blocklen
1898                  * (for the confounder), 16 (for the copy of the token
1899                  * header) and EC (for the filler). The actual
1900                  * plaintext starts after the confounder.
1901                  */
1902                 plen = ctlen - blen - 16 - EC;
1903                 pp = p + 16 + blen;
1904
1905                 /*
1906                  * Checksum the padded plaintext.
1907                  */
1908                 m_copydata(m, ctlen, cklen, buf);
1909                 krb5_checksum(Ki, 0, m, 0, ctlen, cklen);
1910                 m_copydata(m, ctlen, cklen, buf2);
1911
1912                 if (bcmp(buf, buf2, cklen))
1913                         return (GSS_S_BAD_SIG);
1914
1915                 /*
1916                  * Trim the message back to just plaintext.
1917                  */
1918                 m_adj(m, blen);
1919                 tlen = 16 + EC + cklen;
1920                 if (mlast->m_len >= tlen) {
1921                         mlast->m_len -= tlen;
1922                 } else {
1923                         m_trim(m, plen);
1924                 }
1925         } else {
1926                 /*
1927                  * The plaintext message is followed by a checksum of
1928                  * the plaintext plus a version of the header where EC
1929                  * and RRC are set to zero. Also, the original EC must
1930                  * be our checksum size.
1931                  */
1932                 if (mlen < 16 + cklen || EC != cklen)
1933                         return (GSS_S_DEFECTIVE_TOKEN);
1934
1935                 /*
1936                  * The size of the plaintext is simply the message
1937                  * size less header and checksum. The plaintext starts
1938                  * right after the header (which we have saved in hm).
1939                  */
1940                 plen = mlen - 16 - cklen;
1941
1942                 /*
1943                  * Insert a copy of the header (with EC and RRC set to
1944                  * zero) between the plaintext message and the
1945                  * checksum.
1946                  */
1947                 p = hm->m_data;
1948                 p[4] = p[5] = p[6] = p[7] = 0;
1949
1950                 cm = m_split(m, plen, M_WAITOK);
1951                 mlast = m_last(m);
1952                 m->m_next = hm;
1953                 hm->m_next = cm;
1954
1955                 bcopy(cm->m_data, buf, cklen);
1956                 krb5_checksum(Kc, 0, m, 0, plen + 16, cklen);
1957                 if (bcmp(cm->m_data, buf, cklen))
1958                         return (GSS_S_BAD_SIG);
1959
1960                 /*
1961                  * The checksum matches, discard all buf the plaintext.
1962                  */
1963                 mlast->m_next = NULL;
1964                 m_freem(hm);
1965         }
1966
1967         if (conf_state)
1968                 *conf_state = (sealed != 0);
1969
1970         return (res);
1971 }
1972
1973 static OM_uint32
1974 krb5_unwrap(gss_ctx_id_t ctx, OM_uint32 *minor_status,
1975     struct mbuf **mp, int *conf_state, gss_qop_t *qop_state)
1976 {
1977         struct krb5_context *kc = (struct krb5_context *)ctx;
1978         OM_uint32 maj_stat;
1979
1980         *minor_status = 0;
1981         if (qop_state)
1982                 *qop_state = GSS_C_QOP_DEFAULT;
1983         if (conf_state)
1984                 *conf_state = 0;
1985
1986         if (time_uptime > kc->kc_lifetime)
1987                 return (GSS_S_CONTEXT_EXPIRED);
1988
1989         switch (kc->kc_tokenkey->ks_class->ec_type) {
1990         case ETYPE_DES_CBC_CRC:
1991                 maj_stat = krb5_unwrap_old(kc, mp, conf_state,
1992                         sgn_alg_des_md5, seal_alg_des);
1993                 break;
1994
1995         case ETYPE_ARCFOUR_HMAC_MD5:
1996         case ETYPE_ARCFOUR_HMAC_MD5_56:
1997                 maj_stat = krb5_unwrap_old(kc, mp, conf_state,
1998                         sgn_alg_hmac_md5, seal_alg_rc4);
1999                 break;
2000
2001         case ETYPE_DES3_CBC_SHA1:
2002                 maj_stat = krb5_unwrap_old(kc, mp, conf_state,
2003                         sgn_alg_des3_sha1, seal_alg_des3);
2004                 break;
2005
2006         default:
2007                 maj_stat = krb5_unwrap_new(kc, mp, conf_state);
2008                 break;
2009         }
2010
2011         if (GSS_ERROR(maj_stat)) {
2012                 m_freem(*mp);
2013                 *mp = NULL;
2014         }
2015
2016         return (maj_stat);
2017 }
2018
2019 static OM_uint32
2020 krb5_wrap_size_limit(gss_ctx_id_t ctx, OM_uint32 *minor_status,
2021     int conf_req_flag, gss_qop_t qop_req, OM_uint32 req_output_size,
2022     OM_uint32 *max_input_size)
2023 {
2024         struct krb5_context *kc = (struct krb5_context *)ctx;
2025         const struct krb5_encryption_class *ec;
2026         OM_uint32 overhead;
2027
2028         *minor_status = 0;
2029         *max_input_size = 0;
2030
2031         if (qop_req != GSS_C_QOP_DEFAULT)
2032                 return (GSS_S_BAD_QOP);
2033
2034         ec = kc->kc_tokenkey->ks_class;
2035         switch (ec->ec_type) {
2036         case ETYPE_DES_CBC_CRC:
2037         case ETYPE_DES3_CBC_SHA1:
2038         case ETYPE_ARCFOUR_HMAC_MD5: 
2039         case ETYPE_ARCFOUR_HMAC_MD5_56:
2040                 /*
2041                  * up to 5 bytes for [APPLICATION 0] SEQUENCE
2042                  * 2 + krb5 oid length
2043                  * 8 bytes of header
2044                  * 8 bytes of confounder
2045                  * maximum of 8 bytes of padding
2046                  * checksum
2047                  */
2048                 overhead = 5 + 2 + krb5_mech_oid.length;
2049                 overhead += 8 + 8 + ec->ec_msgblocklen;
2050                 overhead += ec->ec_checksumlen;
2051                 break;
2052
2053         default:
2054                 if (conf_req_flag) {
2055                         /*
2056                          * 16 byts of header
2057                          * blocklen bytes of confounder
2058                          * up to msgblocklen - 1 bytes of padding
2059                          * 16 bytes for copy of header
2060                          * checksum
2061                          */
2062                         overhead = 16 + ec->ec_blocklen;
2063                         overhead += ec->ec_msgblocklen - 1;
2064                         overhead += 16;
2065                         overhead += ec->ec_checksumlen;
2066                 } else {
2067                         /*
2068                          * 16 bytes of header plus checksum.
2069                          */
2070                         overhead = 16 + ec->ec_checksumlen;
2071                 }
2072         }
2073
2074         *max_input_size = req_output_size - overhead;
2075
2076         return (GSS_S_COMPLETE);
2077 }
2078
2079 static kobj_method_t krb5_methods[] = {
2080         KOBJMETHOD(kgss_init,           krb5_init),
2081         KOBJMETHOD(kgss_import,         krb5_import),
2082         KOBJMETHOD(kgss_delete,         krb5_delete),
2083         KOBJMETHOD(kgss_mech_type,      krb5_mech_type),
2084         KOBJMETHOD(kgss_get_mic,        krb5_get_mic),
2085         KOBJMETHOD(kgss_verify_mic,     krb5_verify_mic),
2086         KOBJMETHOD(kgss_wrap,           krb5_wrap),
2087         KOBJMETHOD(kgss_unwrap,         krb5_unwrap),
2088         KOBJMETHOD(kgss_wrap_size_limit, krb5_wrap_size_limit),
2089         { 0, 0 }
2090 };
2091
2092 static struct kobj_class krb5_class = {
2093         "kerberosv5",
2094         krb5_methods,
2095         sizeof(struct krb5_context)
2096 };
2097
2098 /*
2099  * Kernel module glue
2100  */
2101 static int
2102 kgssapi_krb5_modevent(module_t mod, int type, void *data)
2103 {
2104
2105         switch (type) {
2106         case MOD_LOAD:
2107                 kgss_install_mech(&krb5_mech_oid, "kerberosv5", &krb5_class);
2108                 break;
2109
2110         case MOD_UNLOAD:
2111                 kgss_uninstall_mech(&krb5_mech_oid);
2112                 break;
2113         }
2114
2115
2116         return (0);
2117 }
2118 static moduledata_t kgssapi_krb5_mod = {
2119         "kgssapi_krb5",
2120         kgssapi_krb5_modevent,
2121         NULL,
2122 };
2123 DECLARE_MODULE(kgssapi_krb5, kgssapi_krb5_mod, SI_SUB_VFS, SI_ORDER_ANY);
2124 MODULE_DEPEND(kgssapi_krb5, kgssapi, 1, 1, 1);
2125 MODULE_DEPEND(kgssapi_krb5, crypto, 1, 1, 1);
2126 MODULE_DEPEND(kgssapi_krb5, rc4, 1, 1, 1);
2127 MODULE_VERSION(kgssapi_krb5, 1);