85
82
unsigned short tok_id;
87
84
krb5_keyblock *key;
85
krb5_cksumtype cksumtype;
89
assert(toktype != KG_TOK_SEAL_MSG || ctx->enc != 0);
90
87
assert(ctx->big_endian == 0);
92
89
acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
93
90
key_usage = (toktype == KG_TOK_WRAP_MSG
95
? KG_USAGE_INITIATOR_SEAL
96
: KG_USAGE_ACCEPTOR_SEAL)
98
? KG_USAGE_INITIATOR_SIGN
99
: KG_USAGE_ACCEPTOR_SIGN));
92
? KG_USAGE_INITIATOR_SEAL
93
: KG_USAGE_ACCEPTOR_SEAL)
95
? KG_USAGE_INITIATOR_SIGN
96
: KG_USAGE_ACCEPTOR_SIGN));
100
97
if (ctx->have_acceptor_subkey) {
101
key = ctx->acceptor_subkey;
98
key = ctx->acceptor_subkey;
99
cksumtype = ctx->acceptor_subkey_cksumtype;
102
cksumtype = ctx->cksumtype;
106
106
#ifdef CFX_EXERCISE
108
static int initialized = 0;
108
static int initialized = 0;
116
116
if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
118
krb5_enc_data cipher;
118
krb5_enc_data cipher;
121
/* 300: Adds some slop. */
122
if (SIZE_MAX - 300 < message->length)
124
ec_max = SIZE_MAX - message->length - 300;
121
/* 300: Adds some slop. */
122
if (SIZE_MAX - 300 < message->length)
124
ec_max = SIZE_MAX - message->length - 300;
127
127
#ifdef CFX_EXERCISE
128
/* For testing only. For performance, always set ec = 0. */
129
ec = ec_max & rand();
128
/* For testing only. For performance, always set ec = 0. */
129
ec = ec_max & rand();
133
plain.length = message->length + 16 + ec;
134
plain.data = malloc(message->length + 16 + ec);
135
if (plain.data == NULL)
138
/* Get size of ciphertext. */
139
bufsize = 16 + krb5_encrypt_size (plain.length, ctx->enc->enctype);
140
/* Allocate space for header plus encrypted data. */
141
outbuf = malloc(bufsize);
142
if (outbuf == NULL) {
148
store_16_be(0x0504, outbuf);
150
outbuf[2] = (acceptor_flag
151
| (conf_req_flag ? FLAG_WRAP_CONFIDENTIAL : 0)
152
| (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
156
store_16_be(ec, outbuf+4);
158
store_16_be(0, outbuf+6);
159
store_64_be(ctx->seq_send, outbuf+8);
161
memcpy(plain.data, message->value, message->length);
162
memset(plain.data + message->length, 'x', ec);
163
memcpy(plain.data + message->length + ec, outbuf, 16);
165
cipher.ciphertext.data = outbuf + 16;
166
cipher.ciphertext.length = bufsize - 16;
167
cipher.enctype = key->enctype;
168
err = krb5_c_encrypt(context, key, key_usage, 0, &plain, &cipher);
169
zap(plain.data, plain.length);
175
/* Now that we know we're returning a valid token.... */
133
plain.length = message->length + 16 + ec;
134
plain.data = malloc(message->length + 16 + ec);
135
if (plain.data == NULL)
138
/* Get size of ciphertext. */
139
bufsize = 16 + krb5_encrypt_size (plain.length, key->enctype);
140
/* Allocate space for header plus encrypted data. */
141
outbuf = malloc(bufsize);
142
if (outbuf == NULL) {
148
store_16_be(KG2_TOK_WRAP_MSG, outbuf);
150
outbuf[2] = (acceptor_flag
151
| (conf_req_flag ? FLAG_WRAP_CONFIDENTIAL : 0)
152
| (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
156
store_16_be(ec, outbuf+4);
158
store_16_be(0, outbuf+6);
159
store_64_be(ctx->seq_send, outbuf+8);
161
memcpy(plain.data, message->value, message->length);
162
memset(plain.data + message->length, 'x', ec);
163
memcpy(plain.data + message->length + ec, outbuf, 16);
165
cipher.ciphertext.data = (char *)outbuf + 16;
166
cipher.ciphertext.length = bufsize - 16;
167
cipher.enctype = key->enctype;
168
err = krb5_c_encrypt(context, key, key_usage, 0, &plain, &cipher);
169
zap(plain.data, plain.length);
175
/* Now that we know we're returning a valid token.... */
178
178
#ifdef CFX_EXERCISE
179
rrc = rand() & 0xffff;
180
if (rotate_left(outbuf+16, bufsize-16,
181
(bufsize-16) - (rrc % (bufsize - 16))))
182
store_16_be(rrc, outbuf+6);
183
/* If the rotate fails, don't worry about it. */
179
rrc = rand() & 0xffff;
180
if (gss_krb5int_rotate_left(outbuf+16, bufsize-16,
181
(bufsize-16) - (rrc % (bufsize - 16))))
182
store_16_be(rrc, outbuf+6);
183
/* If the rotate fails, don't worry about it. */
185
185
} else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) {
188
/* Here, message is the application-supplied data; message2 is
189
what goes into the output token. They may be the same, or
190
message2 may be empty (for MIC). */
189
/* Here, message is the application-supplied data; message2 is
190
what goes into the output token. They may be the same, or
191
message2 may be empty (for MIC). */
193
tok_id = KG2_TOK_WRAP_MSG;
194
195
wrap_with_checksum:
195
plain.length = message->length + 16;
196
plain.data = malloc(message->length + 16);
197
if (plain.data == NULL)
200
if (ctx->cksum_size > 0xffff)
203
bufsize = 16 + message2->length + ctx->cksum_size;
204
outbuf = malloc(bufsize);
205
if (outbuf == NULL) {
213
store_16_be(tok_id, outbuf);
215
outbuf[2] = (acceptor_flag
216
| (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
219
if (toktype == KG_TOK_WRAP_MSG) {
220
/* Use 0 for checksum calculation, substitute
221
checksum length later. */
223
store_16_be(0, outbuf+4);
225
store_16_be(0, outbuf+6);
227
/* MIC and DEL store 0xFF in EC and RRC. */
228
store_16_be(0xffff, outbuf+4);
229
store_16_be(0xffff, outbuf+6);
231
store_64_be(ctx->seq_send, outbuf+8);
233
memcpy(plain.data, message->value, message->length);
234
memcpy(plain.data + message->length, outbuf, 16);
236
/* Fill in the output token -- data contents, if any, and
237
space for the checksum. */
238
if (message2->length)
239
memcpy(outbuf + 16, message2->value, message2->length);
241
sum.contents = outbuf + 16 + message2->length;
242
sum.length = ctx->cksum_size;
244
err = krb5_c_make_checksum(context, ctx->cksumtype, key,
245
key_usage, &plain, &sum);
246
zap(plain.data, plain.length);
254
if (sum.length != ctx->cksum_size)
256
memcpy(outbuf + 16 + message2->length, sum.contents, ctx->cksum_size);
257
krb5_free_checksum_contents(context, &sum);
259
/* Now that we know we're actually generating the token... */
262
if (toktype == KG_TOK_WRAP_MSG) {
196
plain.length = message->length + 16;
197
plain.data = malloc(message->length + 16);
198
if (plain.data == NULL)
201
err = krb5_c_checksum_length(context, cksumtype, &cksumsize);
205
assert(cksumsize <= 0xffff);
207
bufsize = 16 + message2->length + cksumsize;
208
outbuf = malloc(bufsize);
209
if (outbuf == NULL) {
217
store_16_be(tok_id, outbuf);
219
outbuf[2] = (acceptor_flag
220
| (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
223
if (toktype == KG_TOK_WRAP_MSG) {
224
/* Use 0 for checksum calculation, substitute
225
checksum length later. */
227
store_16_be(0, outbuf+4);
229
store_16_be(0, outbuf+6);
231
/* MIC and DEL store 0xFF in EC and RRC. */
232
store_16_be(0xffff, outbuf+4);
233
store_16_be(0xffff, outbuf+6);
235
store_64_be(ctx->seq_send, outbuf+8);
237
memcpy(plain.data, message->value, message->length);
238
memcpy(plain.data + message->length, outbuf, 16);
240
/* Fill in the output token -- data contents, if any, and
241
space for the checksum. */
242
if (message2->length)
243
memcpy(outbuf + 16, message2->value, message2->length);
245
sum.contents = outbuf + 16 + message2->length;
246
sum.length = cksumsize;
248
err = krb5_c_make_checksum(context, cksumtype, key,
249
key_usage, &plain, &sum);
250
zap(plain.data, plain.length);
257
if (sum.length != cksumsize)
259
memcpy(outbuf + 16 + message2->length, sum.contents, cksumsize);
260
krb5_free_checksum_contents(context, &sum);
262
/* Now that we know we're actually generating the token... */
265
if (toktype == KG_TOK_WRAP_MSG) {
263
266
#ifdef CFX_EXERCISE
264
rrc = rand() & 0xffff;
265
/* If the rotate fails, don't worry about it. */
266
if (rotate_left(outbuf+16, bufsize-16,
267
(bufsize-16) - (rrc % (bufsize - 16))))
268
store_16_be(rrc, outbuf+6);
267
rrc = rand() & 0xffff;
268
/* If the rotate fails, don't worry about it. */
269
if (gss_krb5int_rotate_left(outbuf+16, bufsize-16,
270
(bufsize-16) - (rrc % (bufsize - 16))))
271
store_16_be(rrc, outbuf+6);
270
/* Fix up EC field. */
271
store_16_be(ctx->cksum_size, outbuf+4);
273
store_16_be(0xffff, outbuf+6);
273
/* Fix up EC field. */
274
store_16_be(cksumsize, outbuf+4);
276
store_16_be(0xffff, outbuf+6);
275
278
} else if (toktype == KG_TOK_MIC_MSG) {
277
message2 = &empty_message;
278
goto wrap_with_checksum;
279
tok_id = KG2_TOK_MIC_MSG;
280
message2 = &empty_message;
281
goto wrap_with_checksum;
279
282
} else if (toktype == KG_TOK_DEL_CTX) {
281
message = message2 = &empty_message;
282
goto wrap_with_checksum;
283
tok_id = KG2_TOK_DEL_CTX;
284
message = message2 = &empty_message;
285
goto wrap_with_checksum;
286
289
token->value = outbuf;
287
290
token->length = bufsize;
340
343
if (bodysize < 16) {
343
return GSS_S_DEFECTIVE_TOKEN;
346
return GSS_S_DEFECTIVE_TOKEN;
345
348
if ((ptr[2] & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
346
*minor_status = G_BAD_DIRECTION;
347
return GSS_S_BAD_SIG;
349
*minor_status = (OM_uint32)G_BAD_DIRECTION;
350
return GSS_S_BAD_SIG;
350
353
/* Two things to note here.
352
First, we can't really enforce the use of the acceptor's subkey,
353
if we're the acceptor; the initiator may have sent messages
354
before getting the subkey. We could probably enforce it if
355
First, we can't really enforce the use of the acceptor's subkey,
356
if we're the acceptor; the initiator may have sent messages
357
before getting the subkey. We could probably enforce it if
357
Second, if someone tweaks the code to not set the flag telling
358
the krb5 library to generate a new subkey in the AP-REP
359
message, the MIT library may include a subkey anyways --
360
namely, a copy of the AP-REQ subkey, if it was provided. So
361
the initiator may think we wanted a subkey, and set the flag,
362
even though we weren't trying to set the subkey. The "other"
363
key, the one not asserted by the acceptor, will have the same
364
value in that case, though, so we can just ignore the flag. */
360
Second, if someone tweaks the code to not set the flag telling
361
the krb5 library to generate a new subkey in the AP-REP
362
message, the MIT library may include a subkey anyways --
363
namely, a copy of the AP-REQ subkey, if it was provided. So
364
the initiator may think we wanted a subkey, and set the flag,
365
even though we weren't trying to set the subkey. The "other"
366
key, the one not asserted by the acceptor, will have the same
367
value in that case, though, so we can just ignore the flag. */
365
368
if (ctx->have_acceptor_subkey && (ptr[2] & FLAG_ACCEPTOR_SUBKEY)) {
366
key = ctx->acceptor_subkey;
369
key = ctx->acceptor_subkey;
370
cksumtype = ctx->acceptor_subkey_cksumtype;
373
cksumtype = ctx->cksumtype;
371
377
if (toktype == KG_TOK_WRAP_MSG) {
372
if (load_16_be(ptr) != 0x0504)
376
ec = load_16_be(ptr+4);
377
rrc = load_16_be(ptr+6);
378
seqnum = load_64_be(ptr+8);
379
if (!rotate_left(ptr+16, bodysize-16, rrc)) {
381
*minor_status = ENOMEM;
382
return GSS_S_FAILURE;
384
if (ptr[2] & FLAG_WRAP_CONFIDENTIAL) {
385
/* confidentiality */
386
krb5_enc_data cipher;
387
unsigned char *althdr;
391
/* Do we have no decrypt_size function?
393
For all current cryptosystems, the ciphertext size will
394
be larger than the plaintext size. */
395
cipher.enctype = key->enctype;
396
cipher.ciphertext.length = bodysize - 16;
397
cipher.ciphertext.data = ptr + 16;
398
plain.length = bodysize - 16;
399
plain.data = malloc(plain.length);
400
if (plain.data == NULL)
402
err = krb5_c_decrypt(context, key, key_usage, 0,
408
/* Don't use bodysize here! Use the fact that
409
cipher.ciphertext.length has been adjusted to the
411
althdr = plain.data + plain.length - 16;
412
if (load_16_be(althdr) != 0x0504
413
|| althdr[2] != ptr[2]
414
|| althdr[3] != ptr[3]
415
|| memcmp(althdr+8, ptr+8, 8)) {
419
message_buffer->value = plain.data;
420
message_buffer->length = plain.length - ec - 16;
421
if(message_buffer->length == 0) {
422
free(message_buffer->value);
423
message_buffer->value = NULL;
426
/* no confidentiality */
432
if (ec + 16 > bodysize)
434
/* We have: header | msg | cksum.
435
We need cksum(msg | header).
436
Rotate the first two. */
437
store_16_be(0, ptr+4);
438
store_16_be(0, ptr+6);
439
plain.length = bodysize-ec;
441
if (!rotate_left(ptr, bodysize-ec, 16))
444
if (sum.length != ctx->cksum_size) {
446
return GSS_S_BAD_SIG;
448
sum.contents = ptr+bodysize-ec;
449
sum.checksum_type = ctx->cksumtype;
450
err = krb5_c_verify_checksum(context, key, key_usage,
451
&plain, &sum, &valid);
456
return GSS_S_BAD_SIG;
458
message_buffer->length = plain.length - 16;
459
message_buffer->value = malloc(message_buffer->length);
460
if (message_buffer->value == NULL)
462
memcpy(message_buffer->value, plain.data, message_buffer->length);
464
err = g_order_check(&ctx->seqstate, seqnum);
378
if (load_16_be(ptr) != KG2_TOK_WRAP_MSG)
382
ec = load_16_be(ptr+4);
383
rrc = load_16_be(ptr+6);
384
seqnum = load_64_be(ptr+8);
385
if (!gss_krb5int_rotate_left(ptr+16, bodysize-16, rrc)) {
387
*minor_status = ENOMEM;
388
return GSS_S_FAILURE;
390
if (ptr[2] & FLAG_WRAP_CONFIDENTIAL) {
391
/* confidentiality */
392
krb5_enc_data cipher;
393
unsigned char *althdr;
397
/* Do we have no decrypt_size function?
399
For all current cryptosystems, the ciphertext size will
400
be larger than the plaintext size. */
401
cipher.enctype = key->enctype;
402
cipher.ciphertext.length = bodysize - 16;
403
cipher.ciphertext.data = (char *)ptr + 16;
404
plain.length = bodysize - 16;
405
plain.data = malloc(plain.length);
406
if (plain.data == NULL)
408
err = krb5_c_decrypt(context, key, key_usage, 0,
414
/* Don't use bodysize here! Use the fact that
415
cipher.ciphertext.length has been adjusted to the
417
althdr = (unsigned char *)plain.data + plain.length - 16;
418
if (load_16_be(althdr) != KG2_TOK_WRAP_MSG
419
|| althdr[2] != ptr[2]
420
|| althdr[3] != ptr[3]
421
|| memcmp(althdr+8, ptr+8, 8)) {
425
message_buffer->value = plain.data;
426
message_buffer->length = plain.length - ec - 16;
427
if(message_buffer->length == 0) {
428
free(message_buffer->value);
429
message_buffer->value = NULL;
434
err = krb5_c_checksum_length(context, cksumtype, &cksumsize);
438
/* no confidentiality */
444
if (ec + 16 > bodysize)
446
/* We have: header | msg | cksum.
447
We need cksum(msg | header).
448
Rotate the first two. */
449
store_16_be(0, ptr+4);
450
store_16_be(0, ptr+6);
451
plain.length = bodysize-ec;
452
plain.data = (char *)ptr;
453
if (!gss_krb5int_rotate_left(ptr, bodysize-ec, 16))
456
if (sum.length != cksumsize) {
458
return GSS_S_BAD_SIG;
460
sum.contents = ptr+bodysize-ec;
461
sum.checksum_type = cksumtype;
462
err = krb5_c_verify_checksum(context, key, key_usage,
463
&plain, &sum, &valid);
468
return GSS_S_BAD_SIG;
470
message_buffer->length = plain.length - 16;
471
message_buffer->value = malloc(message_buffer->length);
472
if (message_buffer->value == NULL)
474
memcpy(message_buffer->value, plain.data, message_buffer->length);
476
err = g_order_check(&ctx->seqstate, seqnum);
467
479
} else if (toktype == KG_TOK_MIC_MSG) {
468
/* wrap token, no confidentiality */
469
if (load_16_be(ptr) != 0x0404)
480
/* wrap token, no confidentiality */
481
if (load_16_be(ptr) != KG2_TOK_MIC_MSG)
474
if (load_32_be(ptr+4) != 0xffffffffL)
476
seqnum = load_64_be(ptr+8);
477
plain.length = message_buffer->length + 16;
478
plain.data = malloc(plain.length);
479
if (plain.data == NULL)
481
if (message_buffer->length)
482
memcpy(plain.data, message_buffer->value, message_buffer->length);
483
memcpy(plain.data + message_buffer->length, ptr, 16);
484
sum.length = bodysize - 16;
485
sum.contents = ptr + 16;
486
sum.checksum_type = ctx->cksumtype;
487
err = krb5_c_verify_checksum(context, key, key_usage,
488
&plain, &sum, &valid);
494
return GSS_S_BAD_SIG; /* XXX */
498
return GSS_S_BAD_SIG;
500
err = g_order_check(&ctx->seqstate, seqnum);
486
if (load_32_be(ptr+4) != 0xffffffffL)
488
seqnum = load_64_be(ptr+8);
489
plain.length = message_buffer->length + 16;
490
plain.data = malloc(plain.length);
491
if (plain.data == NULL)
493
if (message_buffer->length)
494
memcpy(plain.data, message_buffer->value, message_buffer->length);
495
memcpy(plain.data + message_buffer->length, ptr, 16);
496
sum.length = bodysize - 16;
497
sum.contents = ptr + 16;
498
sum.checksum_type = cksumtype;
499
err = krb5_c_verify_checksum(context, key, key_usage,
500
&plain, &sum, &valid);
506
save_error_info(*minor_status, context);
507
return GSS_S_BAD_SIG; /* XXX */
511
return GSS_S_BAD_SIG;
513
err = g_order_check(&ctx->seqstate, seqnum);
503
516
} else if (toktype == KG_TOK_DEL_CTX) {
504
if (load_16_be(ptr) != 0x0405)
506
message_buffer = &empty_message;
517
if (load_16_be(ptr) != KG2_TOK_DEL_CTX)
519
message_buffer = (gss_buffer_t)&empty_message;