xref: /freebsd/crypto/krb5/src/lib/gssapi/generic/oid_ops.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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
generic_gss_release_oid(OM_uint32 * minor_status,gss_OID * oid)69 generic_gss_release_oid(OM_uint32 *minor_status, gss_OID *oid)
70 {
71     if (minor_status)
72         *minor_status = 0;
73 
74     if (oid == NULL || *oid == GSS_C_NO_OID)
75         return(GSS_S_COMPLETE);
76 
77     /*
78      * The V2 API says the following!
79      *
80      * gss_release_oid[()] will recognize any of the GSSAPI's own OID values,
81      * and will silently ignore attempts to free these OIDs; for other OIDs
82      * it will call the C free() routine for both the OID data and the
83      * descriptor.  This allows applications to freely mix their own heap-
84      * allocated OID values with OIDs returned by GSS-API.
85      */
86 
87     /*
88      * We use the official OID definitions instead of the unofficial OID
89      * definitions. But we continue to support the unofficial OID
90      * gss_nt_service_name just in case if some gss applications use
91      * the old OID.
92      */
93 
94     if ((*oid != GSS_C_NT_USER_NAME) &&
95         (*oid != GSS_C_NT_MACHINE_UID_NAME) &&
96         (*oid != GSS_C_NT_STRING_UID_NAME) &&
97         (*oid != GSS_C_NT_HOSTBASED_SERVICE) &&
98         (*oid != GSS_C_NT_ANONYMOUS) &&
99         (*oid != GSS_C_NT_EXPORT_NAME) &&
100         (*oid != GSS_C_NT_COMPOSITE_EXPORT) &&
101         (*oid != gss_nt_service_name)) {
102         free((*oid)->elements);
103         free(*oid);
104     }
105     *oid = GSS_C_NO_OID;
106     return(GSS_S_COMPLETE);
107 }
108 
109 OM_uint32
generic_gss_copy_oid(OM_uint32 * minor_status,const gss_OID_desc * const oid,gss_OID * new_oid)110 generic_gss_copy_oid(OM_uint32 *minor_status,
111                      const gss_OID_desc * const oid,
112                      gss_OID *new_oid)
113 {
114     gss_OID         p;
115 
116     *minor_status = 0;
117 
118     p = (gss_OID) malloc(sizeof(gss_OID_desc));
119     if (!p) {
120         *minor_status = ENOMEM;
121         return GSS_S_FAILURE;
122     }
123     p->length = oid->length;
124     p->elements = malloc(p->length);
125     if (!p->elements) {
126         free(p);
127         return GSS_S_FAILURE;
128     }
129     memcpy(p->elements, oid->elements, p->length);
130     *new_oid = p;
131     return(GSS_S_COMPLETE);
132 }
133 
134 
135 OM_uint32
generic_gss_create_empty_oid_set(OM_uint32 * minor_status,gss_OID_set * oid_set)136 generic_gss_create_empty_oid_set(OM_uint32 *minor_status, gss_OID_set *oid_set)
137 {
138     *minor_status = 0;
139 
140     if (oid_set == NULL)
141         return GSS_S_CALL_INACCESSIBLE_WRITE;
142 
143     if ((*oid_set = (gss_OID_set) gssalloc_malloc(sizeof(gss_OID_set_desc)))) {
144         memset(*oid_set, 0, sizeof(gss_OID_set_desc));
145         return(GSS_S_COMPLETE);
146     }
147     else {
148         *minor_status = ENOMEM;
149         return(GSS_S_FAILURE);
150     }
151 }
152 
153 OM_uint32
generic_gss_add_oid_set_member(OM_uint32 * minor_status,const gss_OID_desc * const member_oid,gss_OID_set * oid_set)154 generic_gss_add_oid_set_member(OM_uint32 *minor_status,
155                                const gss_OID_desc * const member_oid,
156                                gss_OID_set *oid_set)
157 {
158     gss_OID     elist;
159     gss_OID     lastel;
160 
161     *minor_status = 0;
162 
163     if (member_oid == NULL || member_oid->length == 0 ||
164         member_oid->elements == NULL)
165         return (GSS_S_CALL_INACCESSIBLE_READ);
166 
167     if (oid_set == NULL)
168         return GSS_S_CALL_INACCESSIBLE_WRITE;
169 
170     elist = (*oid_set)->elements;
171     /* Get an enlarged copy of the array */
172     if (((*oid_set)->elements = (gss_OID) gssalloc_malloc(((*oid_set)->count+1) *
173                                                           sizeof(gss_OID_desc)))) {
174         /* Copy in the old junk */
175         if (elist)
176             memcpy((*oid_set)->elements,
177                    elist,
178                    ((*oid_set)->count * sizeof(gss_OID_desc)));
179 
180         /* Duplicate the input element */
181         lastel = &(*oid_set)->elements[(*oid_set)->count];
182         if ((lastel->elements =
183              (void *) gssalloc_malloc((size_t) member_oid->length))) {
184             /* Success - copy elements */
185             memcpy(lastel->elements, member_oid->elements,
186                    (size_t) member_oid->length);
187             /* Set length */
188             lastel->length = member_oid->length;
189 
190             /* Update count */
191             (*oid_set)->count++;
192             if (elist)
193                 gssalloc_free(elist);
194             *minor_status = 0;
195             return(GSS_S_COMPLETE);
196         }
197         else
198             gssalloc_free((*oid_set)->elements);
199     }
200     /* Failure - restore old contents of list */
201     (*oid_set)->elements = elist;
202     *minor_status = ENOMEM;
203     return(GSS_S_FAILURE);
204 }
205 
206 OM_uint32
generic_gss_test_oid_set_member(OM_uint32 * minor_status,const gss_OID_desc * const member,gss_OID_set set,int * present)207 generic_gss_test_oid_set_member(OM_uint32 *minor_status,
208                                 const gss_OID_desc * const member,
209                                 gss_OID_set set,
210                                 int * present)
211 {
212     OM_uint32   i;
213     int         result;
214 
215     *minor_status = 0;
216 
217     if (member == NULL || set == NULL)
218         return (GSS_S_CALL_INACCESSIBLE_READ);
219 
220     if (present == NULL)
221         return (GSS_S_CALL_INACCESSIBLE_WRITE);
222 
223     result = 0;
224     for (i=0; i<set->count; i++) {
225         if ((set->elements[i].length == member->length) &&
226             !memcmp(set->elements[i].elements,
227                     member->elements,
228                     (size_t) member->length)) {
229             result = 1;
230             break;
231         }
232     }
233     *present = result;
234     return(GSS_S_COMPLETE);
235 }
236 
237 OM_uint32
generic_gss_oid_to_str(OM_uint32 * minor_status,const gss_OID_desc * const oid,gss_buffer_t oid_str)238 generic_gss_oid_to_str(OM_uint32 *minor_status,
239                        const gss_OID_desc * const oid,
240                        gss_buffer_t oid_str)
241 {
242     unsigned long       number, n;
243     OM_uint32           i;
244     int                 first;
245     unsigned char       *cp;
246     struct k5buf        buf;
247 
248     if (minor_status != NULL)
249         *minor_status = 0;
250 
251     if (oid_str != GSS_C_NO_BUFFER) {
252         oid_str->length = 0;
253         oid_str->value = NULL;
254     }
255 
256     if (oid == NULL || oid->length == 0 || oid->elements == NULL)
257         return (GSS_S_CALL_INACCESSIBLE_READ);
258 
259     if (oid_str == GSS_C_NO_BUFFER)
260         return (GSS_S_CALL_INACCESSIBLE_WRITE);
261 
262     /* Decoded according to krb5/gssapi_krb5.c */
263 
264     cp = (unsigned char *) oid->elements;
265     number = (unsigned long) cp[0];
266     k5_buf_init_dynamic(&buf);
267     k5_buf_add(&buf, "{ ");
268     number = 0;
269     cp = (unsigned char *) oid->elements;
270     first = 1;
271     for (i = 0; i < oid->length; i++) {
272         number = (number << 7) | (cp[i] & 0x7f);
273         if ((cp[i] & 0x80) == 0) {
274             if (first) {
275                 n = (number < 40) ? 0 : (number < 80) ? 1 : 2;
276                 k5_buf_add_fmt(&buf, "%lu %lu ", n, number - (n * 40));
277                 first = 0;
278             } else {
279                 k5_buf_add_fmt(&buf, "%lu ", number);
280             }
281             number = 0;
282         }
283     }
284     k5_buf_add_len(&buf, "}\0", 2);
285     return k5buf_to_gss(minor_status, &buf, oid_str);
286 }
287 
288 /* Return the length of a DER OID subidentifier encoding. */
289 static size_t
arc_encoded_length(unsigned long arc)290 arc_encoded_length(unsigned long arc)
291 {
292     size_t len = 1;
293 
294     for (arc >>= 7; arc; arc >>= 7)
295         len++;
296     return len;
297 }
298 
299 /* Encode a subidentifier into *bufp and advance it to the encoding's end. */
300 static void
arc_encode(unsigned long arc,unsigned char ** bufp)301 arc_encode(unsigned long arc, unsigned char **bufp)
302 {
303     unsigned char *p;
304 
305     /* Advance to the end and encode backwards. */
306     p = *bufp = *bufp + arc_encoded_length(arc);
307     *--p = arc & 0x7f;
308     for (arc >>= 7; arc; arc >>= 7)
309         *--p = (arc & 0x7f) | 0x80;
310 }
311 
312 /* Fetch an arc value from *bufp and advance past it and any following spaces
313  * or periods.  Return 1 on success, 0 if *bufp is not at a valid arc value. */
314 static int
get_arc(const unsigned char ** bufp,const unsigned char * end,unsigned long * arc_out)315 get_arc(const unsigned char **bufp, const unsigned char *end,
316         unsigned long *arc_out)
317 {
318     const unsigned char *p = *bufp;
319     unsigned long arc = 0, newval;
320 
321     if (p == end || !isdigit(*p))
322         return 0;
323     for (; p < end && isdigit(*p); p++) {
324         newval = arc * 10 + (*p - '0');
325         if (newval < arc)
326             return 0;
327         arc = newval;
328     }
329     while (p < end && (isspace(*p) || *p == '.'))
330         p++;
331     *bufp = p;
332     *arc_out = arc;
333     return 1;
334 }
335 
336 /*
337  * Convert a sequence of two or more decimal arc values into a DER-encoded OID.
338  * The values may be separated by any combination of whitespace and period
339  * characters, and may be optionally surrounded with braces.  Leading
340  * whitespace and trailing garbage is allowed.  The first arc value must be 0,
341  * 1, or 2, and the second value must be less than 40 if the first value is not
342  * 2.
343  */
344 OM_uint32
generic_gss_str_to_oid(OM_uint32 * minor_status,gss_buffer_t oid_str,gss_OID * oid_out)345 generic_gss_str_to_oid(OM_uint32 *minor_status,
346                        gss_buffer_t oid_str,
347                        gss_OID *oid_out)
348 {
349     const unsigned char *p, *end, *arc3_start;
350     unsigned char *out;
351     unsigned long arc, arc1, arc2;
352     size_t nbytes;
353     int brace = 0;
354     gss_OID oid;
355 
356     if (minor_status != NULL)
357         *minor_status = 0;
358 
359     if (oid_out != NULL)
360         *oid_out = GSS_C_NO_OID;
361 
362     if (GSS_EMPTY_BUFFER(oid_str))
363         return (GSS_S_CALL_INACCESSIBLE_READ);
364 
365     if (oid_out == NULL)
366         return (GSS_S_CALL_INACCESSIBLE_WRITE);
367 
368     /* Skip past initial spaces and, optionally, an open brace. */
369     brace = 0;
370     p = oid_str->value;
371     end = p + oid_str->length;
372     while (p < end && isspace(*p))
373         p++;
374     if (p < end && *p == '{') {
375         brace = 1;
376         p++;
377     }
378     while (p < end && isspace(*p))
379         p++;
380 
381     /* Get the first two arc values, to be encoded as one subidentifier. */
382     if (!get_arc(&p, end, &arc1) || !get_arc(&p, end, &arc2))
383         return (GSS_S_FAILURE);
384     if (arc1 > 2 || (arc1 < 2 && arc2 > 39) || arc2 > ULONG_MAX - 80)
385         return (GSS_S_FAILURE);
386     arc3_start = p;
387 
388     /* Compute the total length of the encoding while checking syntax. */
389     nbytes = arc_encoded_length(arc1 * 40 + arc2);
390     while (get_arc(&p, end, &arc))
391         nbytes += arc_encoded_length(arc);
392     if (brace && (p == end || *p != '}'))
393         return (GSS_S_FAILURE);
394 
395     /* Allocate an oid structure. */
396     oid = malloc(sizeof(*oid));
397     if (oid == NULL)
398         return (GSS_S_FAILURE);
399     oid->elements = malloc(nbytes);
400     if (oid->elements == NULL) {
401         free(oid);
402         return (GSS_S_FAILURE);
403     }
404     oid->length = nbytes;
405 
406     out = oid->elements;
407     arc_encode(arc1 * 40 + arc2, &out);
408     p = arc3_start;
409     while (get_arc(&p, end, &arc))
410         arc_encode(arc, &out);
411     assert(out - nbytes == oid->elements);
412     *oid_out = oid;
413     return(GSS_S_COMPLETE);
414 }
415 
416 /* Compose an OID of a prefix and an integer suffix */
417 OM_uint32
generic_gss_oid_compose(OM_uint32 * minor_status,const char * prefix,size_t prefix_len,int suffix,gss_OID_desc * oid)418 generic_gss_oid_compose(OM_uint32 *minor_status,
419                         const char *prefix,
420                         size_t prefix_len,
421                         int suffix,
422                         gss_OID_desc *oid)
423 {
424     int osuffix, i;
425     size_t nbytes;
426     unsigned char *op;
427 
428     if (oid == GSS_C_NO_OID) {
429         *minor_status = EINVAL;
430         return GSS_S_FAILURE;
431     }
432     if (oid->length < prefix_len) {
433         *minor_status = ERANGE;
434         return GSS_S_FAILURE;
435     }
436 
437     memcpy(oid->elements, prefix, prefix_len);
438 
439     nbytes = 0;
440     osuffix = suffix;
441     while (suffix) {
442         nbytes++;
443         suffix >>= 7;
444     }
445     suffix = osuffix;
446 
447     if (oid->length < prefix_len + nbytes) {
448         *minor_status = ERANGE;
449         return GSS_S_FAILURE;
450     }
451 
452     op = (unsigned char *) oid->elements + prefix_len + nbytes;
453     i = -1;
454     while (suffix) {
455         op[i] = (unsigned char)suffix & 0x7f;
456         if (i != -1)
457             op[i] |= 0x80;
458         i--;
459         suffix >>= 7;
460     }
461 
462     oid->length = prefix_len + nbytes;
463 
464     *minor_status = 0;
465     return GSS_S_COMPLETE;
466 }
467 
468 OM_uint32
generic_gss_oid_decompose(OM_uint32 * minor_status,const char * prefix,size_t prefix_len,gss_OID_desc * oid,int * suffix)469 generic_gss_oid_decompose(OM_uint32 *minor_status,
470                           const char *prefix,
471                           size_t prefix_len,
472                           gss_OID_desc *oid,
473                           int *suffix)
474 {
475     size_t i, slen;
476     unsigned char *op;
477 
478     if (oid->length < prefix_len ||
479         memcmp(oid->elements, prefix, prefix_len) != 0) {
480         return GSS_S_BAD_MECH;
481     }
482 
483     op = (unsigned char *) oid->elements + prefix_len;
484 
485     *suffix = 0;
486 
487     slen = oid->length - prefix_len;
488 
489     for (i = 0; i < slen; i++) {
490         *suffix = (*suffix << 7) | (op[i] & 0x7f);
491         if (i + 1 != slen && (op[i] & 0x80) == 0) {
492             *minor_status = EINVAL;
493             return GSS_S_FAILURE;
494         }
495     }
496 
497     return GSS_S_COMPLETE;
498 }
499 
500 OM_uint32
generic_gss_copy_oid_set(OM_uint32 * minor_status,const gss_OID_set_desc * const oidset,gss_OID_set * new_oidset)501 generic_gss_copy_oid_set(OM_uint32 *minor_status,
502                          const gss_OID_set_desc * const oidset,
503                          gss_OID_set *new_oidset)
504 {
505     gss_OID_set_desc *copy;
506     OM_uint32 minor = 0;
507     OM_uint32 major = GSS_S_COMPLETE;
508     OM_uint32 i;
509 
510     if (minor_status != NULL)
511         *minor_status = 0;
512 
513     if (new_oidset != NULL)
514         *new_oidset = GSS_C_NO_OID_SET;
515 
516     if (oidset == GSS_C_NO_OID_SET)
517         return (GSS_S_CALL_INACCESSIBLE_READ);
518 
519     if (new_oidset == NULL)
520         return (GSS_S_CALL_INACCESSIBLE_WRITE);
521 
522     if ((copy = (gss_OID_set_desc *) gssalloc_calloc(1, sizeof (*copy))) == NULL) {
523         major = GSS_S_FAILURE;
524         goto done;
525     }
526 
527     if ((copy->elements = (gss_OID_desc *)
528          gssalloc_calloc(oidset->count, sizeof (*copy->elements))) == NULL) {
529         major = GSS_S_FAILURE;
530         goto done;
531     }
532     copy->count = oidset->count;
533 
534     for (i = 0; i < copy->count; i++) {
535         gss_OID_desc *out = &copy->elements[i];
536         gss_OID_desc *in = &oidset->elements[i];
537 
538         if ((out->elements = (void *) gssalloc_malloc(in->length)) == NULL) {
539             major = GSS_S_FAILURE;
540             goto done;
541         }
542         (void) memcpy(out->elements, in->elements, in->length);
543         out->length = in->length;
544     }
545 
546     *new_oidset = copy;
547 done:
548     if (major != GSS_S_COMPLETE) {
549         (void) generic_gss_release_oid_set(&minor, &copy);
550     }
551 
552     return (major);
553 }
554