Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/lib/gssapi/generic/oid_ops.c
39562 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* lib/gssapi/generic/oid_ops.c */
3
/*
4
* Copyright 1995 by the Massachusetts Institute of Technology.
5
* All Rights Reserved.
6
*
7
* Export of this software from the United States of America may
8
* require a specific license from the United States Government.
9
* It is the responsibility of any person or organization contemplating
10
* export to obtain such a license before exporting.
11
*
12
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13
* distribute this software and its documentation for any purpose and
14
* without fee is hereby granted, provided that the above copyright
15
* notice appear in all copies and that both that copyright notice and
16
* this permission notice appear in supporting documentation, and that
17
* the name of M.I.T. not be used in advertising or publicity pertaining
18
* to distribution of the software without specific, written prior
19
* permission. Furthermore if you modify this software you must label
20
* your software as modified software and not distribute it in such a
21
* fashion that it might be confused with the original M.I.T. software.
22
* M.I.T. makes no representations about the suitability of
23
* this software for any purpose. It is provided "as is" without express
24
* or implied warranty.
25
*/
26
/*
27
* Copyright 1993 by OpenVision Technologies, Inc.
28
*
29
* Permission to use, copy, modify, distribute, and sell this software
30
* and its documentation for any purpose is hereby granted without fee,
31
* provided that the above copyright notice appears in all copies and
32
* that both that copyright notice and this permission notice appear in
33
* supporting documentation, and that the name of OpenVision not be used
34
* in advertising or publicity pertaining to distribution of the software
35
* without specific, written prior permission. OpenVision makes no
36
* representations about the suitability of this software for any
37
* purpose. It is provided "as is" without express or implied warranty.
38
*
39
* OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
40
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
41
* EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
42
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
43
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
44
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
45
* PERFORMANCE OF THIS SOFTWARE.
46
*/
47
48
/* GSS-API V2 interfaces to manipulate OIDs */
49
50
#include "gssapiP_generic.h"
51
#ifdef HAVE_UNISTD_H
52
#include <unistd.h>
53
#endif
54
#include <stdlib.h>
55
#include <string.h>
56
#include <stdio.h>
57
#include <gssapi/gssapi_generic.h>
58
#include <errno.h>
59
#include <ctype.h>
60
61
/*
62
* The functions for allocating and releasing individual OIDs use malloc and
63
* free instead of the gssalloc wrappers, because the mechglue currently mixes
64
* generic_gss_copy_oid() with hand-freeing of OIDs. We do not need to free
65
* free OIDs allocated by mechanisms, so this should not be a problem.
66
*/
67
68
OM_uint32
69
generic_gss_release_oid(OM_uint32 *minor_status, gss_OID *oid)
70
{
71
*minor_status = 0;
72
73
if (oid == NULL || *oid == GSS_C_NO_OID)
74
return(GSS_S_COMPLETE);
75
76
/*
77
* The V2 API says the following!
78
*
79
* gss_release_oid[()] will recognize any of the GSSAPI's own OID values,
80
* and will silently ignore attempts to free these OIDs; for other OIDs
81
* it will call the C free() routine for both the OID data and the
82
* descriptor. This allows applications to freely mix their own heap-
83
* allocated OID values with OIDs returned by GSS-API.
84
*/
85
86
/*
87
* We use the official OID definitions instead of the unofficial OID
88
* definitions. But we continue to support the unofficial OID
89
* gss_nt_service_name just in case if some gss applications use
90
* the old OID.
91
*/
92
93
if ((*oid != GSS_C_NT_USER_NAME) &&
94
(*oid != GSS_C_NT_MACHINE_UID_NAME) &&
95
(*oid != GSS_C_NT_STRING_UID_NAME) &&
96
(*oid != GSS_C_NT_HOSTBASED_SERVICE) &&
97
(*oid != GSS_C_NT_ANONYMOUS) &&
98
(*oid != GSS_C_NT_EXPORT_NAME) &&
99
(*oid != GSS_C_NT_COMPOSITE_EXPORT) &&
100
(*oid != gss_nt_service_name)) {
101
free((*oid)->elements);
102
free(*oid);
103
}
104
*oid = GSS_C_NO_OID;
105
return(GSS_S_COMPLETE);
106
}
107
108
OM_uint32
109
generic_gss_copy_oid(OM_uint32 *minor_status,
110
const gss_OID_desc * const oid,
111
gss_OID *new_oid)
112
{
113
gss_OID p;
114
115
*minor_status = 0;
116
117
p = (gss_OID) malloc(sizeof(gss_OID_desc));
118
if (!p) {
119
*minor_status = ENOMEM;
120
return GSS_S_FAILURE;
121
}
122
p->length = oid->length;
123
p->elements = malloc(p->length);
124
if (!p->elements) {
125
free(p);
126
return GSS_S_FAILURE;
127
}
128
memcpy(p->elements, oid->elements, p->length);
129
*new_oid = p;
130
return(GSS_S_COMPLETE);
131
}
132
133
134
OM_uint32
135
generic_gss_create_empty_oid_set(OM_uint32 *minor_status, gss_OID_set *oid_set)
136
{
137
*minor_status = 0;
138
139
if (oid_set == NULL)
140
return GSS_S_CALL_INACCESSIBLE_WRITE;
141
142
if ((*oid_set = (gss_OID_set) gssalloc_malloc(sizeof(gss_OID_set_desc)))) {
143
memset(*oid_set, 0, sizeof(gss_OID_set_desc));
144
return(GSS_S_COMPLETE);
145
}
146
else {
147
*minor_status = ENOMEM;
148
return(GSS_S_FAILURE);
149
}
150
}
151
152
OM_uint32
153
generic_gss_add_oid_set_member(OM_uint32 *minor_status,
154
const gss_OID_desc * const member_oid,
155
gss_OID_set *oid_set)
156
{
157
gss_OID elist;
158
gss_OID lastel;
159
160
*minor_status = 0;
161
162
if (member_oid == NULL || member_oid->length == 0 ||
163
member_oid->elements == NULL)
164
return (GSS_S_CALL_INACCESSIBLE_READ);
165
166
if (oid_set == NULL)
167
return GSS_S_CALL_INACCESSIBLE_WRITE;
168
169
elist = (*oid_set)->elements;
170
/* Get an enlarged copy of the array */
171
if (((*oid_set)->elements = (gss_OID) gssalloc_malloc(((*oid_set)->count+1) *
172
sizeof(gss_OID_desc)))) {
173
/* Copy in the old junk */
174
if (elist)
175
memcpy((*oid_set)->elements,
176
elist,
177
((*oid_set)->count * sizeof(gss_OID_desc)));
178
179
/* Duplicate the input element */
180
lastel = &(*oid_set)->elements[(*oid_set)->count];
181
if ((lastel->elements =
182
(void *) gssalloc_malloc((size_t) member_oid->length))) {
183
/* Success - copy elements */
184
memcpy(lastel->elements, member_oid->elements,
185
(size_t) member_oid->length);
186
/* Set length */
187
lastel->length = member_oid->length;
188
189
/* Update count */
190
(*oid_set)->count++;
191
if (elist)
192
gssalloc_free(elist);
193
*minor_status = 0;
194
return(GSS_S_COMPLETE);
195
}
196
else
197
gssalloc_free((*oid_set)->elements);
198
}
199
/* Failure - restore old contents of list */
200
(*oid_set)->elements = elist;
201
*minor_status = ENOMEM;
202
return(GSS_S_FAILURE);
203
}
204
205
OM_uint32
206
generic_gss_test_oid_set_member(OM_uint32 *minor_status,
207
const gss_OID_desc * const member,
208
gss_OID_set set,
209
int * present)
210
{
211
OM_uint32 i;
212
int result;
213
214
*minor_status = 0;
215
216
if (member == NULL || set == NULL)
217
return (GSS_S_CALL_INACCESSIBLE_READ);
218
219
if (present == NULL)
220
return (GSS_S_CALL_INACCESSIBLE_WRITE);
221
222
result = 0;
223
for (i=0; i<set->count; i++) {
224
if ((set->elements[i].length == member->length) &&
225
!memcmp(set->elements[i].elements,
226
member->elements,
227
(size_t) member->length)) {
228
result = 1;
229
break;
230
}
231
}
232
*present = result;
233
return(GSS_S_COMPLETE);
234
}
235
236
OM_uint32
237
generic_gss_oid_to_str(OM_uint32 *minor_status,
238
const gss_OID_desc * const oid,
239
gss_buffer_t oid_str)
240
{
241
unsigned long number, n;
242
OM_uint32 i;
243
int first;
244
unsigned char *cp;
245
struct k5buf buf;
246
247
*minor_status = 0;
248
249
if (oid_str != GSS_C_NO_BUFFER) {
250
oid_str->length = 0;
251
oid_str->value = NULL;
252
}
253
254
if (oid == NULL || oid->length == 0 || oid->elements == NULL)
255
return (GSS_S_CALL_INACCESSIBLE_READ);
256
257
if (oid_str == GSS_C_NO_BUFFER)
258
return (GSS_S_CALL_INACCESSIBLE_WRITE);
259
260
/* Decoded according to krb5/gssapi_krb5.c */
261
262
cp = (unsigned char *) oid->elements;
263
number = (unsigned long) cp[0];
264
k5_buf_init_dynamic(&buf);
265
k5_buf_add(&buf, "{ ");
266
number = 0;
267
cp = (unsigned char *) oid->elements;
268
first = 1;
269
for (i = 0; i < oid->length; i++) {
270
number = (number << 7) | (cp[i] & 0x7f);
271
if ((cp[i] & 0x80) == 0) {
272
if (first) {
273
n = (number < 40) ? 0 : (number < 80) ? 1 : 2;
274
k5_buf_add_fmt(&buf, "%lu %lu ", n, number - (n * 40));
275
first = 0;
276
} else {
277
k5_buf_add_fmt(&buf, "%lu ", number);
278
}
279
number = 0;
280
}
281
}
282
k5_buf_add_len(&buf, "}\0", 2);
283
return k5buf_to_gss(minor_status, &buf, oid_str);
284
}
285
286
/* Return the length of a DER OID subidentifier encoding. */
287
static size_t
288
arc_encoded_length(unsigned long arc)
289
{
290
size_t len = 1;
291
292
for (arc >>= 7; arc; arc >>= 7)
293
len++;
294
return len;
295
}
296
297
/* Encode a subidentifier into *bufp and advance it to the encoding's end. */
298
static void
299
arc_encode(unsigned long arc, unsigned char **bufp)
300
{
301
unsigned char *p;
302
303
/* Advance to the end and encode backwards. */
304
p = *bufp = *bufp + arc_encoded_length(arc);
305
*--p = arc & 0x7f;
306
for (arc >>= 7; arc; arc >>= 7)
307
*--p = (arc & 0x7f) | 0x80;
308
}
309
310
/* Fetch an arc value from *bufp and advance past it and any following spaces
311
* or periods. Return 1 on success, 0 if *bufp is not at a valid arc value. */
312
static int
313
get_arc(const unsigned char **bufp, const unsigned char *end,
314
unsigned long *arc_out)
315
{
316
const unsigned char *p = *bufp;
317
unsigned long arc = 0, newval;
318
319
if (p == end || !isdigit(*p))
320
return 0;
321
for (; p < end && isdigit(*p); p++) {
322
newval = arc * 10 + (*p - '0');
323
if (newval < arc)
324
return 0;
325
arc = newval;
326
}
327
while (p < end && (isspace(*p) || *p == '.'))
328
p++;
329
*bufp = p;
330
*arc_out = arc;
331
return 1;
332
}
333
334
/*
335
* Convert a sequence of two or more decimal arc values into a DER-encoded OID.
336
* The values may be separated by any combination of whitespace and period
337
* characters, and may be optionally surrounded with braces. Leading
338
* whitespace and trailing garbage is allowed. The first arc value must be 0,
339
* 1, or 2, and the second value must be less than 40 if the first value is not
340
* 2.
341
*/
342
OM_uint32
343
generic_gss_str_to_oid(OM_uint32 *minor_status,
344
gss_buffer_t oid_str,
345
gss_OID *oid_out)
346
{
347
const unsigned char *p, *end, *arc3_start;
348
unsigned char *out;
349
unsigned long arc, arc1, arc2;
350
size_t nbytes;
351
int brace = 0;
352
gss_OID oid;
353
354
*minor_status = 0;
355
356
if (oid_out != NULL)
357
*oid_out = GSS_C_NO_OID;
358
359
if (GSS_EMPTY_BUFFER(oid_str))
360
return (GSS_S_CALL_INACCESSIBLE_READ);
361
362
if (oid_out == NULL)
363
return (GSS_S_CALL_INACCESSIBLE_WRITE);
364
365
/* Skip past initial spaces and, optionally, an open brace. */
366
brace = 0;
367
p = oid_str->value;
368
end = p + oid_str->length;
369
while (p < end && isspace(*p))
370
p++;
371
if (p < end && *p == '{') {
372
brace = 1;
373
p++;
374
}
375
while (p < end && isspace(*p))
376
p++;
377
378
/* Get the first two arc values, to be encoded as one subidentifier. */
379
if (!get_arc(&p, end, &arc1) || !get_arc(&p, end, &arc2))
380
return (GSS_S_FAILURE);
381
if (arc1 > 2 || (arc1 < 2 && arc2 > 39) || arc2 > ULONG_MAX - 80)
382
return (GSS_S_FAILURE);
383
arc3_start = p;
384
385
/* Compute the total length of the encoding while checking syntax. */
386
nbytes = arc_encoded_length(arc1 * 40 + arc2);
387
while (get_arc(&p, end, &arc))
388
nbytes += arc_encoded_length(arc);
389
if (brace && (p == end || *p != '}'))
390
return (GSS_S_FAILURE);
391
392
/* Allocate an oid structure. */
393
oid = malloc(sizeof(*oid));
394
if (oid == NULL)
395
return (GSS_S_FAILURE);
396
oid->elements = malloc(nbytes);
397
if (oid->elements == NULL) {
398
free(oid);
399
return (GSS_S_FAILURE);
400
}
401
oid->length = nbytes;
402
403
out = oid->elements;
404
arc_encode(arc1 * 40 + arc2, &out);
405
p = arc3_start;
406
while (get_arc(&p, end, &arc))
407
arc_encode(arc, &out);
408
assert(out - nbytes == oid->elements);
409
*oid_out = oid;
410
return(GSS_S_COMPLETE);
411
}
412
413
/* Compose an OID of a prefix and an integer suffix */
414
OM_uint32
415
generic_gss_oid_compose(OM_uint32 *minor_status,
416
const char *prefix,
417
size_t prefix_len,
418
int suffix,
419
gss_OID_desc *oid)
420
{
421
int osuffix, i;
422
size_t nbytes;
423
unsigned char *op;
424
425
if (oid == GSS_C_NO_OID) {
426
*minor_status = EINVAL;
427
return GSS_S_FAILURE;
428
}
429
if (oid->length < prefix_len) {
430
*minor_status = ERANGE;
431
return GSS_S_FAILURE;
432
}
433
434
memcpy(oid->elements, prefix, prefix_len);
435
436
nbytes = 0;
437
osuffix = suffix;
438
while (suffix) {
439
nbytes++;
440
suffix >>= 7;
441
}
442
suffix = osuffix;
443
444
if (oid->length < prefix_len + nbytes) {
445
*minor_status = ERANGE;
446
return GSS_S_FAILURE;
447
}
448
449
op = (unsigned char *) oid->elements + prefix_len + nbytes;
450
i = -1;
451
while (suffix) {
452
op[i] = (unsigned char)suffix & 0x7f;
453
if (i != -1)
454
op[i] |= 0x80;
455
i--;
456
suffix >>= 7;
457
}
458
459
oid->length = prefix_len + nbytes;
460
461
*minor_status = 0;
462
return GSS_S_COMPLETE;
463
}
464
465
OM_uint32
466
generic_gss_oid_decompose(OM_uint32 *minor_status,
467
const char *prefix,
468
size_t prefix_len,
469
gss_OID_desc *oid,
470
int *suffix)
471
{
472
size_t i, slen;
473
unsigned char *op;
474
475
if (oid->length < prefix_len ||
476
memcmp(oid->elements, prefix, prefix_len) != 0) {
477
return GSS_S_BAD_MECH;
478
}
479
480
op = (unsigned char *) oid->elements + prefix_len;
481
482
*suffix = 0;
483
484
slen = oid->length - prefix_len;
485
486
for (i = 0; i < slen; i++) {
487
*suffix = (*suffix << 7) | (op[i] & 0x7f);
488
if (i + 1 != slen && (op[i] & 0x80) == 0) {
489
*minor_status = EINVAL;
490
return GSS_S_FAILURE;
491
}
492
}
493
494
return GSS_S_COMPLETE;
495
}
496
497
OM_uint32
498
generic_gss_copy_oid_set(OM_uint32 *minor_status,
499
const gss_OID_set_desc * const oidset,
500
gss_OID_set *new_oidset)
501
{
502
gss_OID_set_desc *copy;
503
OM_uint32 minor = 0;
504
OM_uint32 major = GSS_S_COMPLETE;
505
OM_uint32 i;
506
507
if (minor_status != NULL)
508
*minor_status = 0;
509
510
if (new_oidset != NULL)
511
*new_oidset = GSS_C_NO_OID_SET;
512
513
if (oidset == GSS_C_NO_OID_SET)
514
return (GSS_S_CALL_INACCESSIBLE_READ);
515
516
if (new_oidset == NULL)
517
return (GSS_S_CALL_INACCESSIBLE_WRITE);
518
519
if ((copy = (gss_OID_set_desc *) gssalloc_calloc(1, sizeof (*copy))) == NULL) {
520
major = GSS_S_FAILURE;
521
goto done;
522
}
523
524
if ((copy->elements = (gss_OID_desc *)
525
gssalloc_calloc(oidset->count, sizeof (*copy->elements))) == NULL) {
526
major = GSS_S_FAILURE;
527
goto done;
528
}
529
copy->count = oidset->count;
530
531
for (i = 0; i < copy->count; i++) {
532
gss_OID_desc *out = &copy->elements[i];
533
gss_OID_desc *in = &oidset->elements[i];
534
535
if ((out->elements = (void *) gssalloc_malloc(in->length)) == NULL) {
536
major = GSS_S_FAILURE;
537
goto done;
538
}
539
(void) memcpy(out->elements, in->elements, in->length);
540
out->length = in->length;
541
}
542
543
*new_oidset = copy;
544
done:
545
if (major != GSS_S_COMPLETE) {
546
(void) generic_gss_release_oid_set(&minor, &copy);
547
}
548
549
return (major);
550
}
551
552