Path: blob/main/crypto/krb5/src/lib/gssapi/generic/oid_ops.c
39562 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/* lib/gssapi/generic/oid_ops.c */2/*3* Copyright 1995 by the Massachusetts Institute of Technology.4* All Rights Reserved.5*6* Export of this software from the United States of America may7* require a specific license from the United States Government.8* It is the responsibility of any person or organization contemplating9* export to obtain such a license before exporting.10*11* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and12* distribute this software and its documentation for any purpose and13* without fee is hereby granted, provided that the above copyright14* notice appear in all copies and that both that copyright notice and15* this permission notice appear in supporting documentation, and that16* the name of M.I.T. not be used in advertising or publicity pertaining17* to distribution of the software without specific, written prior18* permission. Furthermore if you modify this software you must label19* your software as modified software and not distribute it in such a20* fashion that it might be confused with the original M.I.T. software.21* M.I.T. makes no representations about the suitability of22* this software for any purpose. It is provided "as is" without express23* or implied warranty.24*/25/*26* Copyright 1993 by OpenVision Technologies, Inc.27*28* Permission to use, copy, modify, distribute, and sell this software29* and its documentation for any purpose is hereby granted without fee,30* provided that the above copyright notice appears in all copies and31* that both that copyright notice and this permission notice appear in32* supporting documentation, and that the name of OpenVision not be used33* in advertising or publicity pertaining to distribution of the software34* without specific, written prior permission. OpenVision makes no35* representations about the suitability of this software for any36* purpose. It is provided "as is" without express or implied warranty.37*38* OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,39* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO40* EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR41* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF42* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR43* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR44* PERFORMANCE OF THIS SOFTWARE.45*/4647/* GSS-API V2 interfaces to manipulate OIDs */4849#include "gssapiP_generic.h"50#ifdef HAVE_UNISTD_H51#include <unistd.h>52#endif53#include <stdlib.h>54#include <string.h>55#include <stdio.h>56#include <gssapi/gssapi_generic.h>57#include <errno.h>58#include <ctype.h>5960/*61* The functions for allocating and releasing individual OIDs use malloc and62* free instead of the gssalloc wrappers, because the mechglue currently mixes63* generic_gss_copy_oid() with hand-freeing of OIDs. We do not need to free64* free OIDs allocated by mechanisms, so this should not be a problem.65*/6667OM_uint3268generic_gss_release_oid(OM_uint32 *minor_status, gss_OID *oid)69{70*minor_status = 0;7172if (oid == NULL || *oid == GSS_C_NO_OID)73return(GSS_S_COMPLETE);7475/*76* The V2 API says the following!77*78* gss_release_oid[()] will recognize any of the GSSAPI's own OID values,79* and will silently ignore attempts to free these OIDs; for other OIDs80* it will call the C free() routine for both the OID data and the81* descriptor. This allows applications to freely mix their own heap-82* allocated OID values with OIDs returned by GSS-API.83*/8485/*86* We use the official OID definitions instead of the unofficial OID87* definitions. But we continue to support the unofficial OID88* gss_nt_service_name just in case if some gss applications use89* the old OID.90*/9192if ((*oid != GSS_C_NT_USER_NAME) &&93(*oid != GSS_C_NT_MACHINE_UID_NAME) &&94(*oid != GSS_C_NT_STRING_UID_NAME) &&95(*oid != GSS_C_NT_HOSTBASED_SERVICE) &&96(*oid != GSS_C_NT_ANONYMOUS) &&97(*oid != GSS_C_NT_EXPORT_NAME) &&98(*oid != GSS_C_NT_COMPOSITE_EXPORT) &&99(*oid != gss_nt_service_name)) {100free((*oid)->elements);101free(*oid);102}103*oid = GSS_C_NO_OID;104return(GSS_S_COMPLETE);105}106107OM_uint32108generic_gss_copy_oid(OM_uint32 *minor_status,109const gss_OID_desc * const oid,110gss_OID *new_oid)111{112gss_OID p;113114*minor_status = 0;115116p = (gss_OID) malloc(sizeof(gss_OID_desc));117if (!p) {118*minor_status = ENOMEM;119return GSS_S_FAILURE;120}121p->length = oid->length;122p->elements = malloc(p->length);123if (!p->elements) {124free(p);125return GSS_S_FAILURE;126}127memcpy(p->elements, oid->elements, p->length);128*new_oid = p;129return(GSS_S_COMPLETE);130}131132133OM_uint32134generic_gss_create_empty_oid_set(OM_uint32 *minor_status, gss_OID_set *oid_set)135{136*minor_status = 0;137138if (oid_set == NULL)139return GSS_S_CALL_INACCESSIBLE_WRITE;140141if ((*oid_set = (gss_OID_set) gssalloc_malloc(sizeof(gss_OID_set_desc)))) {142memset(*oid_set, 0, sizeof(gss_OID_set_desc));143return(GSS_S_COMPLETE);144}145else {146*minor_status = ENOMEM;147return(GSS_S_FAILURE);148}149}150151OM_uint32152generic_gss_add_oid_set_member(OM_uint32 *minor_status,153const gss_OID_desc * const member_oid,154gss_OID_set *oid_set)155{156gss_OID elist;157gss_OID lastel;158159*minor_status = 0;160161if (member_oid == NULL || member_oid->length == 0 ||162member_oid->elements == NULL)163return (GSS_S_CALL_INACCESSIBLE_READ);164165if (oid_set == NULL)166return GSS_S_CALL_INACCESSIBLE_WRITE;167168elist = (*oid_set)->elements;169/* Get an enlarged copy of the array */170if (((*oid_set)->elements = (gss_OID) gssalloc_malloc(((*oid_set)->count+1) *171sizeof(gss_OID_desc)))) {172/* Copy in the old junk */173if (elist)174memcpy((*oid_set)->elements,175elist,176((*oid_set)->count * sizeof(gss_OID_desc)));177178/* Duplicate the input element */179lastel = &(*oid_set)->elements[(*oid_set)->count];180if ((lastel->elements =181(void *) gssalloc_malloc((size_t) member_oid->length))) {182/* Success - copy elements */183memcpy(lastel->elements, member_oid->elements,184(size_t) member_oid->length);185/* Set length */186lastel->length = member_oid->length;187188/* Update count */189(*oid_set)->count++;190if (elist)191gssalloc_free(elist);192*minor_status = 0;193return(GSS_S_COMPLETE);194}195else196gssalloc_free((*oid_set)->elements);197}198/* Failure - restore old contents of list */199(*oid_set)->elements = elist;200*minor_status = ENOMEM;201return(GSS_S_FAILURE);202}203204OM_uint32205generic_gss_test_oid_set_member(OM_uint32 *minor_status,206const gss_OID_desc * const member,207gss_OID_set set,208int * present)209{210OM_uint32 i;211int result;212213*minor_status = 0;214215if (member == NULL || set == NULL)216return (GSS_S_CALL_INACCESSIBLE_READ);217218if (present == NULL)219return (GSS_S_CALL_INACCESSIBLE_WRITE);220221result = 0;222for (i=0; i<set->count; i++) {223if ((set->elements[i].length == member->length) &&224!memcmp(set->elements[i].elements,225member->elements,226(size_t) member->length)) {227result = 1;228break;229}230}231*present = result;232return(GSS_S_COMPLETE);233}234235OM_uint32236generic_gss_oid_to_str(OM_uint32 *minor_status,237const gss_OID_desc * const oid,238gss_buffer_t oid_str)239{240unsigned long number, n;241OM_uint32 i;242int first;243unsigned char *cp;244struct k5buf buf;245246*minor_status = 0;247248if (oid_str != GSS_C_NO_BUFFER) {249oid_str->length = 0;250oid_str->value = NULL;251}252253if (oid == NULL || oid->length == 0 || oid->elements == NULL)254return (GSS_S_CALL_INACCESSIBLE_READ);255256if (oid_str == GSS_C_NO_BUFFER)257return (GSS_S_CALL_INACCESSIBLE_WRITE);258259/* Decoded according to krb5/gssapi_krb5.c */260261cp = (unsigned char *) oid->elements;262number = (unsigned long) cp[0];263k5_buf_init_dynamic(&buf);264k5_buf_add(&buf, "{ ");265number = 0;266cp = (unsigned char *) oid->elements;267first = 1;268for (i = 0; i < oid->length; i++) {269number = (number << 7) | (cp[i] & 0x7f);270if ((cp[i] & 0x80) == 0) {271if (first) {272n = (number < 40) ? 0 : (number < 80) ? 1 : 2;273k5_buf_add_fmt(&buf, "%lu %lu ", n, number - (n * 40));274first = 0;275} else {276k5_buf_add_fmt(&buf, "%lu ", number);277}278number = 0;279}280}281k5_buf_add_len(&buf, "}\0", 2);282return k5buf_to_gss(minor_status, &buf, oid_str);283}284285/* Return the length of a DER OID subidentifier encoding. */286static size_t287arc_encoded_length(unsigned long arc)288{289size_t len = 1;290291for (arc >>= 7; arc; arc >>= 7)292len++;293return len;294}295296/* Encode a subidentifier into *bufp and advance it to the encoding's end. */297static void298arc_encode(unsigned long arc, unsigned char **bufp)299{300unsigned char *p;301302/* Advance to the end and encode backwards. */303p = *bufp = *bufp + arc_encoded_length(arc);304*--p = arc & 0x7f;305for (arc >>= 7; arc; arc >>= 7)306*--p = (arc & 0x7f) | 0x80;307}308309/* Fetch an arc value from *bufp and advance past it and any following spaces310* or periods. Return 1 on success, 0 if *bufp is not at a valid arc value. */311static int312get_arc(const unsigned char **bufp, const unsigned char *end,313unsigned long *arc_out)314{315const unsigned char *p = *bufp;316unsigned long arc = 0, newval;317318if (p == end || !isdigit(*p))319return 0;320for (; p < end && isdigit(*p); p++) {321newval = arc * 10 + (*p - '0');322if (newval < arc)323return 0;324arc = newval;325}326while (p < end && (isspace(*p) || *p == '.'))327p++;328*bufp = p;329*arc_out = arc;330return 1;331}332333/*334* Convert a sequence of two or more decimal arc values into a DER-encoded OID.335* The values may be separated by any combination of whitespace and period336* characters, and may be optionally surrounded with braces. Leading337* whitespace and trailing garbage is allowed. The first arc value must be 0,338* 1, or 2, and the second value must be less than 40 if the first value is not339* 2.340*/341OM_uint32342generic_gss_str_to_oid(OM_uint32 *minor_status,343gss_buffer_t oid_str,344gss_OID *oid_out)345{346const unsigned char *p, *end, *arc3_start;347unsigned char *out;348unsigned long arc, arc1, arc2;349size_t nbytes;350int brace = 0;351gss_OID oid;352353*minor_status = 0;354355if (oid_out != NULL)356*oid_out = GSS_C_NO_OID;357358if (GSS_EMPTY_BUFFER(oid_str))359return (GSS_S_CALL_INACCESSIBLE_READ);360361if (oid_out == NULL)362return (GSS_S_CALL_INACCESSIBLE_WRITE);363364/* Skip past initial spaces and, optionally, an open brace. */365brace = 0;366p = oid_str->value;367end = p + oid_str->length;368while (p < end && isspace(*p))369p++;370if (p < end && *p == '{') {371brace = 1;372p++;373}374while (p < end && isspace(*p))375p++;376377/* Get the first two arc values, to be encoded as one subidentifier. */378if (!get_arc(&p, end, &arc1) || !get_arc(&p, end, &arc2))379return (GSS_S_FAILURE);380if (arc1 > 2 || (arc1 < 2 && arc2 > 39) || arc2 > ULONG_MAX - 80)381return (GSS_S_FAILURE);382arc3_start = p;383384/* Compute the total length of the encoding while checking syntax. */385nbytes = arc_encoded_length(arc1 * 40 + arc2);386while (get_arc(&p, end, &arc))387nbytes += arc_encoded_length(arc);388if (brace && (p == end || *p != '}'))389return (GSS_S_FAILURE);390391/* Allocate an oid structure. */392oid = malloc(sizeof(*oid));393if (oid == NULL)394return (GSS_S_FAILURE);395oid->elements = malloc(nbytes);396if (oid->elements == NULL) {397free(oid);398return (GSS_S_FAILURE);399}400oid->length = nbytes;401402out = oid->elements;403arc_encode(arc1 * 40 + arc2, &out);404p = arc3_start;405while (get_arc(&p, end, &arc))406arc_encode(arc, &out);407assert(out - nbytes == oid->elements);408*oid_out = oid;409return(GSS_S_COMPLETE);410}411412/* Compose an OID of a prefix and an integer suffix */413OM_uint32414generic_gss_oid_compose(OM_uint32 *minor_status,415const char *prefix,416size_t prefix_len,417int suffix,418gss_OID_desc *oid)419{420int osuffix, i;421size_t nbytes;422unsigned char *op;423424if (oid == GSS_C_NO_OID) {425*minor_status = EINVAL;426return GSS_S_FAILURE;427}428if (oid->length < prefix_len) {429*minor_status = ERANGE;430return GSS_S_FAILURE;431}432433memcpy(oid->elements, prefix, prefix_len);434435nbytes = 0;436osuffix = suffix;437while (suffix) {438nbytes++;439suffix >>= 7;440}441suffix = osuffix;442443if (oid->length < prefix_len + nbytes) {444*minor_status = ERANGE;445return GSS_S_FAILURE;446}447448op = (unsigned char *) oid->elements + prefix_len + nbytes;449i = -1;450while (suffix) {451op[i] = (unsigned char)suffix & 0x7f;452if (i != -1)453op[i] |= 0x80;454i--;455suffix >>= 7;456}457458oid->length = prefix_len + nbytes;459460*minor_status = 0;461return GSS_S_COMPLETE;462}463464OM_uint32465generic_gss_oid_decompose(OM_uint32 *minor_status,466const char *prefix,467size_t prefix_len,468gss_OID_desc *oid,469int *suffix)470{471size_t i, slen;472unsigned char *op;473474if (oid->length < prefix_len ||475memcmp(oid->elements, prefix, prefix_len) != 0) {476return GSS_S_BAD_MECH;477}478479op = (unsigned char *) oid->elements + prefix_len;480481*suffix = 0;482483slen = oid->length - prefix_len;484485for (i = 0; i < slen; i++) {486*suffix = (*suffix << 7) | (op[i] & 0x7f);487if (i + 1 != slen && (op[i] & 0x80) == 0) {488*minor_status = EINVAL;489return GSS_S_FAILURE;490}491}492493return GSS_S_COMPLETE;494}495496OM_uint32497generic_gss_copy_oid_set(OM_uint32 *minor_status,498const gss_OID_set_desc * const oidset,499gss_OID_set *new_oidset)500{501gss_OID_set_desc *copy;502OM_uint32 minor = 0;503OM_uint32 major = GSS_S_COMPLETE;504OM_uint32 i;505506if (minor_status != NULL)507*minor_status = 0;508509if (new_oidset != NULL)510*new_oidset = GSS_C_NO_OID_SET;511512if (oidset == GSS_C_NO_OID_SET)513return (GSS_S_CALL_INACCESSIBLE_READ);514515if (new_oidset == NULL)516return (GSS_S_CALL_INACCESSIBLE_WRITE);517518if ((copy = (gss_OID_set_desc *) gssalloc_calloc(1, sizeof (*copy))) == NULL) {519major = GSS_S_FAILURE;520goto done;521}522523if ((copy->elements = (gss_OID_desc *)524gssalloc_calloc(oidset->count, sizeof (*copy->elements))) == NULL) {525major = GSS_S_FAILURE;526goto done;527}528copy->count = oidset->count;529530for (i = 0; i < copy->count; i++) {531gss_OID_desc *out = ©->elements[i];532gss_OID_desc *in = &oidset->elements[i];533534if ((out->elements = (void *) gssalloc_malloc(in->length)) == NULL) {535major = GSS_S_FAILURE;536goto done;537}538(void) memcpy(out->elements, in->elements, in->length);539out->length = in->length;540}541542*new_oidset = copy;543done:544if (major != GSS_S_COMPLETE) {545(void) generic_gss_release_oid_set(&minor, ©);546}547548return (major);549}550551552