Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/lib/gssapi/ntlm/crypto.c
34914 views
1
/*
2
* Copyright (c) 2006 Kungliga Tekniska Högskolan
3
* (Royal Institute of Technology, Stockholm, Sweden).
4
* All rights reserved.
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
*
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
*
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* 3. Neither the name of the Institute nor the names of its contributors
18
* may be used to endorse or promote products derived from this software
19
* without specific prior written permission.
20
*
21
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
* SUCH DAMAGE.
32
*/
33
34
#include "ntlm.h"
35
36
uint32_t
37
_krb5_crc_update (const char *p, size_t len, uint32_t res);
38
void
39
_krb5_crc_init_table(void);
40
41
/*
42
*
43
*/
44
45
static void
46
encode_le_uint32(uint32_t n, unsigned char *p)
47
{
48
p[0] = (n >> 0) & 0xFF;
49
p[1] = (n >> 8) & 0xFF;
50
p[2] = (n >> 16) & 0xFF;
51
p[3] = (n >> 24) & 0xFF;
52
}
53
54
55
static void
56
decode_le_uint32(const void *ptr, uint32_t *n)
57
{
58
const unsigned char *p = ptr;
59
*n = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
60
}
61
62
/*
63
*
64
*/
65
66
const char a2i_signmagic[] =
67
"session key to server-to-client signing key magic constant";
68
const char a2i_sealmagic[] =
69
"session key to server-to-client sealing key magic constant";
70
const char i2a_signmagic[] =
71
"session key to client-to-server signing key magic constant";
72
const char i2a_sealmagic[] =
73
"session key to client-to-server sealing key magic constant";
74
75
76
void
77
_gss_ntlm_set_key(struct ntlmv2_key *key, int acceptor, int sealsign,
78
unsigned char *data, size_t len)
79
{
80
unsigned char out[16];
81
EVP_MD_CTX *ctx;
82
const char *signmagic;
83
const char *sealmagic;
84
85
if (acceptor) {
86
signmagic = a2i_signmagic;
87
sealmagic = a2i_sealmagic;
88
} else {
89
signmagic = i2a_signmagic;
90
sealmagic = i2a_sealmagic;
91
}
92
93
key->seq = 0;
94
95
ctx = EVP_MD_CTX_create();
96
EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
97
EVP_DigestUpdate(ctx, data, len);
98
EVP_DigestUpdate(ctx, signmagic, strlen(signmagic) + 1);
99
EVP_DigestFinal_ex(ctx, key->signkey, NULL);
100
101
EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
102
EVP_DigestUpdate(ctx, data, len);
103
EVP_DigestUpdate(ctx, sealmagic, strlen(sealmagic) + 1);
104
EVP_DigestFinal_ex(ctx, out, NULL);
105
EVP_MD_CTX_destroy(ctx);
106
107
RC4_set_key(&key->sealkey, 16, out);
108
if (sealsign)
109
key->signsealkey = &key->sealkey;
110
}
111
112
/*
113
*
114
*/
115
116
static OM_uint32
117
v1_sign_message(gss_buffer_t in,
118
RC4_KEY *signkey,
119
uint32_t seq,
120
unsigned char out[16])
121
{
122
unsigned char sigature[12];
123
uint32_t crc;
124
125
_krb5_crc_init_table();
126
crc = _krb5_crc_update(in->value, in->length, 0);
127
128
encode_le_uint32(0, &sigature[0]);
129
encode_le_uint32(crc, &sigature[4]);
130
encode_le_uint32(seq, &sigature[8]);
131
132
encode_le_uint32(1, out); /* version */
133
RC4(signkey, sizeof(sigature), sigature, out + 4);
134
135
if (RAND_bytes(out + 4, 4) != 1)
136
return GSS_S_UNAVAILABLE;
137
138
return 0;
139
}
140
141
142
static OM_uint32
143
v2_sign_message(gss_buffer_t in,
144
unsigned char signkey[16],
145
RC4_KEY *sealkey,
146
uint32_t seq,
147
unsigned char out[16])
148
{
149
unsigned char hmac[16];
150
unsigned int hmaclen;
151
HMAC_CTX *c;
152
153
c = HMAC_CTX_new();
154
if (c == NULL)
155
return GSS_S_FAILURE;
156
HMAC_Init_ex(c, signkey, 16, EVP_md5(), NULL);
157
158
encode_le_uint32(seq, hmac);
159
HMAC_Update(c, hmac, 4);
160
HMAC_Update(c, in->value, in->length);
161
HMAC_Final(c, hmac, &hmaclen);
162
HMAC_CTX_free(c);
163
164
encode_le_uint32(1, &out[0]);
165
if (sealkey)
166
RC4(sealkey, 8, hmac, &out[4]);
167
else
168
memcpy(&out[4], hmac, 8);
169
170
memset(&out[12], 0, 4);
171
172
return GSS_S_COMPLETE;
173
}
174
175
static OM_uint32
176
v2_verify_message(gss_buffer_t in,
177
unsigned char signkey[16],
178
RC4_KEY *sealkey,
179
uint32_t seq,
180
const unsigned char checksum[16])
181
{
182
OM_uint32 ret;
183
unsigned char out[16];
184
185
ret = v2_sign_message(in, signkey, sealkey, seq, out);
186
if (ret)
187
return ret;
188
189
if (memcmp(checksum, out, 16) != 0)
190
return GSS_S_BAD_MIC;
191
192
return GSS_S_COMPLETE;
193
}
194
195
static OM_uint32
196
v2_seal_message(const gss_buffer_t in,
197
unsigned char signkey[16],
198
uint32_t seq,
199
RC4_KEY *sealkey,
200
gss_buffer_t out)
201
{
202
unsigned char *p;
203
OM_uint32 ret;
204
205
if (in->length + 16 < in->length)
206
return EINVAL;
207
208
p = malloc(in->length + 16);
209
if (p == NULL)
210
return ENOMEM;
211
212
RC4(sealkey, in->length, in->value, p);
213
214
ret = v2_sign_message(in, signkey, sealkey, seq, &p[in->length]);
215
if (ret) {
216
free(p);
217
return ret;
218
}
219
220
out->value = p;
221
out->length = in->length + 16;
222
223
return 0;
224
}
225
226
static OM_uint32
227
v2_unseal_message(gss_buffer_t in,
228
unsigned char signkey[16],
229
uint32_t seq,
230
RC4_KEY *sealkey,
231
gss_buffer_t out)
232
{
233
OM_uint32 ret;
234
235
if (in->length < 16)
236
return GSS_S_BAD_MIC;
237
238
out->length = in->length - 16;
239
out->value = malloc(out->length);
240
if (out->value == NULL)
241
return GSS_S_BAD_MIC;
242
243
RC4(sealkey, out->length, in->value, out->value);
244
245
ret = v2_verify_message(out, signkey, sealkey, seq,
246
((const unsigned char *)in->value) + out->length);
247
if (ret) {
248
OM_uint32 junk;
249
gss_release_buffer(&junk, out);
250
}
251
return ret;
252
}
253
254
/*
255
*
256
*/
257
258
#define CTX_FLAGS_ISSET(_ctx,_flags) \
259
(((_ctx)->flags & (_flags)) == (_flags))
260
261
/*
262
*
263
*/
264
265
OM_uint32 GSSAPI_CALLCONV
266
_gss_ntlm_get_mic
267
(OM_uint32 * minor_status,
268
const gss_ctx_id_t context_handle,
269
gss_qop_t qop_req,
270
const gss_buffer_t message_buffer,
271
gss_buffer_t message_token
272
)
273
{
274
ntlm_ctx ctx = (ntlm_ctx)context_handle;
275
OM_uint32 junk;
276
277
*minor_status = 0;
278
279
message_token->value = malloc(16);
280
message_token->length = 16;
281
if (message_token->value == NULL) {
282
*minor_status = ENOMEM;
283
return GSS_S_FAILURE;
284
}
285
286
if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN|NTLM_NEG_NTLM2_SESSION)) {
287
OM_uint32 ret;
288
289
if ((ctx->status & STATUS_SESSIONKEY) == 0) {
290
gss_release_buffer(&junk, message_token);
291
return GSS_S_UNAVAILABLE;
292
}
293
294
ret = v2_sign_message(message_buffer,
295
ctx->u.v2.send.signkey,
296
ctx->u.v2.send.signsealkey,
297
ctx->u.v2.send.seq++,
298
message_token->value);
299
if (ret)
300
gss_release_buffer(&junk, message_token);
301
return ret;
302
303
} else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN)) {
304
OM_uint32 ret;
305
306
if ((ctx->status & STATUS_SESSIONKEY) == 0) {
307
gss_release_buffer(&junk, message_token);
308
return GSS_S_UNAVAILABLE;
309
}
310
311
ret = v1_sign_message(message_buffer,
312
&ctx->u.v1.crypto_send.key,
313
ctx->u.v1.crypto_send.seq++,
314
message_token->value);
315
if (ret)
316
gss_release_buffer(&junk, message_token);
317
return ret;
318
319
} else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_ALWAYS_SIGN)) {
320
unsigned char *sigature;
321
322
sigature = message_token->value;
323
324
encode_le_uint32(1, &sigature[0]); /* version */
325
encode_le_uint32(0, &sigature[4]);
326
encode_le_uint32(0, &sigature[8]);
327
encode_le_uint32(0, &sigature[12]);
328
329
return GSS_S_COMPLETE;
330
}
331
gss_release_buffer(&junk, message_token);
332
333
return GSS_S_UNAVAILABLE;
334
}
335
336
/*
337
*
338
*/
339
340
OM_uint32 GSSAPI_CALLCONV
341
_gss_ntlm_verify_mic
342
(OM_uint32 * minor_status,
343
const gss_ctx_id_t context_handle,
344
const gss_buffer_t message_buffer,
345
const gss_buffer_t token_buffer,
346
gss_qop_t * qop_state
347
)
348
{
349
ntlm_ctx ctx = (ntlm_ctx)context_handle;
350
351
if (qop_state != NULL)
352
*qop_state = GSS_C_QOP_DEFAULT;
353
*minor_status = 0;
354
355
if (token_buffer->length != 16)
356
return GSS_S_BAD_MIC;
357
358
if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN|NTLM_NEG_NTLM2_SESSION)) {
359
OM_uint32 ret;
360
361
if ((ctx->status & STATUS_SESSIONKEY) == 0)
362
return GSS_S_UNAVAILABLE;
363
364
ret = v2_verify_message(message_buffer,
365
ctx->u.v2.recv.signkey,
366
ctx->u.v2.recv.signsealkey,
367
ctx->u.v2.recv.seq++,
368
token_buffer->value);
369
if (ret)
370
return ret;
371
372
return GSS_S_COMPLETE;
373
} else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SIGN)) {
374
375
unsigned char sigature[12];
376
uint32_t crc, num;
377
378
if ((ctx->status & STATUS_SESSIONKEY) == 0)
379
return GSS_S_UNAVAILABLE;
380
381
decode_le_uint32(token_buffer->value, &num);
382
if (num != 1)
383
return GSS_S_BAD_MIC;
384
385
RC4(&ctx->u.v1.crypto_recv.key, sizeof(sigature),
386
((unsigned char *)token_buffer->value) + 4, sigature);
387
388
_krb5_crc_init_table();
389
crc = _krb5_crc_update(message_buffer->value,
390
message_buffer->length, 0);
391
/* skip first 4 bytes in the encrypted checksum */
392
decode_le_uint32(&sigature[4], &num);
393
if (num != crc)
394
return GSS_S_BAD_MIC;
395
decode_le_uint32(&sigature[8], &num);
396
if (ctx->u.v1.crypto_recv.seq != num)
397
return GSS_S_BAD_MIC;
398
ctx->u.v1.crypto_recv.seq++;
399
400
return GSS_S_COMPLETE;
401
} else if (ctx->flags & NTLM_NEG_ALWAYS_SIGN) {
402
uint32_t num;
403
unsigned char *p;
404
405
p = (unsigned char*)(token_buffer->value);
406
407
decode_le_uint32(&p[0], &num); /* version */
408
if (num != 1) return GSS_S_BAD_MIC;
409
decode_le_uint32(&p[4], &num);
410
if (num != 0) return GSS_S_BAD_MIC;
411
decode_le_uint32(&p[8], &num);
412
if (num != 0) return GSS_S_BAD_MIC;
413
decode_le_uint32(&p[12], &num);
414
if (num != 0) return GSS_S_BAD_MIC;
415
416
return GSS_S_COMPLETE;
417
}
418
419
return GSS_S_UNAVAILABLE;
420
}
421
422
/*
423
*
424
*/
425
426
OM_uint32 GSSAPI_CALLCONV
427
_gss_ntlm_wrap_size_limit (
428
OM_uint32 * minor_status,
429
const gss_ctx_id_t context_handle,
430
int conf_req_flag,
431
gss_qop_t qop_req,
432
OM_uint32 req_output_size,
433
OM_uint32 * max_input_size
434
)
435
{
436
ntlm_ctx ctx = (ntlm_ctx)context_handle;
437
438
*minor_status = 0;
439
440
if(ctx->flags & NTLM_NEG_SEAL) {
441
442
if (req_output_size < 16)
443
*max_input_size = 0;
444
else
445
*max_input_size = req_output_size - 16;
446
447
return GSS_S_COMPLETE;
448
}
449
450
return GSS_S_UNAVAILABLE;
451
}
452
453
/*
454
*
455
*/
456
457
OM_uint32 GSSAPI_CALLCONV
458
_gss_ntlm_wrap
459
(OM_uint32 * minor_status,
460
const gss_ctx_id_t context_handle,
461
int conf_req_flag,
462
gss_qop_t qop_req,
463
const gss_buffer_t input_message_buffer,
464
int * conf_state,
465
gss_buffer_t output_message_buffer
466
)
467
{
468
ntlm_ctx ctx = (ntlm_ctx)context_handle;
469
OM_uint32 ret;
470
471
*minor_status = 0;
472
if (conf_state)
473
*conf_state = 0;
474
if (output_message_buffer == GSS_C_NO_BUFFER)
475
return GSS_S_FAILURE;
476
477
478
if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL|NTLM_NEG_NTLM2_SESSION)) {
479
480
return v2_seal_message(input_message_buffer,
481
ctx->u.v2.send.signkey,
482
ctx->u.v2.send.seq++,
483
&ctx->u.v2.send.sealkey,
484
output_message_buffer);
485
486
} else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL)) {
487
gss_buffer_desc trailer;
488
OM_uint32 junk;
489
490
output_message_buffer->length = input_message_buffer->length + 16;
491
output_message_buffer->value = malloc(output_message_buffer->length);
492
if (output_message_buffer->value == NULL) {
493
output_message_buffer->length = 0;
494
return GSS_S_FAILURE;
495
}
496
497
498
RC4(&ctx->u.v1.crypto_send.key, input_message_buffer->length,
499
input_message_buffer->value, output_message_buffer->value);
500
501
ret = _gss_ntlm_get_mic(minor_status, context_handle,
502
0, input_message_buffer,
503
&trailer);
504
if (ret) {
505
gss_release_buffer(&junk, output_message_buffer);
506
return ret;
507
}
508
if (trailer.length != 16) {
509
gss_release_buffer(&junk, output_message_buffer);
510
gss_release_buffer(&junk, &trailer);
511
return GSS_S_FAILURE;
512
}
513
memcpy(((unsigned char *)output_message_buffer->value) +
514
input_message_buffer->length,
515
trailer.value, trailer.length);
516
gss_release_buffer(&junk, &trailer);
517
518
return GSS_S_COMPLETE;
519
}
520
521
return GSS_S_UNAVAILABLE;
522
}
523
524
/*
525
*
526
*/
527
528
OM_uint32 GSSAPI_CALLCONV
529
_gss_ntlm_unwrap
530
(OM_uint32 * minor_status,
531
const gss_ctx_id_t context_handle,
532
const gss_buffer_t input_message_buffer,
533
gss_buffer_t output_message_buffer,
534
int * conf_state,
535
gss_qop_t * qop_state
536
)
537
{
538
ntlm_ctx ctx = (ntlm_ctx)context_handle;
539
OM_uint32 ret;
540
541
*minor_status = 0;
542
output_message_buffer->value = NULL;
543
output_message_buffer->length = 0;
544
545
if (conf_state)
546
*conf_state = 0;
547
if (qop_state)
548
*qop_state = 0;
549
550
if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL|NTLM_NEG_NTLM2_SESSION)) {
551
552
return v2_unseal_message(input_message_buffer,
553
ctx->u.v2.recv.signkey,
554
ctx->u.v2.recv.seq++,
555
&ctx->u.v2.recv.sealkey,
556
output_message_buffer);
557
558
} else if (CTX_FLAGS_ISSET(ctx, NTLM_NEG_SEAL)) {
559
560
gss_buffer_desc trailer;
561
OM_uint32 junk;
562
563
if (input_message_buffer->length < 16)
564
return GSS_S_BAD_MIC;
565
566
output_message_buffer->length = input_message_buffer->length - 16;
567
output_message_buffer->value = malloc(output_message_buffer->length);
568
if (output_message_buffer->value == NULL) {
569
output_message_buffer->length = 0;
570
return GSS_S_FAILURE;
571
}
572
573
RC4(&ctx->u.v1.crypto_recv.key, output_message_buffer->length,
574
input_message_buffer->value, output_message_buffer->value);
575
576
trailer.value = ((unsigned char *)input_message_buffer->value) +
577
output_message_buffer->length;
578
trailer.length = 16;
579
580
ret = _gss_ntlm_verify_mic(minor_status, context_handle,
581
output_message_buffer,
582
&trailer, NULL);
583
if (ret) {
584
gss_release_buffer(&junk, output_message_buffer);
585
return ret;
586
}
587
588
return GSS_S_COMPLETE;
589
}
590
591
return GSS_S_UNAVAILABLE;
592
}
593
594