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