cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

oid_registry.c (4536B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* ASN.1 Object identifier (OID) registry
      3 *
      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 data
     23 * @data: Binary representation of the OID
     24 * @datasize: Size of the binary representation
     25 */
     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 order
     43	 * of hash value then ascending order of size and then in ascending
     44	 * 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 the
     73		 * 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 bytestream
     98 * @data: Binary representation of the header + OID
     99 * @datasize: Size of the binary representation
    100 * @oid: Pointer to oid to return result
    101 *
    102 * Parse an OID from a bytestream that holds the OID in the format
    103 * 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 buffer
    121 * @data: The encoded OID to print
    122 * @datasize: The size of the encoded OID
    123 * @buffer: The buffer to render into
    124 * @bufsize: The size of the buffer
    125 *
    126 * The OID is rendered into the buffer in "a.b.c.d" format and the number of
    127 * bytes is returned.  -EBADMSG is returned if the data could not be interpreted
    128 * 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		num = 0;
    150		n = *v++;
    151		if (!(n & 0x80)) {
    152			num = n;
    153		} else {
    154			num = n & 0x7f;
    155			do {
    156				if (v >= end)
    157					goto bad;
    158				n = *v++;
    159				num <<= 7;
    160				num |= n & 0x7f;
    161			} while (n & 0x80);
    162		}
    163		ret += count = snprintf(buffer, bufsize, ".%lu", num);
    164		if (count >= bufsize)
    165			return -ENOBUFS;
    166		buffer += count;
    167		bufsize -= count;
    168	}
    169
    170	return ret;
    171
    172bad:
    173	snprintf(buffer, bufsize, "(bad)");
    174	return -EBADMSG;
    175}
    176EXPORT_SYMBOL_GPL(sprint_oid);
    177
    178/**
    179 * sprint_OID - Print an Object Identifier into a buffer
    180 * @oid: The OID to print
    181 * @buffer: The buffer to render into
    182 * @bufsize: The size of the buffer
    183 *
    184 * The OID is rendered into the buffer in "a.b.c.d" format and the number of
    185 * bytes is returned.
    186 */
    187int sprint_OID(enum OID oid, char *buffer, size_t bufsize)
    188{
    189	int ret;
    190
    191	BUG_ON(oid >= OID__NR);
    192
    193	ret = sprint_oid(oid_data + oid_index[oid],
    194			 oid_index[oid + 1] - oid_index[oid],
    195			 buffer, bufsize);
    196	BUG_ON(ret == -EBADMSG);
    197	return ret;
    198}
    199EXPORT_SYMBOL_GPL(sprint_OID);