Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
oid_registry.c
Go to the documentation of this file.
1 /* ASN.1 Object identifier (OID) registry
2  *
3  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells ([email protected])
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/export.h>
13 #include <linux/oid_registry.h>
14 #include <linux/kernel.h>
15 #include <linux/errno.h>
16 #include <linux/bug.h>
17 #include "oid_registry_data.c"
18 
24 enum OID look_up_OID(const void *data, size_t datasize)
25 {
26  const unsigned char *octets = data;
27  enum OID oid;
28  unsigned char xhash;
29  unsigned i, j, k, hash;
30  size_t len;
31 
32  /* Hash the OID data */
33  hash = datasize - 1;
34 
35  for (i = 0; i < datasize; i++)
36  hash += octets[i] * 33;
37  hash = (hash >> 24) ^ (hash >> 16) ^ (hash >> 8) ^ hash;
38  hash &= 0xff;
39 
40  /* Binary search the OID registry. OIDs are stored in ascending order
41  * of hash value then ascending order of size and then in ascending
42  * order of reverse value.
43  */
44  i = 0;
45  k = OID__NR;
46  while (i < k) {
47  j = (i + k) / 2;
48 
49  xhash = oid_search_table[j].hash;
50  if (xhash > hash) {
51  k = j;
52  continue;
53  }
54  if (xhash < hash) {
55  i = j + 1;
56  continue;
57  }
58 
59  oid = oid_search_table[j].oid;
60  len = oid_index[oid + 1] - oid_index[oid];
61  if (len > datasize) {
62  k = j;
63  continue;
64  }
65  if (len < datasize) {
66  i = j + 1;
67  continue;
68  }
69 
70  /* Variation is most likely to be at the tail end of the
71  * OID, so do the comparison in reverse.
72  */
73  while (len > 0) {
74  unsigned char a = oid_data[oid_index[oid] + --len];
75  unsigned char b = octets[len];
76  if (a > b) {
77  k = j;
78  goto next;
79  }
80  if (a < b) {
81  i = j + 1;
82  goto next;
83  }
84  }
85  return oid;
86  next:
87  ;
88  }
89 
90  return OID__NR;
91 }
93 
94 /*
95  * sprint_OID - Print an Object Identifier into a buffer
96  * @data: The encoded OID to print
97  * @datasize: The size of the encoded OID
98  * @buffer: The buffer to render into
99  * @bufsize: The size of the buffer
100  *
101  * The OID is rendered into the buffer in "a.b.c.d" format and the number of
102  * bytes is returned. -EBADMSG is returned if the data could not be intepreted
103  * and -ENOBUFS if the buffer was too small.
104  */
105 int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize)
106 {
107  const unsigned char *v = data, *end = v + datasize;
108  unsigned long num;
109  unsigned char n;
110  size_t ret;
111  int count;
112 
113  if (v >= end)
114  return -EBADMSG;
115 
116  n = *v++;
117  ret = count = snprintf(buffer, bufsize, "%u.%u", n / 40, n % 40);
118  buffer += count;
119  bufsize -= count;
120  if (bufsize == 0)
121  return -ENOBUFS;
122 
123  while (v < end) {
124  num = 0;
125  n = *v++;
126  if (!(n & 0x80)) {
127  num = n;
128  } else {
129  num = n & 0x7f;
130  do {
131  if (v >= end)
132  return -EBADMSG;
133  n = *v++;
134  num <<= 7;
135  num |= n & 0x7f;
136  } while (n & 0x80);
137  }
138  ret += count = snprintf(buffer, bufsize, ".%lu", num);
139  buffer += count;
140  bufsize -= count;
141  if (bufsize == 0)
142  return -ENOBUFS;
143  }
144 
145  return ret;
146 }
148 
158 int sprint_OID(enum OID oid, char *buffer, size_t bufsize)
159 {
160  int ret;
161 
162  BUG_ON(oid >= OID__NR);
163 
164  ret = sprint_oid(oid_data + oid_index[oid],
165  oid_index[oid + 1] - oid_index[oid],
166  buffer, bufsize);
167  BUG_ON(ret == -EBADMSG);
168  return ret;
169 }