brintos

brintos / linux-shallow public Read only

0
0
Text · 4.4 KiB · fe6705c Raw
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