17c478bd9Sstevel@tonic-gate /*
25e01956fSGlenn Barry * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
37c478bd9Sstevel@tonic-gate */
47c478bd9Sstevel@tonic-gate /*
57c478bd9Sstevel@tonic-gate * lib/gssapi/krb5/k5sealv3.c
67c478bd9Sstevel@tonic-gate *
77c478bd9Sstevel@tonic-gate * Copyright 2003,2004 by the Massachusetts Institute of Technology.
87c478bd9Sstevel@tonic-gate * All Rights Reserved.
97c478bd9Sstevel@tonic-gate *
107c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may
117c478bd9Sstevel@tonic-gate * require a specific license from the United States Government.
127c478bd9Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating
137c478bd9Sstevel@tonic-gate * export to obtain such a license before exporting.
14*55fea89dSDan Cross *
157c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
167c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and
177c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright
187c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and
197c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that
207c478bd9Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining
217c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior
22159d09a2SMark Phalan * permission. Furthermore if you modify this software you must label
237c478bd9Sstevel@tonic-gate * your software as modified software and not distribute it in such a
247c478bd9Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software.
257c478bd9Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of
267c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express
277c478bd9Sstevel@tonic-gate * or implied warranty.
28*55fea89dSDan Cross *
297c478bd9Sstevel@tonic-gate *
307c478bd9Sstevel@tonic-gate */
317c478bd9Sstevel@tonic-gate /* draft-ietf-krb-wg-gssapi-cfx-05 */
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate #ifndef _KERNEL
347c478bd9Sstevel@tonic-gate #include <assert.h>
357c478bd9Sstevel@tonic-gate #include <stdarg.h>
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate #define ASSERT assert
387c478bd9Sstevel@tonic-gate #endif
397c478bd9Sstevel@tonic-gate
40159d09a2SMark Phalan /* Solaris Kerberos */
41159d09a2SMark Phalan #include "k5-int.h" /* for zap() */
42159d09a2SMark Phalan #include "k5-platform.h"
43159d09a2SMark Phalan
44159d09a2SMark Phalan /* Solaris Kerberos */
45159d09a2SMark Phalan #include "k5-platform-store_16.h"
46159d09a2SMark Phalan #include "k5-platform-store_64.h"
47159d09a2SMark Phalan #include "k5-platform-load_16.h"
48159d09a2SMark Phalan #include "k5-platform-load_64.h"
49159d09a2SMark Phalan
50159d09a2SMark Phalan #include "gssapiP_krb5.h"
517c478bd9Sstevel@tonic-gate #include <sys/int_limits.h>
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate static int
rotate_left(void * ptr,size_t bufsiz,size_t rc)547c478bd9Sstevel@tonic-gate rotate_left (void *ptr, size_t bufsiz, size_t rc)
557c478bd9Sstevel@tonic-gate {
567c478bd9Sstevel@tonic-gate /* Optimize for receiving. After some debugging is done, the MIT
577c478bd9Sstevel@tonic-gate implementation won't do any rotates on sending, and while
587c478bd9Sstevel@tonic-gate debugging, they'll be randomly chosen.
597c478bd9Sstevel@tonic-gate
607c478bd9Sstevel@tonic-gate Return 1 for success, 0 for failure (ENOMEM). */
617c478bd9Sstevel@tonic-gate void *tbuf;
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate if (bufsiz == 0)
647c478bd9Sstevel@tonic-gate return 1;
657c478bd9Sstevel@tonic-gate rc = rc % bufsiz;
667c478bd9Sstevel@tonic-gate if (rc == 0)
677c478bd9Sstevel@tonic-gate return 1;
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate tbuf = MALLOC(rc);
707c478bd9Sstevel@tonic-gate if (tbuf == 0)
717c478bd9Sstevel@tonic-gate return 0;
727c478bd9Sstevel@tonic-gate (void) memcpy(tbuf, ptr, rc);
737c478bd9Sstevel@tonic-gate (void) memmove(ptr, (char *)ptr + rc, bufsiz - rc);
747c478bd9Sstevel@tonic-gate (void) memcpy((char *)ptr + bufsiz - rc, tbuf, rc);
757c478bd9Sstevel@tonic-gate FREE(tbuf, rc);
767c478bd9Sstevel@tonic-gate return 1;
777c478bd9Sstevel@tonic-gate }
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate static const gss_buffer_desc empty_message = { 0, 0 };
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate #define FLAG_SENDER_IS_ACCEPTOR 0x01
827c478bd9Sstevel@tonic-gate #define FLAG_WRAP_CONFIDENTIAL 0x02
837c478bd9Sstevel@tonic-gate #define FLAG_ACCEPTOR_SUBKEY 0x04
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate krb5_error_code
gss_krb5int_make_seal_token_v3(krb5_context context,krb5_gss_ctx_id_rec * ctx,const gss_buffer_desc * message,gss_buffer_t token,int conf_req_flag,int toktype)867c478bd9Sstevel@tonic-gate gss_krb5int_make_seal_token_v3 (krb5_context context,
877c478bd9Sstevel@tonic-gate krb5_gss_ctx_id_rec *ctx,
887c478bd9Sstevel@tonic-gate const gss_buffer_desc * message,
897c478bd9Sstevel@tonic-gate gss_buffer_t token,
907c478bd9Sstevel@tonic-gate int conf_req_flag, int toktype)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate size_t bufsize = 16;
937c478bd9Sstevel@tonic-gate unsigned char *outbuf = 0;
947c478bd9Sstevel@tonic-gate krb5_error_code err;
957c478bd9Sstevel@tonic-gate int key_usage;
967c478bd9Sstevel@tonic-gate unsigned char acceptor_flag;
977c478bd9Sstevel@tonic-gate const gss_buffer_desc *message2 = message;
98ab9b2e15Sgtb #ifdef CFX_EXERCISE
99ab9b2e15Sgtb size_t rrc;
100ab9b2e15Sgtb #endif
1017c478bd9Sstevel@tonic-gate size_t ec;
1027c478bd9Sstevel@tonic-gate unsigned short tok_id;
1037c478bd9Sstevel@tonic-gate krb5_checksum sum;
1047c478bd9Sstevel@tonic-gate krb5_keyblock *key;
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate ASSERT(toktype != KG_TOK_SEAL_MSG || ctx->enc != 0);
1077c478bd9Sstevel@tonic-gate ASSERT(ctx->big_endian == 0);
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
1107c478bd9Sstevel@tonic-gate key_usage = (toktype == KG_TOK_WRAP_MSG
1117c478bd9Sstevel@tonic-gate ? (ctx->initiate
1127c478bd9Sstevel@tonic-gate ? KG_USAGE_INITIATOR_SEAL
1137c478bd9Sstevel@tonic-gate : KG_USAGE_ACCEPTOR_SEAL)
1147c478bd9Sstevel@tonic-gate : (ctx->initiate
1157c478bd9Sstevel@tonic-gate ? KG_USAGE_INITIATOR_SIGN
1167c478bd9Sstevel@tonic-gate : KG_USAGE_ACCEPTOR_SIGN));
1177c478bd9Sstevel@tonic-gate if (ctx->have_acceptor_subkey) {
1187c478bd9Sstevel@tonic-gate key = ctx->acceptor_subkey;
1197c478bd9Sstevel@tonic-gate } else {
1207c478bd9Sstevel@tonic-gate key = ctx->enc;
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate #ifdef _KERNEL
1247c478bd9Sstevel@tonic-gate context->kef_cipher_mt = get_cipher_mech_type(context, key);
1257c478bd9Sstevel@tonic-gate context->kef_hash_mt = get_hash_mech_type(context, key);
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate if ((err = init_key_kef(context->kef_cipher_mt, key))) {
1287c478bd9Sstevel@tonic-gate return (GSS_S_FAILURE);
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate #ifdef CFX_EXERCISE
1347c478bd9Sstevel@tonic-gate {
1357c478bd9Sstevel@tonic-gate static int initialized = 0;
1367c478bd9Sstevel@tonic-gate if (!initialized) {
1377c478bd9Sstevel@tonic-gate srand(time(0));
1387c478bd9Sstevel@tonic-gate initialized = 1;
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate #endif
1427c478bd9Sstevel@tonic-gate
1437c478bd9Sstevel@tonic-gate if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
1447c478bd9Sstevel@tonic-gate krb5_data plain;
1457c478bd9Sstevel@tonic-gate krb5_enc_data cipher;
1467c478bd9Sstevel@tonic-gate size_t ec_max;
1477c478bd9Sstevel@tonic-gate size_t tlen;
1487c478bd9Sstevel@tonic-gate
1497c478bd9Sstevel@tonic-gate /* 300: Adds some slop. */
1507c478bd9Sstevel@tonic-gate if (SIZE_MAX - 300 < message->length)
1517c478bd9Sstevel@tonic-gate return ENOMEM;
1527c478bd9Sstevel@tonic-gate ec_max = SIZE_MAX - message->length - 300;
1537c478bd9Sstevel@tonic-gate if (ec_max > 0xffff)
1547c478bd9Sstevel@tonic-gate ec_max = 0xffff;
1557c478bd9Sstevel@tonic-gate /*
1567c478bd9Sstevel@tonic-gate * EC should really be a multiple (1) of the number of octets that
1577c478bd9Sstevel@tonic-gate * the cryptosystem would pad by if we didn't have the filler.
1587c478bd9Sstevel@tonic-gate *
1597c478bd9Sstevel@tonic-gate * For AES-CTS this will always be 0 and we expect no further
1607c478bd9Sstevel@tonic-gate * enctypes, so there should be no issue here.
1617c478bd9Sstevel@tonic-gate */
1627c478bd9Sstevel@tonic-gate ec = 0;
1637c478bd9Sstevel@tonic-gate plain.length = message->length + 16 + ec;
1647c478bd9Sstevel@tonic-gate plain.data = MALLOC(plain.length);
1657c478bd9Sstevel@tonic-gate if (plain.data == NULL)
1667c478bd9Sstevel@tonic-gate return ENOMEM;
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate /* Get size of ciphertext. */
1697c478bd9Sstevel@tonic-gate if ((err = krb5_c_encrypt_length(context,
1707c478bd9Sstevel@tonic-gate ctx->enc->enctype, plain.length, &tlen))) {
1717c478bd9Sstevel@tonic-gate FREE(plain.data, plain.length);
1727c478bd9Sstevel@tonic-gate return (err);
1737c478bd9Sstevel@tonic-gate }
174*55fea89dSDan Cross
1757c478bd9Sstevel@tonic-gate bufsize = 16 + tlen;
1767c478bd9Sstevel@tonic-gate /* Allocate space for header plus encrypted data. */
1777c478bd9Sstevel@tonic-gate outbuf = MALLOC(bufsize);
1787c478bd9Sstevel@tonic-gate if (outbuf == NULL) {
1797c478bd9Sstevel@tonic-gate FREE(plain.data, plain.length);
1807c478bd9Sstevel@tonic-gate return ENOMEM;
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate /* TOK_ID */
1847c478bd9Sstevel@tonic-gate store_16_be(0x0504, outbuf);
1857c478bd9Sstevel@tonic-gate /* flags */
1867c478bd9Sstevel@tonic-gate outbuf[2] = (acceptor_flag
1877c478bd9Sstevel@tonic-gate | (conf_req_flag ? FLAG_WRAP_CONFIDENTIAL : 0)
1887c478bd9Sstevel@tonic-gate | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
1897c478bd9Sstevel@tonic-gate /* filler */
1907c478bd9Sstevel@tonic-gate outbuf[3] = 0xff;
1917c478bd9Sstevel@tonic-gate /* EC */
1927c478bd9Sstevel@tonic-gate store_16_be(ec, outbuf+4);
1937c478bd9Sstevel@tonic-gate /* RRC */
1947c478bd9Sstevel@tonic-gate store_16_be(0, outbuf+6);
1957c478bd9Sstevel@tonic-gate store_64_be(ctx->seq_send, outbuf+8);
1967c478bd9Sstevel@tonic-gate
1977c478bd9Sstevel@tonic-gate (void) memcpy(plain.data, message->value, message->length);
1987c478bd9Sstevel@tonic-gate (void) memset(plain.data + message->length, 'x', ec);
1997c478bd9Sstevel@tonic-gate (void) memcpy(plain.data + message->length + ec, outbuf, 16);
2007c478bd9Sstevel@tonic-gate
2017c478bd9Sstevel@tonic-gate /* Should really use scatter/gather crypto interfaces */
2027c478bd9Sstevel@tonic-gate cipher.ciphertext.data = (char *)outbuf + 16;
2037c478bd9Sstevel@tonic-gate cipher.ciphertext.length = bufsize - 16;
2047c478bd9Sstevel@tonic-gate cipher.enctype = key->enctype;
2057c478bd9Sstevel@tonic-gate err = krb5_c_encrypt(context, key, key_usage, 0, &plain, &cipher);
2067c478bd9Sstevel@tonic-gate (void) bzero(plain.data, plain.length);
2077c478bd9Sstevel@tonic-gate FREE(plain.data, plain.length);
2087c478bd9Sstevel@tonic-gate plain.data = 0;
2097c478bd9Sstevel@tonic-gate if (err)
2107c478bd9Sstevel@tonic-gate goto error;
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate /* Now that we know we're returning a valid token.... */
2137c478bd9Sstevel@tonic-gate ctx->seq_send++;
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate #ifdef CFX_EXERCISE
2167c478bd9Sstevel@tonic-gate rrc = rand() & 0xffff;
2177c478bd9Sstevel@tonic-gate if (rotate_left(outbuf+16, bufsize-16,
2187c478bd9Sstevel@tonic-gate (bufsize-16) - (rrc % (bufsize - 16))))
2197c478bd9Sstevel@tonic-gate store_16_be(rrc, outbuf+6);
2207c478bd9Sstevel@tonic-gate /* If the rotate fails, don't worry about it. */
2217c478bd9Sstevel@tonic-gate #endif
2227c478bd9Sstevel@tonic-gate } else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) {
2237c478bd9Sstevel@tonic-gate krb5_data plain;
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate /* Here, message is the application-supplied data; message2 is
2267c478bd9Sstevel@tonic-gate what goes into the output token. They may be the same, or
2277c478bd9Sstevel@tonic-gate message2 may be empty (for MIC). */
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate tok_id = 0x0504;
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate wrap_with_checksum:
2327c478bd9Sstevel@tonic-gate plain.length = message->length + 16;
2337c478bd9Sstevel@tonic-gate plain.data = MALLOC(message->length + 16);
2347c478bd9Sstevel@tonic-gate if (plain.data == NULL)
2357c478bd9Sstevel@tonic-gate return ENOMEM;
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate if (ctx->cksum_size > 0xffff) {
2387c478bd9Sstevel@tonic-gate FREE(plain.data, plain.length);
2397c478bd9Sstevel@tonic-gate return EINVAL;
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate bufsize = 16 + message2->length + ctx->cksum_size;
2437c478bd9Sstevel@tonic-gate outbuf = MALLOC(bufsize);
2447c478bd9Sstevel@tonic-gate if (outbuf == NULL) {
2457c478bd9Sstevel@tonic-gate FREE(plain.data, plain.length);
2467c478bd9Sstevel@tonic-gate plain.data = 0;
2477c478bd9Sstevel@tonic-gate err = ENOMEM;
2487c478bd9Sstevel@tonic-gate goto error;
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate /* TOK_ID */
2527c478bd9Sstevel@tonic-gate store_16_be(tok_id, outbuf);
2537c478bd9Sstevel@tonic-gate /* flags */
2547c478bd9Sstevel@tonic-gate outbuf[2] = (acceptor_flag
2557c478bd9Sstevel@tonic-gate | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
2567c478bd9Sstevel@tonic-gate /* filler */
2577c478bd9Sstevel@tonic-gate outbuf[3] = 0xff;
2587c478bd9Sstevel@tonic-gate if (toktype == KG_TOK_WRAP_MSG) {
2597c478bd9Sstevel@tonic-gate /* Use 0 for checksum calculation, substitute
2607c478bd9Sstevel@tonic-gate checksum length later. */
2617c478bd9Sstevel@tonic-gate /* EC */
2627c478bd9Sstevel@tonic-gate store_16_be(0, outbuf+4);
2637c478bd9Sstevel@tonic-gate /* RRC */
2647c478bd9Sstevel@tonic-gate store_16_be(0, outbuf+6);
2657c478bd9Sstevel@tonic-gate } else {
2667c478bd9Sstevel@tonic-gate /* MIC and DEL store 0xFF in EC and RRC. */
2677c478bd9Sstevel@tonic-gate store_16_be(0xffff, outbuf+4);
2687c478bd9Sstevel@tonic-gate store_16_be(0xffff, outbuf+6);
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate store_64_be(ctx->seq_send, outbuf+8);
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate (void) memcpy(plain.data, message->value, message->length);
2737c478bd9Sstevel@tonic-gate (void) memcpy(plain.data + message->length, outbuf, 16);
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate /* Fill in the output token -- data contents, if any, and
2767c478bd9Sstevel@tonic-gate space for the checksum. */
2777c478bd9Sstevel@tonic-gate if (message2->length)
2787c478bd9Sstevel@tonic-gate (void) memcpy(outbuf + 16, message2->value, message2->length);
2797c478bd9Sstevel@tonic-gate
2807c478bd9Sstevel@tonic-gate sum.contents = outbuf + 16 + message2->length;
2817c478bd9Sstevel@tonic-gate sum.length = ctx->cksum_size;
2827c478bd9Sstevel@tonic-gate
2837c478bd9Sstevel@tonic-gate err = krb5_c_make_checksum(context, ctx->cksumtype, key,
2847c478bd9Sstevel@tonic-gate key_usage, &plain, &sum);
2857c478bd9Sstevel@tonic-gate bzero(plain.data, plain.length);
2867c478bd9Sstevel@tonic-gate FREE(plain.data, plain.length);
2877c478bd9Sstevel@tonic-gate plain.data = 0;
2887c478bd9Sstevel@tonic-gate if (err) {
2897c478bd9Sstevel@tonic-gate bzero(outbuf,bufsize);
2907c478bd9Sstevel@tonic-gate err = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2917c478bd9Sstevel@tonic-gate goto error;
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate if (sum.length != ctx->cksum_size) {
2947c478bd9Sstevel@tonic-gate err = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2957c478bd9Sstevel@tonic-gate goto error;
2967c478bd9Sstevel@tonic-gate }
2977c478bd9Sstevel@tonic-gate (void) memcpy(outbuf + 16 + message2->length, sum.contents,
2987c478bd9Sstevel@tonic-gate ctx->cksum_size);
2997c478bd9Sstevel@tonic-gate krb5_free_checksum_contents(context, &sum);
3007c478bd9Sstevel@tonic-gate sum.contents = 0;
3017c478bd9Sstevel@tonic-gate /* Now that we know we're actually generating the token... */
3027c478bd9Sstevel@tonic-gate ctx->seq_send++;
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate if (toktype == KG_TOK_WRAP_MSG) {
3057c478bd9Sstevel@tonic-gate #ifdef CFX_EXERCISE
3067c478bd9Sstevel@tonic-gate rrc = rand() & 0xffff;
3077c478bd9Sstevel@tonic-gate /* If the rotate fails, don't worry about it. */
3087c478bd9Sstevel@tonic-gate if (rotate_left(outbuf+16, bufsize-16,
3097c478bd9Sstevel@tonic-gate (bufsize-16) - (rrc % (bufsize - 16))))
3107c478bd9Sstevel@tonic-gate store_16_be(rrc, outbuf+6);
3117c478bd9Sstevel@tonic-gate #endif
3127c478bd9Sstevel@tonic-gate /* Fix up EC field. */
3137c478bd9Sstevel@tonic-gate store_16_be(ctx->cksum_size, outbuf+4);
3147c478bd9Sstevel@tonic-gate } else {
3157c478bd9Sstevel@tonic-gate store_16_be(0xffff, outbuf+6);
3167c478bd9Sstevel@tonic-gate }
3177c478bd9Sstevel@tonic-gate } else if (toktype == KG_TOK_MIC_MSG) {
3187c478bd9Sstevel@tonic-gate tok_id = 0x0404;
3197c478bd9Sstevel@tonic-gate message2 = &empty_message;
3207c478bd9Sstevel@tonic-gate goto wrap_with_checksum;
3217c478bd9Sstevel@tonic-gate } else if (toktype == KG_TOK_DEL_CTX) {
3223dba6097Smp /*
3233dba6097Smp * Solaris Kerberos:
3243dba6097Smp * No token should be generated for context deletion. Just
3253dba6097Smp * return.
3263dba6097Smp */
3273dba6097Smp return 0;
3287c478bd9Sstevel@tonic-gate } else {
3297c478bd9Sstevel@tonic-gate err = KRB5KRB_AP_ERR_BAD_INTEGRITY;
3307c478bd9Sstevel@tonic-gate goto error;
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate
3337c478bd9Sstevel@tonic-gate token->value = outbuf;
3347c478bd9Sstevel@tonic-gate token->length = bufsize;
3357c478bd9Sstevel@tonic-gate return 0;
3367c478bd9Sstevel@tonic-gate
3377c478bd9Sstevel@tonic-gate error:
3387c478bd9Sstevel@tonic-gate FREE(outbuf, bufsize);
3397c478bd9Sstevel@tonic-gate token->value = NULL;
3407c478bd9Sstevel@tonic-gate token->length = 0;
3417c478bd9Sstevel@tonic-gate return err;
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate /* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
3457c478bd9Sstevel@tonic-gate conf_state is only valid if SEAL. */
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate OM_uint32
gss_krb5int_unseal_token_v3(krb5_context * contextptr,OM_uint32 * minor_status,krb5_gss_ctx_id_rec * ctx,unsigned char * ptr,int bodysize,gss_buffer_t message_buffer,int * conf_state,int * qop_state,int toktype)348159d09a2SMark Phalan gss_krb5int_unseal_token_v3(krb5_context *contextptr,
3497c478bd9Sstevel@tonic-gate OM_uint32 *minor_status,
3507c478bd9Sstevel@tonic-gate krb5_gss_ctx_id_rec *ctx,
3517c478bd9Sstevel@tonic-gate unsigned char *ptr, int bodysize,
3527c478bd9Sstevel@tonic-gate gss_buffer_t message_buffer,
3537c478bd9Sstevel@tonic-gate int *conf_state, int *qop_state, int toktype)
3547c478bd9Sstevel@tonic-gate {
355159d09a2SMark Phalan krb5_context context = *contextptr;
3567c478bd9Sstevel@tonic-gate krb5_data plain;
3577c478bd9Sstevel@tonic-gate gssint_uint64 seqnum;
3587c478bd9Sstevel@tonic-gate size_t ec, rrc;
3597c478bd9Sstevel@tonic-gate int key_usage;
3607c478bd9Sstevel@tonic-gate unsigned char acceptor_flag;
3617c478bd9Sstevel@tonic-gate krb5_checksum sum;
3627c478bd9Sstevel@tonic-gate krb5_error_code err;
3637c478bd9Sstevel@tonic-gate krb5_boolean valid;
3647c478bd9Sstevel@tonic-gate krb5_keyblock *key;
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate ASSERT(toktype != KG_TOK_SEAL_MSG || ctx->enc != 0);
3677c478bd9Sstevel@tonic-gate ASSERT(ctx->big_endian == 0);
3687c478bd9Sstevel@tonic-gate ASSERT(ctx->proto == 1);
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate if (qop_state)
3717c478bd9Sstevel@tonic-gate *qop_state = GSS_C_QOP_DEFAULT;
3727c478bd9Sstevel@tonic-gate
3737c478bd9Sstevel@tonic-gate acceptor_flag = ctx->initiate ? FLAG_SENDER_IS_ACCEPTOR : 0;
3747c478bd9Sstevel@tonic-gate key_usage = (toktype == KG_TOK_WRAP_MSG
3757c478bd9Sstevel@tonic-gate ? (!ctx->initiate
3767c478bd9Sstevel@tonic-gate ? KG_USAGE_INITIATOR_SEAL
3777c478bd9Sstevel@tonic-gate : KG_USAGE_ACCEPTOR_SEAL)
3787c478bd9Sstevel@tonic-gate : (!ctx->initiate
3797c478bd9Sstevel@tonic-gate ? KG_USAGE_INITIATOR_SIGN
3807c478bd9Sstevel@tonic-gate : KG_USAGE_ACCEPTOR_SIGN));
3817c478bd9Sstevel@tonic-gate
3827c478bd9Sstevel@tonic-gate /* Oops. I wrote this code assuming ptr would be at the start of
3837c478bd9Sstevel@tonic-gate the token header. */
3847c478bd9Sstevel@tonic-gate ptr -= 2;
3857c478bd9Sstevel@tonic-gate bodysize += 2;
3867c478bd9Sstevel@tonic-gate
3877c478bd9Sstevel@tonic-gate if (bodysize < 16) {
3887c478bd9Sstevel@tonic-gate defective:
3897c478bd9Sstevel@tonic-gate *minor_status = 0;
3907c478bd9Sstevel@tonic-gate return GSS_S_DEFECTIVE_TOKEN;
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate if ((ptr[2] & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
3937c478bd9Sstevel@tonic-gate *minor_status = (OM_uint32)G_BAD_DIRECTION;
3947c478bd9Sstevel@tonic-gate return GSS_S_BAD_SIG;
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate /* Two things to note here.
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate First, we can't really enforce the use of the acceptor's subkey,
4007c478bd9Sstevel@tonic-gate if we're the acceptor; the initiator may have sent messages
4017c478bd9Sstevel@tonic-gate before getting the subkey. We could probably enforce it if
4027c478bd9Sstevel@tonic-gate we're the initiator.
4037c478bd9Sstevel@tonic-gate
4047c478bd9Sstevel@tonic-gate Second, if someone tweaks the code to not set the flag telling
4057c478bd9Sstevel@tonic-gate the krb5 library to generate a new subkey in the AP-REP
4067c478bd9Sstevel@tonic-gate message, the MIT library may include a subkey anyways --
4077c478bd9Sstevel@tonic-gate namely, a copy of the AP-REQ subkey, if it was provided. So
4087c478bd9Sstevel@tonic-gate the initiator may think we wanted a subkey, and set the flag,
4097c478bd9Sstevel@tonic-gate even though we weren't trying to set the subkey. The "other"
410159d09a2SMark Phalan key, the one not asserted by the acceptor, will have the same
4117c478bd9Sstevel@tonic-gate value in that case, though, so we can just ignore the flag. */
4127c478bd9Sstevel@tonic-gate if (ctx->have_acceptor_subkey && (ptr[2] & FLAG_ACCEPTOR_SUBKEY)) {
4137c478bd9Sstevel@tonic-gate key = ctx->acceptor_subkey;
4147c478bd9Sstevel@tonic-gate } else {
4157c478bd9Sstevel@tonic-gate key = ctx->enc;
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate #ifdef _KERNEL
4197c478bd9Sstevel@tonic-gate context->kef_cipher_mt = get_cipher_mech_type(context, key);
4207c478bd9Sstevel@tonic-gate context->kef_hash_mt = get_hash_mech_type(context, key);
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate if ((err = init_key_kef(context->kef_cipher_mt, key))) {
4237c478bd9Sstevel@tonic-gate return (GSS_S_FAILURE);
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate if (toktype == KG_TOK_WRAP_MSG) {
4287c478bd9Sstevel@tonic-gate if (load_16_be(ptr) != 0x0504)
4297c478bd9Sstevel@tonic-gate goto defective;
4307c478bd9Sstevel@tonic-gate if (ptr[3] != 0xff)
4317c478bd9Sstevel@tonic-gate goto defective;
4327c478bd9Sstevel@tonic-gate ec = load_16_be(ptr+4);
4337c478bd9Sstevel@tonic-gate rrc = load_16_be(ptr+6);
4347c478bd9Sstevel@tonic-gate seqnum = load_64_be(ptr+8);
4357c478bd9Sstevel@tonic-gate if (!rotate_left(ptr+16, bodysize-16, rrc)) {
436159d09a2SMark Phalan no_mem:
4377c478bd9Sstevel@tonic-gate *minor_status = ENOMEM;
4387c478bd9Sstevel@tonic-gate return GSS_S_FAILURE;
4397c478bd9Sstevel@tonic-gate }
4407c478bd9Sstevel@tonic-gate if (ptr[2] & FLAG_WRAP_CONFIDENTIAL) {
4417c478bd9Sstevel@tonic-gate /* confidentiality */
4427c478bd9Sstevel@tonic-gate krb5_enc_data cipher;
4437c478bd9Sstevel@tonic-gate unsigned char *althdr;
4447c478bd9Sstevel@tonic-gate size_t plainlen;
4457c478bd9Sstevel@tonic-gate
4467c478bd9Sstevel@tonic-gate if (conf_state)
4477c478bd9Sstevel@tonic-gate *conf_state = 1;
4487c478bd9Sstevel@tonic-gate /* Do we have no decrypt_size function?
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate For all current cryptosystems, the ciphertext size will
4517c478bd9Sstevel@tonic-gate be larger than the plaintext size. */
4527c478bd9Sstevel@tonic-gate cipher.enctype = key->enctype;
4537c478bd9Sstevel@tonic-gate cipher.ciphertext.length = bodysize - 16;
4547c478bd9Sstevel@tonic-gate cipher.ciphertext.data = (char *)ptr + 16;
4557c478bd9Sstevel@tonic-gate plain.length = plainlen = bodysize - 16;
4567c478bd9Sstevel@tonic-gate plain.data = MALLOC(plain.length);
4577c478bd9Sstevel@tonic-gate if (plain.data == NULL)
4587c478bd9Sstevel@tonic-gate goto no_mem;
4597c478bd9Sstevel@tonic-gate err = krb5_c_decrypt(context, key, key_usage, 0,
4607c478bd9Sstevel@tonic-gate &cipher, &plain);
4617c478bd9Sstevel@tonic-gate if (err) {
4627c478bd9Sstevel@tonic-gate goto error;
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate /* Don't use bodysize here! Use the fact that
4657c478bd9Sstevel@tonic-gate plain.length has been adjusted to the
4667c478bd9Sstevel@tonic-gate correct length. */
4677c478bd9Sstevel@tonic-gate althdr = (uchar_t *)plain.data + plain.length - 16;
4687c478bd9Sstevel@tonic-gate if (load_16_be(althdr) != 0x0504
4697c478bd9Sstevel@tonic-gate || althdr[2] != ptr[2]
4707c478bd9Sstevel@tonic-gate || althdr[3] != ptr[3]
4717c478bd9Sstevel@tonic-gate || memcmp(althdr+8, ptr+8, 8)) {
4727c478bd9Sstevel@tonic-gate FREE(plain.data, plainlen);
4737c478bd9Sstevel@tonic-gate goto defective;
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate message_buffer->length = plain.length - ec - 16;
4767c478bd9Sstevel@tonic-gate message_buffer->value = MALLOC(message_buffer->length);
4777c478bd9Sstevel@tonic-gate if (message_buffer->value == NULL) {
4787c478bd9Sstevel@tonic-gate FREE(plain.data, plainlen);
4797c478bd9Sstevel@tonic-gate goto no_mem;
4807c478bd9Sstevel@tonic-gate }
4817c478bd9Sstevel@tonic-gate (void) memcpy(message_buffer->value, plain.data,
4827c478bd9Sstevel@tonic-gate message_buffer->length);
4837c478bd9Sstevel@tonic-gate FREE(plain.data, plainlen);
4847c478bd9Sstevel@tonic-gate } else {
4857c478bd9Sstevel@tonic-gate /* no confidentiality */
4867c478bd9Sstevel@tonic-gate if (conf_state)
4877c478bd9Sstevel@tonic-gate *conf_state = 0;
4887c478bd9Sstevel@tonic-gate if (ec + 16 < ec)
4897c478bd9Sstevel@tonic-gate /* overflow check */
4907c478bd9Sstevel@tonic-gate goto defective;
4917c478bd9Sstevel@tonic-gate if (ec + 16 > bodysize)
4927c478bd9Sstevel@tonic-gate goto defective;
4937c478bd9Sstevel@tonic-gate /* We have: header | msg | cksum.
4947c478bd9Sstevel@tonic-gate We need cksum(msg | header).
4957c478bd9Sstevel@tonic-gate Rotate the first two. */
4967c478bd9Sstevel@tonic-gate store_16_be(0, ptr+4);
4977c478bd9Sstevel@tonic-gate store_16_be(0, ptr+6);
498159d09a2SMark Phalan plain.length = bodysize-ec;
4997c478bd9Sstevel@tonic-gate plain.data = (char *)ptr;
5007c478bd9Sstevel@tonic-gate if (!rotate_left(ptr, bodysize-ec, 16))
5017c478bd9Sstevel@tonic-gate goto no_mem;
5027c478bd9Sstevel@tonic-gate sum.length = ec;
5037c478bd9Sstevel@tonic-gate if (sum.length != ctx->cksum_size) {
5047c478bd9Sstevel@tonic-gate *minor_status = 0;
5057c478bd9Sstevel@tonic-gate return GSS_S_BAD_SIG;
5067c478bd9Sstevel@tonic-gate }
5077c478bd9Sstevel@tonic-gate sum.contents = ptr+bodysize-ec;
5087c478bd9Sstevel@tonic-gate sum.checksum_type = ctx->cksumtype;
5097c478bd9Sstevel@tonic-gate err = krb5_c_verify_checksum(context, key, key_usage,
5107c478bd9Sstevel@tonic-gate &plain, &sum, &valid);
5117c478bd9Sstevel@tonic-gate if (err) {
5127c478bd9Sstevel@tonic-gate *minor_status = err;
5137c478bd9Sstevel@tonic-gate return GSS_S_BAD_SIG;
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate if (!valid) {
5167c478bd9Sstevel@tonic-gate *minor_status = 0;
5177c478bd9Sstevel@tonic-gate return GSS_S_BAD_SIG;
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate message_buffer->length = plain.length - 16;
5207c478bd9Sstevel@tonic-gate message_buffer->value = MALLOC(message_buffer->length);
5217c478bd9Sstevel@tonic-gate if (message_buffer->value == NULL)
5227c478bd9Sstevel@tonic-gate goto no_mem;
5237c478bd9Sstevel@tonic-gate (void) memcpy(message_buffer->value,
5247c478bd9Sstevel@tonic-gate plain.data, message_buffer->length);
5253dba6097Smp
5263dba6097Smp /*
5273dba6097Smp * Solaris Kerberos: Restore the original token.
5283dba6097Smp * This allows the token to be detected as a duplicate if it
5293dba6097Smp * is passed in to gss_unwrap() again.
5303dba6097Smp */
5313dba6097Smp if (!rotate_left(ptr, bodysize-ec, bodysize - ec - 16))
5323dba6097Smp goto no_mem;
5333dba6097Smp store_16_be(ec, ptr+4);
5343dba6097Smp store_16_be(rrc, ptr+6);
5357c478bd9Sstevel@tonic-gate }
5367c478bd9Sstevel@tonic-gate err = g_order_check(&ctx->seqstate, seqnum);
5377c478bd9Sstevel@tonic-gate *minor_status = 0;
5387c478bd9Sstevel@tonic-gate return err;
5397c478bd9Sstevel@tonic-gate } else if (toktype == KG_TOK_MIC_MSG) {
5407c478bd9Sstevel@tonic-gate /* wrap token, no confidentiality */
5417c478bd9Sstevel@tonic-gate if (load_16_be(ptr) != 0x0404)
5427c478bd9Sstevel@tonic-gate goto defective;
5437c478bd9Sstevel@tonic-gate verify_mic_1:
5447c478bd9Sstevel@tonic-gate if (ptr[3] != 0xff)
5457c478bd9Sstevel@tonic-gate goto defective;
5467c478bd9Sstevel@tonic-gate if (load_32_be(ptr+4) != (ulong_t)0xffffffffU)
5477c478bd9Sstevel@tonic-gate goto defective;
5487c478bd9Sstevel@tonic-gate seqnum = load_64_be(ptr+8);
5497c478bd9Sstevel@tonic-gate plain.length = message_buffer->length + 16;
5507c478bd9Sstevel@tonic-gate plain.data = MALLOC(plain.length);
5517c478bd9Sstevel@tonic-gate if (plain.data == NULL)
5527c478bd9Sstevel@tonic-gate goto no_mem;
5537c478bd9Sstevel@tonic-gate if (message_buffer->length)
5547c478bd9Sstevel@tonic-gate (void) memcpy(plain.data,
5557c478bd9Sstevel@tonic-gate message_buffer->value, message_buffer->length);
5567c478bd9Sstevel@tonic-gate (void) memcpy(plain.data + message_buffer->length, ptr, 16);
5577c478bd9Sstevel@tonic-gate sum.length = bodysize - 16;
5587c478bd9Sstevel@tonic-gate sum.contents = ptr + 16;
5597c478bd9Sstevel@tonic-gate sum.checksum_type = ctx->cksumtype;
5607c478bd9Sstevel@tonic-gate err = krb5_c_verify_checksum(context, key, key_usage,
5617c478bd9Sstevel@tonic-gate &plain, &sum, &valid);
5627c478bd9Sstevel@tonic-gate if (err) {
563159d09a2SMark Phalan error:
5647c478bd9Sstevel@tonic-gate FREE(plain.data, plain.length);
5657c478bd9Sstevel@tonic-gate *minor_status = err;
5665e01956fSGlenn Barry save_error_info(*minor_status, context);
5677c478bd9Sstevel@tonic-gate return GSS_S_BAD_SIG; /* XXX */
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate FREE(plain.data, plain.length);
5707c478bd9Sstevel@tonic-gate if (!valid) {
5717c478bd9Sstevel@tonic-gate *minor_status = 0;
5727c478bd9Sstevel@tonic-gate return GSS_S_BAD_SIG;
5737c478bd9Sstevel@tonic-gate }
5747c478bd9Sstevel@tonic-gate err = g_order_check(&ctx->seqstate, seqnum);
5757c478bd9Sstevel@tonic-gate *minor_status = 0;
5767c478bd9Sstevel@tonic-gate return err;
5777c478bd9Sstevel@tonic-gate } else if (toktype == KG_TOK_DEL_CTX) {
5787c478bd9Sstevel@tonic-gate if (load_16_be(ptr) != 0x0405)
5797c478bd9Sstevel@tonic-gate goto defective;
5807c478bd9Sstevel@tonic-gate message_buffer = (gss_buffer_t)&empty_message;
5817c478bd9Sstevel@tonic-gate goto verify_mic_1;
5827c478bd9Sstevel@tonic-gate } else {
5837c478bd9Sstevel@tonic-gate goto defective;
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate }
586