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