xref: /OK3568_Linux_fs/kernel/lib/oid_registry.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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