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