linux/lib/oid_registry.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* ASN.1 Object identifier (OID) registry
   3 *
   4 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
   5 * Written by David Howells (dhowells@redhat.com)
   6 */
   7
   8#include <linux/module.h>
   9#include <linux/export.h>
  10#include <linux/oid_registry.h>
  11#include <linux/kernel.h>
  12#include <linux/errno.h>
  13#include <linux/bug.h>
  14#include "oid_registry_data.c"
  15
  16MODULE_DESCRIPTION("OID Registry");
  17MODULE_AUTHOR("Red Hat, Inc.");
  18MODULE_LICENSE("GPL");
  19
  20/**
  21 * look_up_OID - Find an OID registration for the specified data
  22 * @data: Binary representation of the OID
  23 * @datasize: Size of the binary representation
  24 */
  25enum OID look_up_OID(const void *data, size_t datasize)
  26{
  27        const unsigned char *octets = data;
  28        enum OID oid;
  29        unsigned char xhash;
  30        unsigned i, j, k, hash;
  31        size_t len;
  32
  33        /* Hash the OID data */
  34        hash = datasize - 1;
  35
  36        for (i = 0; i < datasize; i++)
  37                hash += octets[i] * 33;
  38        hash = (hash >> 24) ^ (hash >> 16) ^ (hash >> 8) ^ hash;
  39        hash &= 0xff;
  40
  41        /* Binary search the OID registry.  OIDs are stored in ascending order
  42         * of hash value then ascending order of size and then in ascending
  43         * order of reverse value.
  44         */
  45        i = 0;
  46        k = OID__NR;
  47        while (i < k) {
  48                j = (i + k) / 2;
  49
  50                xhash = oid_search_table[j].hash;
  51                if (xhash > hash) {
  52                        k = j;
  53                        continue;
  54                }
  55                if (xhash < hash) {
  56                        i = j + 1;
  57                        continue;
  58                }
  59
  60                oid = oid_search_table[j].oid;
  61                len = oid_index[oid + 1] - oid_index[oid];
  62                if (len > datasize) {
  63                        k = j;
  64                        continue;
  65                }
  66                if (len < datasize) {
  67                        i = j + 1;
  68                        continue;
  69                }
  70
  71                /* Variation is most likely to be at the tail end of the
  72                 * OID, so do the comparison in reverse.
  73                 */
  74                while (len > 0) {
  75                        unsigned char a = oid_data[oid_index[oid] + --len];
  76                        unsigned char b = octets[len];
  77                        if (a > b) {
  78                                k = j;
  79                                goto next;
  80                        }
  81                        if (a < b) {
  82                                i = j + 1;
  83                                goto next;
  84                        }
  85                }
  86                return oid;
  87        next:
  88                ;
  89        }
  90
  91        return OID__NR;
  92}
  93EXPORT_SYMBOL_GPL(look_up_OID);
  94
  95/*
  96 * sprint_OID - Print an Object Identifier into a buffer
  97 * @data: The encoded OID to print
  98 * @datasize: The size of the encoded OID
  99 * @buffer: The buffer to render into
 100 * @bufsize: The size of the buffer
 101 *
 102 * The OID is rendered into the buffer in "a.b.c.d" format and the number of
 103 * bytes is returned.  -EBADMSG is returned if the data could not be intepreted
 104 * and -ENOBUFS if the buffer was too small.
 105 */
 106int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize)
 107{
 108        const unsigned char *v = data, *end = v + datasize;
 109        unsigned long num;
 110        unsigned char n;
 111        size_t ret;
 112        int count;
 113
 114        if (v >= end)
 115                goto bad;
 116
 117        n = *v++;
 118        ret = count = snprintf(buffer, bufsize, "%u.%u", n / 40, n % 40);
 119        if (count >= bufsize)
 120                return -ENOBUFS;
 121        buffer += count;
 122        bufsize -= count;
 123
 124        while (v < end) {
 125                num = 0;
 126                n = *v++;
 127                if (!(n & 0x80)) {
 128                        num = n;
 129                } else {
 130                        num = n & 0x7f;
 131                        do {
 132                                if (v >= end)
 133                                        goto bad;
 134                                n = *v++;
 135                                num <<= 7;
 136                                num |= n & 0x7f;
 137                        } while (n & 0x80);
 138                }
 139                ret += count = snprintf(buffer, bufsize, ".%lu", num);
 140                if (count >= bufsize)
 141                        return -ENOBUFS;
 142                buffer += count;
 143                bufsize -= count;
 144        }
 145
 146        return ret;
 147
 148bad:
 149        snprintf(buffer, bufsize, "(bad)");
 150        return -EBADMSG;
 151}
 152EXPORT_SYMBOL_GPL(sprint_oid);
 153
 154/**
 155 * sprint_OID - Print an Object Identifier into a buffer
 156 * @oid: The OID to print
 157 * @buffer: The buffer to render into
 158 * @bufsize: The size of the buffer
 159 *
 160 * The OID is rendered into the buffer in "a.b.c.d" format and the number of
 161 * bytes is returned.
 162 */
 163int sprint_OID(enum OID oid, char *buffer, size_t bufsize)
 164{
 165        int ret;
 166
 167        BUG_ON(oid >= OID__NR);
 168
 169        ret = sprint_oid(oid_data + oid_index[oid],
 170                         oid_index[oid + 1] - oid_index[oid],
 171                         buffer, bufsize);
 172        BUG_ON(ret == -EBADMSG);
 173        return ret;
 174}
 175EXPORT_SYMBOL_GPL(sprint_OID);
 176