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 <linux/asn1.h>
  15#include "oid_registry_data.c"
  16
  17MODULE_DESCRIPTION("OID Registry");
  18MODULE_AUTHOR("Red Hat, Inc.");
  19MODULE_LICENSE("GPL");
  20
  21/**
  22 * look_up_OID - Find an OID registration for the specified data
  23 * @data: Binary representation of the OID
  24 * @datasize: Size of the binary representation
  25 */
  26enum OID look_up_OID(const void *data, size_t datasize)
  27{
  28        const unsigned char *octets = data;
  29        enum OID oid;
  30        unsigned char xhash;
  31        unsigned i, j, k, hash;
  32        size_t len;
  33
  34        /* Hash the OID data */
  35        hash = datasize - 1;
  36
  37        for (i = 0; i < datasize; i++)
  38                hash += octets[i] * 33;
  39        hash = (hash >> 24) ^ (hash >> 16) ^ (hash >> 8) ^ hash;
  40        hash &= 0xff;
  41
  42        /* Binary search the OID registry.  OIDs are stored in ascending order
  43         * of hash value then ascending order of size and then in ascending
  44         * order of reverse value.
  45         */
  46        i = 0;
  47        k = OID__NR;
  48        while (i < k) {
  49                j = (i + k) / 2;
  50
  51                xhash = oid_search_table[j].hash;
  52                if (xhash > hash) {
  53                        k = j;
  54                        continue;
  55                }
  56                if (xhash < hash) {
  57                        i = j + 1;
  58                        continue;
  59                }
  60
  61                oid = oid_search_table[j].oid;
  62                len = oid_index[oid + 1] - oid_index[oid];
  63                if (len > datasize) {
  64                        k = j;
  65                        continue;
  66                }
  67                if (len < datasize) {
  68                        i = j + 1;
  69                        continue;
  70                }
  71
  72                /* Variation is most likely to be at the tail end of the
  73                 * OID, so do the comparison in reverse.
  74                 */
  75                while (len > 0) {
  76                        unsigned char a = oid_data[oid_index[oid] + --len];
  77                        unsigned char b = octets[len];
  78                        if (a > b) {
  79                                k = j;
  80                                goto next;
  81                        }
  82                        if (a < b) {
  83                                i = j + 1;
  84                                goto next;
  85                        }
  86                }
  87                return oid;
  88        next:
  89                ;
  90        }
  91
  92        return OID__NR;
  93}
  94EXPORT_SYMBOL_GPL(look_up_OID);
  95
  96/**
  97 * parse_OID - Parse an OID from a bytestream
  98 * @data: Binary representation of the header + OID
  99 * @datasize: Size of the binary representation
 100 * @oid: Pointer to oid to return result
 101 *
 102 * Parse an OID from a bytestream that holds the OID in the format
 103 * ASN1_OID | length | oid. The length indicator must equal to datasize - 2.
 104 * -EBADMSG is returned if the bytestream is too short.
 105 */
 106int parse_OID(const void *data, size_t datasize, enum OID *oid)
 107{
 108        const unsigned char *v = data;
 109
 110        /* we need 2 bytes of header and at least 1 byte for oid */
 111        if (datasize < 3 || v[0] != ASN1_OID || v[1] != datasize - 2)
 112                return -EBADMSG;
 113
 114        *oid = look_up_OID(data + 2, datasize - 2);
 115        return 0;
 116}
 117EXPORT_SYMBOL_GPL(parse_OID);
 118
 119/*
 120 * sprint_OID - Print an Object Identifier into a buffer
 121 * @data: The encoded OID to print
 122 * @datasize: The size of the encoded OID
 123 * @buffer: The buffer to render into
 124 * @bufsize: The size of the buffer
 125 *
 126 * The OID is rendered into the buffer in "a.b.c.d" format and the number of
 127 * bytes is returned.  -EBADMSG is returned if the data could not be interpreted
 128 * and -ENOBUFS if the buffer was too small.
 129 */
 130int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize)
 131{
 132        const unsigned char *v = data, *end = v + datasize;
 133        unsigned long num;
 134        unsigned char n;
 135        size_t ret;
 136        int count;
 137
 138        if (v >= end)
 139                goto bad;
 140
 141        n = *v++;
 142        ret = count = snprintf(buffer, bufsize, "%u.%u", n / 40, n % 40);
 143        if (count >= bufsize)
 144                return -ENOBUFS;
 145        buffer += count;
 146        bufsize -= count;
 147
 148        while (v < end) {
 149                num = 0;
 150                n = *v++;
 151                if (!(n & 0x80)) {
 152                        num = n;
 153                } else {
 154                        num = n & 0x7f;
 155                        do {
 156                                if (v >= end)
 157                                        goto bad;
 158                                n = *v++;
 159                                num <<= 7;
 160                                num |= n & 0x7f;
 161                        } while (n & 0x80);
 162                }
 163                ret += count = snprintf(buffer, bufsize, ".%lu", num);
 164                if (count >= bufsize)
 165                        return -ENOBUFS;
 166                buffer += count;
 167                bufsize -= count;
 168        }
 169
 170        return ret;
 171
 172bad:
 173        snprintf(buffer, bufsize, "(bad)");
 174        return -EBADMSG;
 175}
 176EXPORT_SYMBOL_GPL(sprint_oid);
 177
 178/**
 179 * sprint_OID - Print an Object Identifier into a buffer
 180 * @oid: The OID to print
 181 * @buffer: The buffer to render into
 182 * @bufsize: The size of the buffer
 183 *
 184 * The OID is rendered into the buffer in "a.b.c.d" format and the number of
 185 * bytes is returned.
 186 */
 187int sprint_OID(enum OID oid, char *buffer, size_t bufsize)
 188{
 189        int ret;
 190
 191        BUG_ON(oid >= OID__NR);
 192
 193        ret = sprint_oid(oid_data + oid_index[oid],
 194                         oid_index[oid + 1] - oid_index[oid],
 195                         buffer, bufsize);
 196        BUG_ON(ret == -EBADMSG);
 197        return ret;
 198}
 199EXPORT_SYMBOL_GPL(sprint_OID);
 200