Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/lib/krb5/digest.c
34878 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 "krb5_locl.h"
35
#include "digest_asn1.h"
36
37
#ifndef HEIMDAL_SMALLER
38
39
struct krb5_digest_data {
40
char *cbtype;
41
char *cbbinding;
42
43
DigestInit init;
44
DigestInitReply initReply;
45
DigestRequest request;
46
DigestResponse response;
47
};
48
49
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
50
krb5_digest_alloc(krb5_context context, krb5_digest *digest)
51
{
52
krb5_digest d;
53
54
d = calloc(1, sizeof(*d));
55
if (d == NULL) {
56
*digest = NULL;
57
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
58
return ENOMEM;
59
}
60
*digest = d;
61
62
return 0;
63
}
64
65
KRB5_LIB_FUNCTION void KRB5_LIB_CALL
66
krb5_digest_free(krb5_digest digest)
67
{
68
if (digest == NULL)
69
return;
70
free_DigestInit(&digest->init);
71
free_DigestInitReply(&digest->initReply);
72
free_DigestRequest(&digest->request);
73
free_DigestResponse(&digest->response);
74
memset(digest, 0, sizeof(*digest));
75
free(digest);
76
return;
77
}
78
79
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
80
krb5_digest_set_server_cb(krb5_context context,
81
krb5_digest digest,
82
const char *type,
83
const char *binding)
84
{
85
if (digest->init.channel) {
86
krb5_set_error_message(context, EINVAL,
87
N_("server channel binding already set", ""));
88
return EINVAL;
89
}
90
digest->init.channel = calloc(1, sizeof(*digest->init.channel));
91
if (digest->init.channel == NULL)
92
goto error;
93
94
digest->init.channel->cb_type = strdup(type);
95
if (digest->init.channel->cb_type == NULL)
96
goto error;
97
98
digest->init.channel->cb_binding = strdup(binding);
99
if (digest->init.channel->cb_binding == NULL)
100
goto error;
101
return 0;
102
error:
103
if (digest->init.channel) {
104
free(digest->init.channel->cb_type);
105
free(digest->init.channel->cb_binding);
106
free(digest->init.channel);
107
digest->init.channel = NULL;
108
}
109
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
110
return ENOMEM;
111
}
112
113
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
114
krb5_digest_set_type(krb5_context context,
115
krb5_digest digest,
116
const char *type)
117
{
118
if (digest->init.type) {
119
krb5_set_error_message(context, EINVAL, "client type already set");
120
return EINVAL;
121
}
122
digest->init.type = strdup(type);
123
if (digest->init.type == NULL) {
124
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
125
return ENOMEM;
126
}
127
return 0;
128
}
129
130
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
131
krb5_digest_set_hostname(krb5_context context,
132
krb5_digest digest,
133
const char *hostname)
134
{
135
if (digest->init.hostname) {
136
krb5_set_error_message(context, EINVAL, "server hostname already set");
137
return EINVAL;
138
}
139
digest->init.hostname = malloc(sizeof(*digest->init.hostname));
140
if (digest->init.hostname == NULL) {
141
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
142
return ENOMEM;
143
}
144
*digest->init.hostname = strdup(hostname);
145
if (*digest->init.hostname == NULL) {
146
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
147
free(digest->init.hostname);
148
digest->init.hostname = NULL;
149
return ENOMEM;
150
}
151
return 0;
152
}
153
154
KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL
155
krb5_digest_get_server_nonce(krb5_context context,
156
krb5_digest digest)
157
{
158
return digest->initReply.nonce;
159
}
160
161
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
162
krb5_digest_set_server_nonce(krb5_context context,
163
krb5_digest digest,
164
const char *nonce)
165
{
166
if (digest->request.serverNonce) {
167
krb5_set_error_message(context, EINVAL, N_("nonce already set", ""));
168
return EINVAL;
169
}
170
digest->request.serverNonce = strdup(nonce);
171
if (digest->request.serverNonce == NULL) {
172
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
173
return ENOMEM;
174
}
175
return 0;
176
}
177
178
KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL
179
krb5_digest_get_opaque(krb5_context context,
180
krb5_digest digest)
181
{
182
return digest->initReply.opaque;
183
}
184
185
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
186
krb5_digest_set_opaque(krb5_context context,
187
krb5_digest digest,
188
const char *opaque)
189
{
190
if (digest->request.opaque) {
191
krb5_set_error_message(context, EINVAL, "opaque already set");
192
return EINVAL;
193
}
194
digest->request.opaque = strdup(opaque);
195
if (digest->request.opaque == NULL) {
196
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
197
return ENOMEM;
198
}
199
return 0;
200
}
201
202
KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL
203
krb5_digest_get_identifier(krb5_context context,
204
krb5_digest digest)
205
{
206
if (digest->initReply.identifier == NULL)
207
return NULL;
208
return *digest->initReply.identifier;
209
}
210
211
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
212
krb5_digest_set_identifier(krb5_context context,
213
krb5_digest digest,
214
const char *id)
215
{
216
if (digest->request.identifier) {
217
krb5_set_error_message(context, EINVAL, N_("identifier already set", ""));
218
return EINVAL;
219
}
220
digest->request.identifier = calloc(1, sizeof(*digest->request.identifier));
221
if (digest->request.identifier == NULL) {
222
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
223
return ENOMEM;
224
}
225
*digest->request.identifier = strdup(id);
226
if (*digest->request.identifier == NULL) {
227
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
228
free(digest->request.identifier);
229
digest->request.identifier = NULL;
230
return ENOMEM;
231
}
232
return 0;
233
}
234
235
static krb5_error_code
236
digest_request(krb5_context context,
237
krb5_realm realm,
238
krb5_ccache ccache,
239
krb5_key_usage usage,
240
const DigestReqInner *ireq,
241
DigestRepInner *irep)
242
{
243
DigestREQ req;
244
DigestREP rep;
245
krb5_error_code ret;
246
krb5_data data, data2;
247
size_t size = 0;
248
krb5_crypto crypto = NULL;
249
krb5_auth_context ac = NULL;
250
krb5_principal principal = NULL;
251
krb5_ccache id = NULL;
252
krb5_realm r = NULL;
253
254
krb5_data_zero(&data);
255
krb5_data_zero(&data2);
256
memset(&req, 0, sizeof(req));
257
memset(&rep, 0, sizeof(rep));
258
259
if (ccache == NULL) {
260
ret = krb5_cc_default(context, &id);
261
if (ret)
262
goto out;
263
} else
264
id = ccache;
265
266
if (realm == NULL) {
267
ret = krb5_get_default_realm(context, &r);
268
if (ret)
269
goto out;
270
} else
271
r = realm;
272
273
/*
274
*
275
*/
276
277
ret = krb5_make_principal(context, &principal,
278
r, KRB5_DIGEST_NAME, r, NULL);
279
if (ret)
280
goto out;
281
282
ASN1_MALLOC_ENCODE(DigestReqInner, data.data, data.length,
283
ireq, &size, ret);
284
if (ret) {
285
krb5_set_error_message(context, ret,
286
N_("Failed to encode digest inner request", ""));
287
goto out;
288
}
289
if (size != data.length)
290
krb5_abortx(context, "ASN.1 internal encoder error");
291
292
ret = krb5_mk_req_exact(context, &ac,
293
AP_OPTS_USE_SUBKEY|AP_OPTS_MUTUAL_REQUIRED,
294
principal, NULL, id, &req.apReq);
295
if (ret)
296
goto out;
297
298
{
299
krb5_keyblock *key;
300
301
ret = krb5_auth_con_getlocalsubkey(context, ac, &key);
302
if (ret)
303
goto out;
304
if (key == NULL) {
305
ret = EINVAL;
306
krb5_set_error_message(context, ret,
307
N_("Digest failed to get local subkey", ""));
308
goto out;
309
}
310
311
ret = krb5_crypto_init(context, key, 0, &crypto);
312
krb5_free_keyblock (context, key);
313
if (ret)
314
goto out;
315
}
316
317
ret = krb5_encrypt_EncryptedData(context, crypto, usage,
318
data.data, data.length, 0,
319
&req.innerReq);
320
if (ret)
321
goto out;
322
323
krb5_data_free(&data);
324
325
ASN1_MALLOC_ENCODE(DigestREQ, data.data, data.length,
326
&req, &size, ret);
327
if (ret) {
328
krb5_set_error_message(context, ret,
329
N_("Failed to encode DigestREQest", ""));
330
goto out;
331
}
332
if (size != data.length)
333
krb5_abortx(context, "ASN.1 internal encoder error");
334
335
ret = krb5_sendto_kdc(context, &data, &r, &data2);
336
if (ret)
337
goto out;
338
339
ret = decode_DigestREP(data2.data, data2.length, &rep, NULL);
340
if (ret) {
341
krb5_set_error_message(context, ret,
342
N_("Failed to parse digest response", ""));
343
goto out;
344
}
345
346
{
347
krb5_ap_rep_enc_part *repl;
348
349
ret = krb5_rd_rep(context, ac, &rep.apRep, &repl);
350
if (ret)
351
goto out;
352
353
krb5_free_ap_rep_enc_part(context, repl);
354
}
355
{
356
krb5_keyblock *key;
357
358
ret = krb5_auth_con_getremotesubkey(context, ac, &key);
359
if (ret)
360
goto out;
361
if (key == NULL) {
362
ret = EINVAL;
363
krb5_set_error_message(context, ret,
364
N_("Digest reply have no remote subkey", ""));
365
goto out;
366
}
367
368
krb5_crypto_destroy(context, crypto);
369
ret = krb5_crypto_init(context, key, 0, &crypto);
370
krb5_free_keyblock (context, key);
371
if (ret)
372
goto out;
373
}
374
375
krb5_data_free(&data);
376
ret = krb5_decrypt_EncryptedData(context, crypto, usage,
377
&rep.innerRep, &data);
378
if (ret)
379
goto out;
380
381
ret = decode_DigestRepInner(data.data, data.length, irep, NULL);
382
if (ret) {
383
krb5_set_error_message(context, ret,
384
N_("Failed to decode digest inner reply", ""));
385
goto out;
386
}
387
388
out:
389
if (ccache == NULL && id)
390
krb5_cc_close(context, id);
391
if (realm == NULL && r)
392
free(r);
393
if (crypto)
394
krb5_crypto_destroy(context, crypto);
395
if (ac)
396
krb5_auth_con_free(context, ac);
397
if (principal)
398
krb5_free_principal(context, principal);
399
400
krb5_data_free(&data);
401
krb5_data_free(&data2);
402
403
free_DigestREQ(&req);
404
free_DigestREP(&rep);
405
406
return ret;
407
}
408
409
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
410
krb5_digest_init_request(krb5_context context,
411
krb5_digest digest,
412
krb5_realm realm,
413
krb5_ccache ccache)
414
{
415
DigestReqInner ireq;
416
DigestRepInner irep;
417
krb5_error_code ret;
418
419
memset(&ireq, 0, sizeof(ireq));
420
memset(&irep, 0, sizeof(irep));
421
422
if (digest->init.type == NULL) {
423
krb5_set_error_message(context, EINVAL,
424
N_("Type missing from init req", ""));
425
return EINVAL;
426
}
427
428
ireq.element = choice_DigestReqInner_init;
429
ireq.u.init = digest->init;
430
431
ret = digest_request(context, realm, ccache,
432
KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
433
if (ret)
434
goto out;
435
436
if (irep.element == choice_DigestRepInner_error) {
437
ret = irep.u.error.code;
438
krb5_set_error_message(context, ret, N_("Digest init error: %s", ""),
439
irep.u.error.reason);
440
goto out;
441
}
442
443
if (irep.element != choice_DigestRepInner_initReply) {
444
ret = EINVAL;
445
krb5_set_error_message(context, ret,
446
N_("digest reply not an initReply", ""));
447
goto out;
448
}
449
450
ret = copy_DigestInitReply(&irep.u.initReply, &digest->initReply);
451
if (ret) {
452
krb5_set_error_message(context, ret,
453
N_("Failed to copy initReply", ""));
454
goto out;
455
}
456
457
out:
458
free_DigestRepInner(&irep);
459
460
return ret;
461
}
462
463
464
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
465
krb5_digest_set_client_nonce(krb5_context context,
466
krb5_digest digest,
467
const char *nonce)
468
{
469
if (digest->request.clientNonce) {
470
krb5_set_error_message(context, EINVAL,
471
N_("clientNonce already set", ""));
472
return EINVAL;
473
}
474
digest->request.clientNonce =
475
calloc(1, sizeof(*digest->request.clientNonce));
476
if (digest->request.clientNonce == NULL) {
477
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
478
return ENOMEM;
479
}
480
*digest->request.clientNonce = strdup(nonce);
481
if (*digest->request.clientNonce == NULL) {
482
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
483
free(digest->request.clientNonce);
484
digest->request.clientNonce = NULL;
485
return ENOMEM;
486
}
487
return 0;
488
}
489
490
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
491
krb5_digest_set_digest(krb5_context context,
492
krb5_digest digest,
493
const char *dgst)
494
{
495
if (digest->request.digest) {
496
krb5_set_error_message(context, EINVAL,
497
N_("digest already set", ""));
498
return EINVAL;
499
}
500
digest->request.digest = strdup(dgst);
501
if (digest->request.digest == NULL) {
502
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
503
return ENOMEM;
504
}
505
return 0;
506
}
507
508
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
509
krb5_digest_set_username(krb5_context context,
510
krb5_digest digest,
511
const char *username)
512
{
513
if (digest->request.username) {
514
krb5_set_error_message(context, EINVAL, "username already set");
515
return EINVAL;
516
}
517
digest->request.username = strdup(username);
518
if (digest->request.username == NULL) {
519
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
520
return ENOMEM;
521
}
522
return 0;
523
}
524
525
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
526
krb5_digest_set_authid(krb5_context context,
527
krb5_digest digest,
528
const char *authid)
529
{
530
if (digest->request.authid) {
531
krb5_set_error_message(context, EINVAL, "authid already set");
532
return EINVAL;
533
}
534
digest->request.authid = malloc(sizeof(*digest->request.authid));
535
if (digest->request.authid == NULL) {
536
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
537
return ENOMEM;
538
}
539
*digest->request.authid = strdup(authid);
540
if (*digest->request.authid == NULL) {
541
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
542
free(digest->request.authid);
543
digest->request.authid = NULL;
544
return ENOMEM;
545
}
546
return 0;
547
}
548
549
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
550
krb5_digest_set_authentication_user(krb5_context context,
551
krb5_digest digest,
552
krb5_principal authentication_user)
553
{
554
krb5_error_code ret;
555
556
if (digest->request.authentication_user) {
557
krb5_set_error_message(context, EINVAL,
558
N_("authentication_user already set", ""));
559
return EINVAL;
560
}
561
ret = krb5_copy_principal(context,
562
authentication_user,
563
&digest->request.authentication_user);
564
if (ret)
565
return ret;
566
return 0;
567
}
568
569
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
570
krb5_digest_set_realm(krb5_context context,
571
krb5_digest digest,
572
const char *realm)
573
{
574
if (digest->request.realm) {
575
krb5_set_error_message(context, EINVAL, "realm already set");
576
return EINVAL;
577
}
578
digest->request.realm = malloc(sizeof(*digest->request.realm));
579
if (digest->request.realm == NULL) {
580
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
581
return ENOMEM;
582
}
583
*digest->request.realm = strdup(realm);
584
if (*digest->request.realm == NULL) {
585
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
586
free(digest->request.realm);
587
digest->request.realm = NULL;
588
return ENOMEM;
589
}
590
return 0;
591
}
592
593
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
594
krb5_digest_set_method(krb5_context context,
595
krb5_digest digest,
596
const char *method)
597
{
598
if (digest->request.method) {
599
krb5_set_error_message(context, EINVAL,
600
N_("method already set", ""));
601
return EINVAL;
602
}
603
digest->request.method = malloc(sizeof(*digest->request.method));
604
if (digest->request.method == NULL) {
605
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
606
return ENOMEM;
607
}
608
*digest->request.method = strdup(method);
609
if (*digest->request.method == NULL) {
610
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
611
free(digest->request.method);
612
digest->request.method = NULL;
613
return ENOMEM;
614
}
615
return 0;
616
}
617
618
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
619
krb5_digest_set_uri(krb5_context context,
620
krb5_digest digest,
621
const char *uri)
622
{
623
if (digest->request.uri) {
624
krb5_set_error_message(context, EINVAL, N_("uri already set", ""));
625
return EINVAL;
626
}
627
digest->request.uri = malloc(sizeof(*digest->request.uri));
628
if (digest->request.uri == NULL) {
629
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
630
return ENOMEM;
631
}
632
*digest->request.uri = strdup(uri);
633
if (*digest->request.uri == NULL) {
634
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
635
free(digest->request.uri);
636
digest->request.uri = NULL;
637
return ENOMEM;
638
}
639
return 0;
640
}
641
642
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
643
krb5_digest_set_nonceCount(krb5_context context,
644
krb5_digest digest,
645
const char *nonce_count)
646
{
647
if (digest->request.nonceCount) {
648
krb5_set_error_message(context, EINVAL,
649
N_("nonceCount already set", ""));
650
return EINVAL;
651
}
652
digest->request.nonceCount =
653
malloc(sizeof(*digest->request.nonceCount));
654
if (digest->request.nonceCount == NULL) {
655
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
656
return ENOMEM;
657
}
658
*digest->request.nonceCount = strdup(nonce_count);
659
if (*digest->request.nonceCount == NULL) {
660
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
661
free(digest->request.nonceCount);
662
digest->request.nonceCount = NULL;
663
return ENOMEM;
664
}
665
return 0;
666
}
667
668
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
669
krb5_digest_set_qop(krb5_context context,
670
krb5_digest digest,
671
const char *qop)
672
{
673
if (digest->request.qop) {
674
krb5_set_error_message(context, EINVAL, "qop already set");
675
return EINVAL;
676
}
677
digest->request.qop = malloc(sizeof(*digest->request.qop));
678
if (digest->request.qop == NULL) {
679
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
680
return ENOMEM;
681
}
682
*digest->request.qop = strdup(qop);
683
if (*digest->request.qop == NULL) {
684
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
685
free(digest->request.qop);
686
digest->request.qop = NULL;
687
return ENOMEM;
688
}
689
return 0;
690
}
691
692
KRB5_LIB_FUNCTION int KRB5_LIB_CALL
693
krb5_digest_set_responseData(krb5_context context,
694
krb5_digest digest,
695
const char *response)
696
{
697
digest->request.responseData = strdup(response);
698
if (digest->request.responseData == NULL) {
699
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
700
return ENOMEM;
701
}
702
return 0;
703
}
704
705
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
706
krb5_digest_request(krb5_context context,
707
krb5_digest digest,
708
krb5_realm realm,
709
krb5_ccache ccache)
710
{
711
DigestReqInner ireq;
712
DigestRepInner irep;
713
krb5_error_code ret;
714
715
memset(&ireq, 0, sizeof(ireq));
716
memset(&irep, 0, sizeof(irep));
717
718
ireq.element = choice_DigestReqInner_digestRequest;
719
ireq.u.digestRequest = digest->request;
720
721
if (digest->request.type == NULL) {
722
if (digest->init.type == NULL) {
723
krb5_set_error_message(context, EINVAL,
724
N_("Type missing from req", ""));
725
return EINVAL;
726
}
727
ireq.u.digestRequest.type = digest->init.type;
728
}
729
730
if (ireq.u.digestRequest.digest == NULL) {
731
static char md5[] = "md5";
732
ireq.u.digestRequest.digest = md5;
733
}
734
735
ret = digest_request(context, realm, ccache,
736
KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
737
if (ret)
738
return ret;
739
740
if (irep.element == choice_DigestRepInner_error) {
741
ret = irep.u.error.code;
742
krb5_set_error_message(context, ret,
743
N_("Digest response error: %s", ""),
744
irep.u.error.reason);
745
goto out;
746
}
747
748
if (irep.element != choice_DigestRepInner_response) {
749
krb5_set_error_message(context, EINVAL,
750
N_("digest reply not an DigestResponse", ""));
751
ret = EINVAL;
752
goto out;
753
}
754
755
ret = copy_DigestResponse(&irep.u.response, &digest->response);
756
if (ret) {
757
krb5_set_error_message(context, ret,
758
N_("Failed to copy initReply,", ""));
759
goto out;
760
}
761
762
out:
763
free_DigestRepInner(&irep);
764
765
return ret;
766
}
767
768
KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
769
krb5_digest_rep_get_status(krb5_context context,
770
krb5_digest digest)
771
{
772
return digest->response.success ? TRUE : FALSE;
773
}
774
775
KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL
776
krb5_digest_get_rsp(krb5_context context,
777
krb5_digest digest)
778
{
779
if (digest->response.rsp == NULL)
780
return NULL;
781
return *digest->response.rsp;
782
}
783
784
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
785
krb5_digest_get_tickets(krb5_context context,
786
krb5_digest digest,
787
Ticket **tickets)
788
{
789
*tickets = NULL;
790
return 0;
791
}
792
793
794
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
795
krb5_digest_get_client_binding(krb5_context context,
796
krb5_digest digest,
797
char **type,
798
char **binding)
799
{
800
if (digest->response.channel) {
801
*type = strdup(digest->response.channel->cb_type);
802
*binding = strdup(digest->response.channel->cb_binding);
803
if (*type == NULL || *binding == NULL) {
804
free(*type);
805
free(*binding);
806
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
807
return ENOMEM;
808
}
809
} else {
810
*type = NULL;
811
*binding = NULL;
812
}
813
return 0;
814
}
815
816
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
817
krb5_digest_get_session_key(krb5_context context,
818
krb5_digest digest,
819
krb5_data *data)
820
{
821
krb5_error_code ret;
822
823
krb5_data_zero(data);
824
if (digest->response.session_key == NULL)
825
return 0;
826
ret = der_copy_octet_string(digest->response.session_key, data);
827
if (ret)
828
krb5_clear_error_message(context);
829
830
return ret;
831
}
832
833
struct krb5_ntlm_data {
834
NTLMInit init;
835
NTLMInitReply initReply;
836
NTLMRequest request;
837
NTLMResponse response;
838
};
839
840
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
841
krb5_ntlm_alloc(krb5_context context,
842
krb5_ntlm *ntlm)
843
{
844
*ntlm = calloc(1, sizeof(**ntlm));
845
if (*ntlm == NULL) {
846
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
847
return ENOMEM;
848
}
849
return 0;
850
}
851
852
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
853
krb5_ntlm_free(krb5_context context, krb5_ntlm ntlm)
854
{
855
free_NTLMInit(&ntlm->init);
856
free_NTLMInitReply(&ntlm->initReply);
857
free_NTLMRequest(&ntlm->request);
858
free_NTLMResponse(&ntlm->response);
859
memset(ntlm, 0, sizeof(*ntlm));
860
free(ntlm);
861
return 0;
862
}
863
864
865
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
866
krb5_ntlm_init_request(krb5_context context,
867
krb5_ntlm ntlm,
868
krb5_realm realm,
869
krb5_ccache ccache,
870
uint32_t flags,
871
const char *hostname,
872
const char *domainname)
873
{
874
DigestReqInner ireq;
875
DigestRepInner irep;
876
krb5_error_code ret;
877
878
memset(&ireq, 0, sizeof(ireq));
879
memset(&irep, 0, sizeof(irep));
880
881
ntlm->init.flags = flags;
882
if (hostname) {
883
ALLOC(ntlm->init.hostname, 1);
884
*ntlm->init.hostname = strdup(hostname);
885
}
886
if (domainname) {
887
ALLOC(ntlm->init.domain, 1);
888
*ntlm->init.domain = strdup(domainname);
889
}
890
891
ireq.element = choice_DigestReqInner_ntlmInit;
892
ireq.u.ntlmInit = ntlm->init;
893
894
ret = digest_request(context, realm, ccache,
895
KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
896
if (ret)
897
goto out;
898
899
if (irep.element == choice_DigestRepInner_error) {
900
ret = irep.u.error.code;
901
krb5_set_error_message(context, ret, N_("Digest init error: %s", ""),
902
irep.u.error.reason);
903
goto out;
904
}
905
906
if (irep.element != choice_DigestRepInner_ntlmInitReply) {
907
ret = EINVAL;
908
krb5_set_error_message(context, ret,
909
N_("ntlm reply not an initReply", ""));
910
goto out;
911
}
912
913
ret = copy_NTLMInitReply(&irep.u.ntlmInitReply, &ntlm->initReply);
914
if (ret) {
915
krb5_set_error_message(context, ret,
916
N_("Failed to copy initReply", ""));
917
goto out;
918
}
919
920
out:
921
free_DigestRepInner(&irep);
922
923
return ret;
924
}
925
926
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
927
krb5_ntlm_init_get_flags(krb5_context context,
928
krb5_ntlm ntlm,
929
uint32_t *flags)
930
{
931
*flags = ntlm->initReply.flags;
932
return 0;
933
}
934
935
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
936
krb5_ntlm_init_get_challange(krb5_context context,
937
krb5_ntlm ntlm,
938
krb5_data *challange)
939
{
940
krb5_error_code ret;
941
942
ret = der_copy_octet_string(&ntlm->initReply.challange, challange);
943
if (ret)
944
krb5_clear_error_message(context);
945
946
return ret;
947
}
948
949
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
950
krb5_ntlm_init_get_opaque(krb5_context context,
951
krb5_ntlm ntlm,
952
krb5_data *opaque)
953
{
954
krb5_error_code ret;
955
956
ret = der_copy_octet_string(&ntlm->initReply.opaque, opaque);
957
if (ret)
958
krb5_clear_error_message(context);
959
960
return ret;
961
}
962
963
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
964
krb5_ntlm_init_get_targetname(krb5_context context,
965
krb5_ntlm ntlm,
966
char **name)
967
{
968
*name = strdup(ntlm->initReply.targetname);
969
if (*name == NULL) {
970
krb5_clear_error_message(context);
971
return ENOMEM;
972
}
973
return 0;
974
}
975
976
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
977
krb5_ntlm_init_get_targetinfo(krb5_context context,
978
krb5_ntlm ntlm,
979
krb5_data *data)
980
{
981
krb5_error_code ret;
982
983
if (ntlm->initReply.targetinfo == NULL) {
984
krb5_data_zero(data);
985
return 0;
986
}
987
988
ret = krb5_data_copy(data,
989
ntlm->initReply.targetinfo->data,
990
ntlm->initReply.targetinfo->length);
991
if (ret) {
992
krb5_clear_error_message(context);
993
return ret;
994
}
995
return 0;
996
}
997
998
999
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1000
krb5_ntlm_request(krb5_context context,
1001
krb5_ntlm ntlm,
1002
krb5_realm realm,
1003
krb5_ccache ccache)
1004
{
1005
DigestReqInner ireq;
1006
DigestRepInner irep;
1007
krb5_error_code ret;
1008
1009
memset(&ireq, 0, sizeof(ireq));
1010
memset(&irep, 0, sizeof(irep));
1011
1012
ireq.element = choice_DigestReqInner_ntlmRequest;
1013
ireq.u.ntlmRequest = ntlm->request;
1014
1015
ret = digest_request(context, realm, ccache,
1016
KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
1017
if (ret)
1018
return ret;
1019
1020
if (irep.element == choice_DigestRepInner_error) {
1021
ret = irep.u.error.code;
1022
krb5_set_error_message(context, ret,
1023
N_("NTLM response error: %s", ""),
1024
irep.u.error.reason);
1025
goto out;
1026
}
1027
1028
if (irep.element != choice_DigestRepInner_ntlmResponse) {
1029
ret = EINVAL;
1030
krb5_set_error_message(context, ret,
1031
N_("NTLM reply not an NTLMResponse", ""));
1032
goto out;
1033
}
1034
1035
ret = copy_NTLMResponse(&irep.u.ntlmResponse, &ntlm->response);
1036
if (ret) {
1037
krb5_set_error_message(context, ret,
1038
N_("Failed to copy NTLMResponse", ""));
1039
goto out;
1040
}
1041
1042
out:
1043
free_DigestRepInner(&irep);
1044
1045
return ret;
1046
}
1047
1048
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1049
krb5_ntlm_req_set_flags(krb5_context context,
1050
krb5_ntlm ntlm,
1051
uint32_t flags)
1052
{
1053
ntlm->request.flags = flags;
1054
return 0;
1055
}
1056
1057
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1058
krb5_ntlm_req_set_username(krb5_context context,
1059
krb5_ntlm ntlm,
1060
const char *username)
1061
{
1062
ntlm->request.username = strdup(username);
1063
if (ntlm->request.username == NULL) {
1064
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1065
return ENOMEM;
1066
}
1067
return 0;
1068
}
1069
1070
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1071
krb5_ntlm_req_set_targetname(krb5_context context,
1072
krb5_ntlm ntlm,
1073
const char *targetname)
1074
{
1075
ntlm->request.targetname = strdup(targetname);
1076
if (ntlm->request.targetname == NULL) {
1077
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1078
return ENOMEM;
1079
}
1080
return 0;
1081
}
1082
1083
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1084
krb5_ntlm_req_set_lm(krb5_context context,
1085
krb5_ntlm ntlm,
1086
void *hash, size_t len)
1087
{
1088
ntlm->request.lm.data = malloc(len);
1089
if (ntlm->request.lm.data == NULL && len != 0) {
1090
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1091
return ENOMEM;
1092
}
1093
ntlm->request.lm.length = len;
1094
memcpy(ntlm->request.lm.data, hash, len);
1095
return 0;
1096
}
1097
1098
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1099
krb5_ntlm_req_set_ntlm(krb5_context context,
1100
krb5_ntlm ntlm,
1101
void *hash, size_t len)
1102
{
1103
ntlm->request.ntlm.data = malloc(len);
1104
if (ntlm->request.ntlm.data == NULL && len != 0) {
1105
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1106
return ENOMEM;
1107
}
1108
ntlm->request.ntlm.length = len;
1109
memcpy(ntlm->request.ntlm.data, hash, len);
1110
return 0;
1111
}
1112
1113
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1114
krb5_ntlm_req_set_opaque(krb5_context context,
1115
krb5_ntlm ntlm,
1116
krb5_data *opaque)
1117
{
1118
ntlm->request.opaque.data = malloc(opaque->length);
1119
if (ntlm->request.opaque.data == NULL && opaque->length != 0) {
1120
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1121
return ENOMEM;
1122
}
1123
ntlm->request.opaque.length = opaque->length;
1124
memcpy(ntlm->request.opaque.data, opaque->data, opaque->length);
1125
return 0;
1126
}
1127
1128
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1129
krb5_ntlm_req_set_session(krb5_context context,
1130
krb5_ntlm ntlm,
1131
void *sessionkey, size_t length)
1132
{
1133
ntlm->request.sessionkey = calloc(1, sizeof(*ntlm->request.sessionkey));
1134
if (ntlm->request.sessionkey == NULL) {
1135
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1136
return ENOMEM;
1137
}
1138
ntlm->request.sessionkey->data = malloc(length);
1139
if (ntlm->request.sessionkey->data == NULL && length != 0) {
1140
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1141
return ENOMEM;
1142
}
1143
memcpy(ntlm->request.sessionkey->data, sessionkey, length);
1144
ntlm->request.sessionkey->length = length;
1145
return 0;
1146
}
1147
1148
KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1149
krb5_ntlm_rep_get_status(krb5_context context,
1150
krb5_ntlm ntlm)
1151
{
1152
return ntlm->response.success ? TRUE : FALSE;
1153
}
1154
1155
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1156
krb5_ntlm_rep_get_sessionkey(krb5_context context,
1157
krb5_ntlm ntlm,
1158
krb5_data *data)
1159
{
1160
if (ntlm->response.sessionkey == NULL) {
1161
krb5_set_error_message(context, EINVAL,
1162
N_("no ntlm session key", ""));
1163
return EINVAL;
1164
}
1165
krb5_clear_error_message(context);
1166
return krb5_data_copy(data,
1167
ntlm->response.sessionkey->data,
1168
ntlm->response.sessionkey->length);
1169
}
1170
1171
/**
1172
* Get the supported/allowed mechanism for this principal.
1173
*
1174
* @param context A Keberos context.
1175
* @param realm The realm of the KDC.
1176
* @param ccache The credential cache to use when talking to the KDC.
1177
* @param flags The supported mechanism.
1178
*
1179
* @return Return an error code or 0.
1180
*
1181
* @ingroup krb5_digest
1182
*/
1183
1184
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1185
krb5_digest_probe(krb5_context context,
1186
krb5_realm realm,
1187
krb5_ccache ccache,
1188
unsigned *flags)
1189
{
1190
DigestReqInner ireq;
1191
DigestRepInner irep;
1192
krb5_error_code ret;
1193
1194
memset(&ireq, 0, sizeof(ireq));
1195
memset(&irep, 0, sizeof(irep));
1196
1197
ireq.element = choice_DigestReqInner_supportedMechs;
1198
1199
ret = digest_request(context, realm, ccache,
1200
KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
1201
if (ret)
1202
goto out;
1203
1204
if (irep.element == choice_DigestRepInner_error) {
1205
ret = irep.u.error.code;
1206
krb5_set_error_message(context, ret, "Digest probe error: %s",
1207
irep.u.error.reason);
1208
goto out;
1209
}
1210
1211
if (irep.element != choice_DigestRepInner_supportedMechs) {
1212
ret = EINVAL;
1213
krb5_set_error_message(context, ret, "Digest reply not an probe");
1214
goto out;
1215
}
1216
1217
*flags = DigestTypes2int(irep.u.supportedMechs);
1218
1219
out:
1220
free_DigestRepInner(&irep);
1221
1222
return ret;
1223
}
1224
1225
#endif /* HEIMDAL_SMALLER */
1226
1227