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