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