199 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* ASN.1 Object identifier (OID) registry3 *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 data23 * @data: Binary representation of the OID24 * @datasize: Size of the binary representation25 */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 order43 * of hash value then ascending order of size and then in ascending44 * 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 the73 * 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 bytestream98 * @data: Binary representation of the header + OID99 * @datasize: Size of the binary representation100 * @oid: Pointer to oid to return result101 *102 * Parse an OID from a bytestream that holds the OID in the format103 * 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 buffer121 * @data: The encoded OID to print122 * @datasize: The size of the encoded OID123 * @buffer: The buffer to render into124 * @bufsize: The size of the buffer125 *126 * The OID is rendered into the buffer in "a.b.c.d" format and the number of127 * bytes is returned. -EBADMSG is returned if the data could not be interpreted128 * 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 n = *v++;150 if (!(n & 0x80)) {151 num = n;152 } else {153 num = n & 0x7f;154 do {155 if (v >= end)156 goto bad;157 n = *v++;158 num <<= 7;159 num |= n & 0x7f;160 } while (n & 0x80);161 }162 ret += count = snprintf(buffer, bufsize, ".%lu", num);163 if (count >= bufsize)164 return -ENOBUFS;165 buffer += count;166 bufsize -= count;167 }168 169 return ret;170 171bad:172 snprintf(buffer, bufsize, "(bad)");173 return -EBADMSG;174}175EXPORT_SYMBOL_GPL(sprint_oid);176 177/**178 * sprint_OID - Print an Object Identifier into a buffer179 * @oid: The OID to print180 * @buffer: The buffer to render into181 * @bufsize: The size of the buffer182 *183 * The OID is rendered into the buffer in "a.b.c.d" format and the number of184 * bytes is returned.185 */186int sprint_OID(enum OID oid, char *buffer, size_t bufsize)187{188 int ret;189 190 BUG_ON(oid >= OID__NR);191 192 ret = sprint_oid(oid_data + oid_index[oid],193 oid_index[oid + 1] - oid_index[oid],194 buffer, bufsize);195 BUG_ON(ret == -EBADMSG);196 return ret;197}198EXPORT_SYMBOL_GPL(sprint_OID);199