10Sstevel@tonic-gate /*
2*13132SGlenn.Barry@oracle.com * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
30Sstevel@tonic-gate */
40Sstevel@tonic-gate /*
50Sstevel@tonic-gate * lib/gssapi/krb5/k5sealv3.c
60Sstevel@tonic-gate *
70Sstevel@tonic-gate * Copyright 2003,2004 by the Massachusetts Institute of Technology.
80Sstevel@tonic-gate * All Rights Reserved.
90Sstevel@tonic-gate *
100Sstevel@tonic-gate * Export of this software from the United States of America may
110Sstevel@tonic-gate * require a specific license from the United States Government.
120Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating
130Sstevel@tonic-gate * export to obtain such a license before exporting.
147934SMark.Phalan@Sun.COM *
150Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
160Sstevel@tonic-gate * distribute this software and its documentation for any purpose and
170Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright
180Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and
190Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that
200Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining
210Sstevel@tonic-gate * to distribution of the software without specific, written prior
227934SMark.Phalan@Sun.COM * permission. Furthermore if you modify this software you must label
230Sstevel@tonic-gate * your software as modified software and not distribute it in such a
240Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software.
250Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of
260Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express
270Sstevel@tonic-gate * or implied warranty.
287934SMark.Phalan@Sun.COM *
290Sstevel@tonic-gate *
300Sstevel@tonic-gate */
310Sstevel@tonic-gate /* draft-ietf-krb-wg-gssapi-cfx-05 */
320Sstevel@tonic-gate
330Sstevel@tonic-gate #ifndef _KERNEL
340Sstevel@tonic-gate #include <assert.h>
350Sstevel@tonic-gate #include <stdarg.h>
360Sstevel@tonic-gate
370Sstevel@tonic-gate #define ASSERT assert
380Sstevel@tonic-gate #endif
390Sstevel@tonic-gate
407934SMark.Phalan@Sun.COM /* Solaris Kerberos */
417934SMark.Phalan@Sun.COM #include "k5-int.h" /* for zap() */
427934SMark.Phalan@Sun.COM #include "k5-platform.h"
437934SMark.Phalan@Sun.COM
447934SMark.Phalan@Sun.COM /* Solaris Kerberos */
457934SMark.Phalan@Sun.COM #include "k5-platform-store_16.h"
467934SMark.Phalan@Sun.COM #include "k5-platform-store_64.h"
477934SMark.Phalan@Sun.COM #include "k5-platform-load_16.h"
487934SMark.Phalan@Sun.COM #include "k5-platform-load_64.h"
497934SMark.Phalan@Sun.COM
507934SMark.Phalan@Sun.COM #include "gssapiP_krb5.h"
510Sstevel@tonic-gate #include <sys/int_limits.h>
520Sstevel@tonic-gate
530Sstevel@tonic-gate static int
rotate_left(void * ptr,size_t bufsiz,size_t rc)540Sstevel@tonic-gate rotate_left (void *ptr, size_t bufsiz, size_t rc)
550Sstevel@tonic-gate {
560Sstevel@tonic-gate /* Optimize for receiving. After some debugging is done, the MIT
570Sstevel@tonic-gate implementation won't do any rotates on sending, and while
580Sstevel@tonic-gate debugging, they'll be randomly chosen.
590Sstevel@tonic-gate
600Sstevel@tonic-gate Return 1 for success, 0 for failure (ENOMEM). */
610Sstevel@tonic-gate void *tbuf;
620Sstevel@tonic-gate
630Sstevel@tonic-gate if (bufsiz == 0)
640Sstevel@tonic-gate return 1;
650Sstevel@tonic-gate rc = rc % bufsiz;
660Sstevel@tonic-gate if (rc == 0)
670Sstevel@tonic-gate return 1;
680Sstevel@tonic-gate
690Sstevel@tonic-gate tbuf = MALLOC(rc);
700Sstevel@tonic-gate if (tbuf == 0)
710Sstevel@tonic-gate return 0;
720Sstevel@tonic-gate (void) memcpy(tbuf, ptr, rc);
730Sstevel@tonic-gate (void) memmove(ptr, (char *)ptr + rc, bufsiz - rc);
740Sstevel@tonic-gate (void) memcpy((char *)ptr + bufsiz - rc, tbuf, rc);
750Sstevel@tonic-gate FREE(tbuf, rc);
760Sstevel@tonic-gate return 1;
770Sstevel@tonic-gate }
780Sstevel@tonic-gate
790Sstevel@tonic-gate static const gss_buffer_desc empty_message = { 0, 0 };
800Sstevel@tonic-gate
810Sstevel@tonic-gate #define FLAG_SENDER_IS_ACCEPTOR 0x01
820Sstevel@tonic-gate #define FLAG_WRAP_CONFIDENTIAL 0x02
830Sstevel@tonic-gate #define FLAG_ACCEPTOR_SUBKEY 0x04
840Sstevel@tonic-gate
850Sstevel@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)860Sstevel@tonic-gate gss_krb5int_make_seal_token_v3 (krb5_context context,
870Sstevel@tonic-gate krb5_gss_ctx_id_rec *ctx,
880Sstevel@tonic-gate const gss_buffer_desc * message,
890Sstevel@tonic-gate gss_buffer_t token,
900Sstevel@tonic-gate int conf_req_flag, int toktype)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate size_t bufsize = 16;
930Sstevel@tonic-gate unsigned char *outbuf = 0;
940Sstevel@tonic-gate krb5_error_code err;
950Sstevel@tonic-gate int key_usage;
960Sstevel@tonic-gate unsigned char acceptor_flag;
970Sstevel@tonic-gate const gss_buffer_desc *message2 = message;
985053Sgtb #ifdef CFX_EXERCISE
995053Sgtb size_t rrc;
1005053Sgtb #endif
1010Sstevel@tonic-gate size_t ec;
1020Sstevel@tonic-gate unsigned short tok_id;
1030Sstevel@tonic-gate krb5_checksum sum;
1040Sstevel@tonic-gate krb5_keyblock *key;
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate ASSERT(toktype != KG_TOK_SEAL_MSG || ctx->enc != 0);
1070Sstevel@tonic-gate ASSERT(ctx->big_endian == 0);
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
1100Sstevel@tonic-gate key_usage = (toktype == KG_TOK_WRAP_MSG
1110Sstevel@tonic-gate ? (ctx->initiate
1120Sstevel@tonic-gate ? KG_USAGE_INITIATOR_SEAL
1130Sstevel@tonic-gate : KG_USAGE_ACCEPTOR_SEAL)
1140Sstevel@tonic-gate : (ctx->initiate
1150Sstevel@tonic-gate ? KG_USAGE_INITIATOR_SIGN
1160Sstevel@tonic-gate : KG_USAGE_ACCEPTOR_SIGN));
1170Sstevel@tonic-gate if (ctx->have_acceptor_subkey) {
1180Sstevel@tonic-gate key = ctx->acceptor_subkey;
1190Sstevel@tonic-gate } else {
1200Sstevel@tonic-gate key = ctx->enc;
1210Sstevel@tonic-gate }
1220Sstevel@tonic-gate
1230Sstevel@tonic-gate #ifdef _KERNEL
1240Sstevel@tonic-gate context->kef_cipher_mt = get_cipher_mech_type(context, key);
1250Sstevel@tonic-gate context->kef_hash_mt = get_hash_mech_type(context, key);
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate if ((err = init_key_kef(context->kef_cipher_mt, key))) {
1280Sstevel@tonic-gate return (GSS_S_FAILURE);
1290Sstevel@tonic-gate }
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate #endif /* _KERNEL */
1320Sstevel@tonic-gate
1330Sstevel@tonic-gate #ifdef CFX_EXERCISE
1340Sstevel@tonic-gate {
1350Sstevel@tonic-gate static int initialized = 0;
1360Sstevel@tonic-gate if (!initialized) {
1370Sstevel@tonic-gate srand(time(0));
1380Sstevel@tonic-gate initialized = 1;
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate }
1410Sstevel@tonic-gate #endif
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
1440Sstevel@tonic-gate krb5_data plain;
1450Sstevel@tonic-gate krb5_enc_data cipher;
1460Sstevel@tonic-gate size_t ec_max;
1470Sstevel@tonic-gate size_t tlen;
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate /* 300: Adds some slop. */
1500Sstevel@tonic-gate if (SIZE_MAX - 300 < message->length)
1510Sstevel@tonic-gate return ENOMEM;
1520Sstevel@tonic-gate ec_max = SIZE_MAX - message->length - 300;
1530Sstevel@tonic-gate if (ec_max > 0xffff)
1540Sstevel@tonic-gate ec_max = 0xffff;
1550Sstevel@tonic-gate /*
1560Sstevel@tonic-gate * EC should really be a multiple (1) of the number of octets that
1570Sstevel@tonic-gate * the cryptosystem would pad by if we didn't have the filler.
1580Sstevel@tonic-gate *
1590Sstevel@tonic-gate * For AES-CTS this will always be 0 and we expect no further
1600Sstevel@tonic-gate * enctypes, so there should be no issue here.
1610Sstevel@tonic-gate */
1620Sstevel@tonic-gate ec = 0;
1630Sstevel@tonic-gate plain.length = message->length + 16 + ec;
1640Sstevel@tonic-gate plain.data = MALLOC(plain.length);
1650Sstevel@tonic-gate if (plain.data == NULL)
1660Sstevel@tonic-gate return ENOMEM;
1670Sstevel@tonic-gate
1680Sstevel@tonic-gate /* Get size of ciphertext. */
1690Sstevel@tonic-gate if ((err = krb5_c_encrypt_length(context,
1700Sstevel@tonic-gate ctx->enc->enctype, plain.length, &tlen))) {
1710Sstevel@tonic-gate FREE(plain.data, plain.length);
1720Sstevel@tonic-gate return (err);
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate bufsize = 16 + tlen;
1760Sstevel@tonic-gate /* Allocate space for header plus encrypted data. */
1770Sstevel@tonic-gate outbuf = MALLOC(bufsize);
1780Sstevel@tonic-gate if (outbuf == NULL) {
1790Sstevel@tonic-gate FREE(plain.data, plain.length);
1800Sstevel@tonic-gate return ENOMEM;
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate /* TOK_ID */
1840Sstevel@tonic-gate store_16_be(0x0504, outbuf);
1850Sstevel@tonic-gate /* flags */
1860Sstevel@tonic-gate outbuf[2] = (acceptor_flag
1870Sstevel@tonic-gate | (conf_req_flag ? FLAG_WRAP_CONFIDENTIAL : 0)
1880Sstevel@tonic-gate | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
1890Sstevel@tonic-gate /* filler */
1900Sstevel@tonic-gate outbuf[3] = 0xff;
1910Sstevel@tonic-gate /* EC */
1920Sstevel@tonic-gate store_16_be(ec, outbuf+4);
1930Sstevel@tonic-gate /* RRC */
1940Sstevel@tonic-gate store_16_be(0, outbuf+6);
1950Sstevel@tonic-gate store_64_be(ctx->seq_send, outbuf+8);
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate (void) memcpy(plain.data, message->value, message->length);
1980Sstevel@tonic-gate (void) memset(plain.data + message->length, 'x', ec);
1990Sstevel@tonic-gate (void) memcpy(plain.data + message->length + ec, outbuf, 16);
2000Sstevel@tonic-gate
2010Sstevel@tonic-gate /* Should really use scatter/gather crypto interfaces */
2020Sstevel@tonic-gate cipher.ciphertext.data = (char *)outbuf + 16;
2030Sstevel@tonic-gate cipher.ciphertext.length = bufsize - 16;
2040Sstevel@tonic-gate cipher.enctype = key->enctype;
2050Sstevel@tonic-gate err = krb5_c_encrypt(context, key, key_usage, 0, &plain, &cipher);
2060Sstevel@tonic-gate (void) bzero(plain.data, plain.length);
2070Sstevel@tonic-gate FREE(plain.data, plain.length);
2080Sstevel@tonic-gate plain.data = 0;
2090Sstevel@tonic-gate if (err)
2100Sstevel@tonic-gate goto error;
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate /* Now that we know we're returning a valid token.... */
2130Sstevel@tonic-gate ctx->seq_send++;
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate #ifdef CFX_EXERCISE
2160Sstevel@tonic-gate rrc = rand() & 0xffff;
2170Sstevel@tonic-gate if (rotate_left(outbuf+16, bufsize-16,
2180Sstevel@tonic-gate (bufsize-16) - (rrc % (bufsize - 16))))
2190Sstevel@tonic-gate store_16_be(rrc, outbuf+6);
2200Sstevel@tonic-gate /* If the rotate fails, don't worry about it. */
2210Sstevel@tonic-gate #endif
2220Sstevel@tonic-gate } else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) {
2230Sstevel@tonic-gate krb5_data plain;
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate /* Here, message is the application-supplied data; message2 is
2260Sstevel@tonic-gate what goes into the output token. They may be the same, or
2270Sstevel@tonic-gate message2 may be empty (for MIC). */
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate tok_id = 0x0504;
2300Sstevel@tonic-gate
2310Sstevel@tonic-gate wrap_with_checksum:
2320Sstevel@tonic-gate plain.length = message->length + 16;
2330Sstevel@tonic-gate plain.data = MALLOC(message->length + 16);
2340Sstevel@tonic-gate if (plain.data == NULL)
2350Sstevel@tonic-gate return ENOMEM;
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate if (ctx->cksum_size > 0xffff) {
2380Sstevel@tonic-gate FREE(plain.data, plain.length);
2390Sstevel@tonic-gate return EINVAL;
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate bufsize = 16 + message2->length + ctx->cksum_size;
2430Sstevel@tonic-gate outbuf = MALLOC(bufsize);
2440Sstevel@tonic-gate if (outbuf == NULL) {
2450Sstevel@tonic-gate FREE(plain.data, plain.length);
2460Sstevel@tonic-gate plain.data = 0;
2470Sstevel@tonic-gate err = ENOMEM;
2480Sstevel@tonic-gate goto error;
2490Sstevel@tonic-gate }
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate /* TOK_ID */
2520Sstevel@tonic-gate store_16_be(tok_id, outbuf);
2530Sstevel@tonic-gate /* flags */
2540Sstevel@tonic-gate outbuf[2] = (acceptor_flag
2550Sstevel@tonic-gate | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
2560Sstevel@tonic-gate /* filler */
2570Sstevel@tonic-gate outbuf[3] = 0xff;
2580Sstevel@tonic-gate if (toktype == KG_TOK_WRAP_MSG) {
2590Sstevel@tonic-gate /* Use 0 for checksum calculation, substitute
2600Sstevel@tonic-gate checksum length later. */
2610Sstevel@tonic-gate /* EC */
2620Sstevel@tonic-gate store_16_be(0, outbuf+4);
2630Sstevel@tonic-gate /* RRC */
2640Sstevel@tonic-gate store_16_be(0, outbuf+6);
2650Sstevel@tonic-gate } else {
2660Sstevel@tonic-gate /* MIC and DEL store 0xFF in EC and RRC. */
2670Sstevel@tonic-gate store_16_be(0xffff, outbuf+4);
2680Sstevel@tonic-gate store_16_be(0xffff, outbuf+6);
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate store_64_be(ctx->seq_send, outbuf+8);
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate (void) memcpy(plain.data, message->value, message->length);
2730Sstevel@tonic-gate (void) memcpy(plain.data + message->length, outbuf, 16);
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate /* Fill in the output token -- data contents, if any, and
2760Sstevel@tonic-gate space for the checksum. */
2770Sstevel@tonic-gate if (message2->length)
2780Sstevel@tonic-gate (void) memcpy(outbuf + 16, message2->value, message2->length);
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate sum.contents = outbuf + 16 + message2->length;
2810Sstevel@tonic-gate sum.length = ctx->cksum_size;
2820Sstevel@tonic-gate
2830Sstevel@tonic-gate err = krb5_c_make_checksum(context, ctx->cksumtype, key,
2840Sstevel@tonic-gate key_usage, &plain, &sum);
2850Sstevel@tonic-gate bzero(plain.data, plain.length);
2860Sstevel@tonic-gate FREE(plain.data, plain.length);
2870Sstevel@tonic-gate plain.data = 0;
2880Sstevel@tonic-gate if (err) {
2890Sstevel@tonic-gate bzero(outbuf,bufsize);
2900Sstevel@tonic-gate err = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2910Sstevel@tonic-gate goto error;
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate if (sum.length != ctx->cksum_size) {
2940Sstevel@tonic-gate err = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2950Sstevel@tonic-gate goto error;
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate (void) memcpy(outbuf + 16 + message2->length, sum.contents,
2980Sstevel@tonic-gate ctx->cksum_size);
2990Sstevel@tonic-gate krb5_free_checksum_contents(context, &sum);
3000Sstevel@tonic-gate sum.contents = 0;
3010Sstevel@tonic-gate /* Now that we know we're actually generating the token... */
3020Sstevel@tonic-gate ctx->seq_send++;
3030Sstevel@tonic-gate
3040Sstevel@tonic-gate if (toktype == KG_TOK_WRAP_MSG) {
3050Sstevel@tonic-gate #ifdef CFX_EXERCISE
3060Sstevel@tonic-gate rrc = rand() & 0xffff;
3070Sstevel@tonic-gate /* If the rotate fails, don't worry about it. */
3080Sstevel@tonic-gate if (rotate_left(outbuf+16, bufsize-16,
3090Sstevel@tonic-gate (bufsize-16) - (rrc % (bufsize - 16))))
3100Sstevel@tonic-gate store_16_be(rrc, outbuf+6);
3110Sstevel@tonic-gate #endif
3120Sstevel@tonic-gate /* Fix up EC field. */
3130Sstevel@tonic-gate store_16_be(ctx->cksum_size, outbuf+4);
3140Sstevel@tonic-gate } else {
3150Sstevel@tonic-gate store_16_be(0xffff, outbuf+6);
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate } else if (toktype == KG_TOK_MIC_MSG) {
3180Sstevel@tonic-gate tok_id = 0x0404;
3190Sstevel@tonic-gate message2 = &empty_message;
3200Sstevel@tonic-gate goto wrap_with_checksum;
3210Sstevel@tonic-gate } else if (toktype == KG_TOK_DEL_CTX) {
3223376Smp153739 /*
3233376Smp153739 * Solaris Kerberos:
3243376Smp153739 * No token should be generated for context deletion. Just
3253376Smp153739 * return.
3263376Smp153739 */
3273376Smp153739 return 0;
3280Sstevel@tonic-gate } else {
3290Sstevel@tonic-gate err = KRB5KRB_AP_ERR_BAD_INTEGRITY;
3300Sstevel@tonic-gate goto error;
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate token->value = outbuf;
3340Sstevel@tonic-gate token->length = bufsize;
3350Sstevel@tonic-gate return 0;
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate error:
3380Sstevel@tonic-gate FREE(outbuf, bufsize);
3390Sstevel@tonic-gate token->value = NULL;
3400Sstevel@tonic-gate token->length = 0;
3410Sstevel@tonic-gate return err;
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate /* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
3450Sstevel@tonic-gate conf_state is only valid if SEAL. */
3460Sstevel@tonic-gate
3470Sstevel@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)3487934SMark.Phalan@Sun.COM gss_krb5int_unseal_token_v3(krb5_context *contextptr,
3490Sstevel@tonic-gate OM_uint32 *minor_status,
3500Sstevel@tonic-gate krb5_gss_ctx_id_rec *ctx,
3510Sstevel@tonic-gate unsigned char *ptr, int bodysize,
3520Sstevel@tonic-gate gss_buffer_t message_buffer,
3530Sstevel@tonic-gate int *conf_state, int *qop_state, int toktype)
3540Sstevel@tonic-gate {
3557934SMark.Phalan@Sun.COM krb5_context context = *contextptr;
3560Sstevel@tonic-gate krb5_data plain;
3570Sstevel@tonic-gate gssint_uint64 seqnum;
3580Sstevel@tonic-gate size_t ec, rrc;
3590Sstevel@tonic-gate int key_usage;
3600Sstevel@tonic-gate unsigned char acceptor_flag;
3610Sstevel@tonic-gate krb5_checksum sum;
3620Sstevel@tonic-gate krb5_error_code err;
3630Sstevel@tonic-gate krb5_boolean valid;
3640Sstevel@tonic-gate krb5_keyblock *key;
3650Sstevel@tonic-gate
3660Sstevel@tonic-gate ASSERT(toktype != KG_TOK_SEAL_MSG || ctx->enc != 0);
3670Sstevel@tonic-gate ASSERT(ctx->big_endian == 0);
3680Sstevel@tonic-gate ASSERT(ctx->proto == 1);
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate if (qop_state)
3710Sstevel@tonic-gate *qop_state = GSS_C_QOP_DEFAULT;
3720Sstevel@tonic-gate
3730Sstevel@tonic-gate acceptor_flag = ctx->initiate ? FLAG_SENDER_IS_ACCEPTOR : 0;
3740Sstevel@tonic-gate key_usage = (toktype == KG_TOK_WRAP_MSG
3750Sstevel@tonic-gate ? (!ctx->initiate
3760Sstevel@tonic-gate ? KG_USAGE_INITIATOR_SEAL
3770Sstevel@tonic-gate : KG_USAGE_ACCEPTOR_SEAL)
3780Sstevel@tonic-gate : (!ctx->initiate
3790Sstevel@tonic-gate ? KG_USAGE_INITIATOR_SIGN
3800Sstevel@tonic-gate : KG_USAGE_ACCEPTOR_SIGN));
3810Sstevel@tonic-gate
3820Sstevel@tonic-gate /* Oops. I wrote this code assuming ptr would be at the start of
3830Sstevel@tonic-gate the token header. */
3840Sstevel@tonic-gate ptr -= 2;
3850Sstevel@tonic-gate bodysize += 2;
3860Sstevel@tonic-gate
3870Sstevel@tonic-gate if (bodysize < 16) {
3880Sstevel@tonic-gate defective:
3890Sstevel@tonic-gate *minor_status = 0;
3900Sstevel@tonic-gate return GSS_S_DEFECTIVE_TOKEN;
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate if ((ptr[2] & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
3930Sstevel@tonic-gate *minor_status = (OM_uint32)G_BAD_DIRECTION;
3940Sstevel@tonic-gate return GSS_S_BAD_SIG;
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate /* Two things to note here.
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate First, we can't really enforce the use of the acceptor's subkey,
4000Sstevel@tonic-gate if we're the acceptor; the initiator may have sent messages
4010Sstevel@tonic-gate before getting the subkey. We could probably enforce it if
4020Sstevel@tonic-gate we're the initiator.
4030Sstevel@tonic-gate
4040Sstevel@tonic-gate Second, if someone tweaks the code to not set the flag telling
4050Sstevel@tonic-gate the krb5 library to generate a new subkey in the AP-REP
4060Sstevel@tonic-gate message, the MIT library may include a subkey anyways --
4070Sstevel@tonic-gate namely, a copy of the AP-REQ subkey, if it was provided. So
4080Sstevel@tonic-gate the initiator may think we wanted a subkey, and set the flag,
4090Sstevel@tonic-gate even though we weren't trying to set the subkey. The "other"
4107934SMark.Phalan@Sun.COM key, the one not asserted by the acceptor, will have the same
4110Sstevel@tonic-gate value in that case, though, so we can just ignore the flag. */
4120Sstevel@tonic-gate if (ctx->have_acceptor_subkey && (ptr[2] & FLAG_ACCEPTOR_SUBKEY)) {
4130Sstevel@tonic-gate key = ctx->acceptor_subkey;
4140Sstevel@tonic-gate } else {
4150Sstevel@tonic-gate key = ctx->enc;
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate
4180Sstevel@tonic-gate #ifdef _KERNEL
4190Sstevel@tonic-gate context->kef_cipher_mt = get_cipher_mech_type(context, key);
4200Sstevel@tonic-gate context->kef_hash_mt = get_hash_mech_type(context, key);
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate if ((err = init_key_kef(context->kef_cipher_mt, key))) {
4230Sstevel@tonic-gate return (GSS_S_FAILURE);
4240Sstevel@tonic-gate }
4250Sstevel@tonic-gate #endif /* _KERNEL */
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate if (toktype == KG_TOK_WRAP_MSG) {
4280Sstevel@tonic-gate if (load_16_be(ptr) != 0x0504)
4290Sstevel@tonic-gate goto defective;
4300Sstevel@tonic-gate if (ptr[3] != 0xff)
4310Sstevel@tonic-gate goto defective;
4320Sstevel@tonic-gate ec = load_16_be(ptr+4);
4330Sstevel@tonic-gate rrc = load_16_be(ptr+6);
4340Sstevel@tonic-gate seqnum = load_64_be(ptr+8);
4350Sstevel@tonic-gate if (!rotate_left(ptr+16, bodysize-16, rrc)) {
4367934SMark.Phalan@Sun.COM no_mem:
4370Sstevel@tonic-gate *minor_status = ENOMEM;
4380Sstevel@tonic-gate return GSS_S_FAILURE;
4390Sstevel@tonic-gate }
4400Sstevel@tonic-gate if (ptr[2] & FLAG_WRAP_CONFIDENTIAL) {
4410Sstevel@tonic-gate /* confidentiality */
4420Sstevel@tonic-gate krb5_enc_data cipher;
4430Sstevel@tonic-gate unsigned char *althdr;
4440Sstevel@tonic-gate size_t plainlen;
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate if (conf_state)
4470Sstevel@tonic-gate *conf_state = 1;
4480Sstevel@tonic-gate /* Do we have no decrypt_size function?
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate For all current cryptosystems, the ciphertext size will
4510Sstevel@tonic-gate be larger than the plaintext size. */
4520Sstevel@tonic-gate cipher.enctype = key->enctype;
4530Sstevel@tonic-gate cipher.ciphertext.length = bodysize - 16;
4540Sstevel@tonic-gate cipher.ciphertext.data = (char *)ptr + 16;
4550Sstevel@tonic-gate plain.length = plainlen = bodysize - 16;
4560Sstevel@tonic-gate plain.data = MALLOC(plain.length);
4570Sstevel@tonic-gate if (plain.data == NULL)
4580Sstevel@tonic-gate goto no_mem;
4590Sstevel@tonic-gate err = krb5_c_decrypt(context, key, key_usage, 0,
4600Sstevel@tonic-gate &cipher, &plain);
4610Sstevel@tonic-gate if (err) {
4620Sstevel@tonic-gate goto error;
4630Sstevel@tonic-gate }
4640Sstevel@tonic-gate /* Don't use bodysize here! Use the fact that
4650Sstevel@tonic-gate plain.length has been adjusted to the
4660Sstevel@tonic-gate correct length. */
4670Sstevel@tonic-gate althdr = (uchar_t *)plain.data + plain.length - 16;
4680Sstevel@tonic-gate if (load_16_be(althdr) != 0x0504
4690Sstevel@tonic-gate || althdr[2] != ptr[2]
4700Sstevel@tonic-gate || althdr[3] != ptr[3]
4710Sstevel@tonic-gate || memcmp(althdr+8, ptr+8, 8)) {
4720Sstevel@tonic-gate FREE(plain.data, plainlen);
4730Sstevel@tonic-gate goto defective;
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate message_buffer->length = plain.length - ec - 16;
4760Sstevel@tonic-gate message_buffer->value = MALLOC(message_buffer->length);
4770Sstevel@tonic-gate if (message_buffer->value == NULL) {
4780Sstevel@tonic-gate FREE(plain.data, plainlen);
4790Sstevel@tonic-gate goto no_mem;
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate (void) memcpy(message_buffer->value, plain.data,
4820Sstevel@tonic-gate message_buffer->length);
4830Sstevel@tonic-gate FREE(plain.data, plainlen);
4840Sstevel@tonic-gate } else {
4850Sstevel@tonic-gate /* no confidentiality */
4860Sstevel@tonic-gate if (conf_state)
4870Sstevel@tonic-gate *conf_state = 0;
4880Sstevel@tonic-gate if (ec + 16 < ec)
4890Sstevel@tonic-gate /* overflow check */
4900Sstevel@tonic-gate goto defective;
4910Sstevel@tonic-gate if (ec + 16 > bodysize)
4920Sstevel@tonic-gate goto defective;
4930Sstevel@tonic-gate /* We have: header | msg | cksum.
4940Sstevel@tonic-gate We need cksum(msg | header).
4950Sstevel@tonic-gate Rotate the first two. */
4960Sstevel@tonic-gate store_16_be(0, ptr+4);
4970Sstevel@tonic-gate store_16_be(0, ptr+6);
4987934SMark.Phalan@Sun.COM plain.length = bodysize-ec;
4990Sstevel@tonic-gate plain.data = (char *)ptr;
5000Sstevel@tonic-gate if (!rotate_left(ptr, bodysize-ec, 16))
5010Sstevel@tonic-gate goto no_mem;
5020Sstevel@tonic-gate sum.length = ec;
5030Sstevel@tonic-gate if (sum.length != ctx->cksum_size) {
5040Sstevel@tonic-gate *minor_status = 0;
5050Sstevel@tonic-gate return GSS_S_BAD_SIG;
5060Sstevel@tonic-gate }
5070Sstevel@tonic-gate sum.contents = ptr+bodysize-ec;
5080Sstevel@tonic-gate sum.checksum_type = ctx->cksumtype;
5090Sstevel@tonic-gate err = krb5_c_verify_checksum(context, key, key_usage,
5100Sstevel@tonic-gate &plain, &sum, &valid);
5110Sstevel@tonic-gate if (err) {
5120Sstevel@tonic-gate *minor_status = err;
5130Sstevel@tonic-gate return GSS_S_BAD_SIG;
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate if (!valid) {
5160Sstevel@tonic-gate *minor_status = 0;
5170Sstevel@tonic-gate return GSS_S_BAD_SIG;
5180Sstevel@tonic-gate }
5190Sstevel@tonic-gate message_buffer->length = plain.length - 16;
5200Sstevel@tonic-gate message_buffer->value = MALLOC(message_buffer->length);
5210Sstevel@tonic-gate if (message_buffer->value == NULL)
5220Sstevel@tonic-gate goto no_mem;
5230Sstevel@tonic-gate (void) memcpy(message_buffer->value,
5240Sstevel@tonic-gate plain.data, message_buffer->length);
5253376Smp153739
5263376Smp153739 /*
5273376Smp153739 * Solaris Kerberos: Restore the original token.
5283376Smp153739 * This allows the token to be detected as a duplicate if it
5293376Smp153739 * is passed in to gss_unwrap() again.
5303376Smp153739 */
5313376Smp153739 if (!rotate_left(ptr, bodysize-ec, bodysize - ec - 16))
5323376Smp153739 goto no_mem;
5333376Smp153739 store_16_be(ec, ptr+4);
5343376Smp153739 store_16_be(rrc, ptr+6);
5350Sstevel@tonic-gate }
5360Sstevel@tonic-gate err = g_order_check(&ctx->seqstate, seqnum);
5370Sstevel@tonic-gate *minor_status = 0;
5380Sstevel@tonic-gate return err;
5390Sstevel@tonic-gate } else if (toktype == KG_TOK_MIC_MSG) {
5400Sstevel@tonic-gate /* wrap token, no confidentiality */
5410Sstevel@tonic-gate if (load_16_be(ptr) != 0x0404)
5420Sstevel@tonic-gate goto defective;
5430Sstevel@tonic-gate verify_mic_1:
5440Sstevel@tonic-gate if (ptr[3] != 0xff)
5450Sstevel@tonic-gate goto defective;
5460Sstevel@tonic-gate if (load_32_be(ptr+4) != (ulong_t)0xffffffffU)
5470Sstevel@tonic-gate goto defective;
5480Sstevel@tonic-gate seqnum = load_64_be(ptr+8);
5490Sstevel@tonic-gate plain.length = message_buffer->length + 16;
5500Sstevel@tonic-gate plain.data = MALLOC(plain.length);
5510Sstevel@tonic-gate if (plain.data == NULL)
5520Sstevel@tonic-gate goto no_mem;
5530Sstevel@tonic-gate if (message_buffer->length)
5540Sstevel@tonic-gate (void) memcpy(plain.data,
5550Sstevel@tonic-gate message_buffer->value, message_buffer->length);
5560Sstevel@tonic-gate (void) memcpy(plain.data + message_buffer->length, ptr, 16);
5570Sstevel@tonic-gate sum.length = bodysize - 16;
5580Sstevel@tonic-gate sum.contents = ptr + 16;
5590Sstevel@tonic-gate sum.checksum_type = ctx->cksumtype;
5600Sstevel@tonic-gate err = krb5_c_verify_checksum(context, key, key_usage,
5610Sstevel@tonic-gate &plain, &sum, &valid);
5620Sstevel@tonic-gate if (err) {
5637934SMark.Phalan@Sun.COM error:
5640Sstevel@tonic-gate FREE(plain.data, plain.length);
5650Sstevel@tonic-gate *minor_status = err;
566*13132SGlenn.Barry@oracle.com save_error_info(*minor_status, context);
5670Sstevel@tonic-gate return GSS_S_BAD_SIG; /* XXX */
5680Sstevel@tonic-gate }
5690Sstevel@tonic-gate FREE(plain.data, plain.length);
5700Sstevel@tonic-gate if (!valid) {
5710Sstevel@tonic-gate *minor_status = 0;
5720Sstevel@tonic-gate return GSS_S_BAD_SIG;
5730Sstevel@tonic-gate }
5740Sstevel@tonic-gate err = g_order_check(&ctx->seqstate, seqnum);
5750Sstevel@tonic-gate *minor_status = 0;
5760Sstevel@tonic-gate return err;
5770Sstevel@tonic-gate } else if (toktype == KG_TOK_DEL_CTX) {
5780Sstevel@tonic-gate if (load_16_be(ptr) != 0x0405)
5790Sstevel@tonic-gate goto defective;
5800Sstevel@tonic-gate message_buffer = (gss_buffer_t)&empty_message;
5810Sstevel@tonic-gate goto verify_mic_1;
5820Sstevel@tonic-gate } else {
5830Sstevel@tonic-gate goto defective;
5840Sstevel@tonic-gate }
5850Sstevel@tonic-gate }
586